openlp-core team mailing list archive
-
openlp-core team
-
Mailing list archive
-
Message #22684
[Merge] lp:~raoul-snyman/openlp/songselect2 into lp:openlp
Raoul Snyman has proposed merging lp:~raoul-snyman/openlp/songselect2 into lp:openlp.
Requested reviews:
Tim Bentley (trb143)
For more details, see:
https://code.launchpad.net/~raoul-snyman/openlp/songselect2/+merge/210478
First stab at CCLI SongSelect integration
--
https://code.launchpad.net/~raoul-snyman/openlp/songselect2/+merge/210478
Your team OpenLP Core is subscribed to branch lp:openlp.
=== modified file 'openlp/core/common/__init__.py'
--- openlp/core/common/__init__.py 2014-01-11 21:29:01 +0000
+++ openlp/core/common/__init__.py 2014-03-11 19:13:15 +0000
@@ -134,4 +134,4 @@
from .uistrings import UiStrings
from .settings import Settings
from .applocation import AppLocation
-
+from .historycombobox import HistoryComboBox
=== added file 'openlp/core/common/historycombobox.py'
--- openlp/core/common/historycombobox.py 1970-01-01 00:00:00 +0000
+++ openlp/core/common/historycombobox.py 2014-03-11 19:13:15 +0000
@@ -0,0 +1,91 @@
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
+
+###############################################################################
+# OpenLP - Open Source Lyrics Projection #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2014 Raoul Snyman #
+# Portions copyright (c) 2008-2014 Tim Bentley, Gerald Britton, Jonathan #
+# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
+# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
+# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
+# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
+# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, #
+# Frode Woldsund, Martin Zibricky, Patrick Zimmermann #
+# --------------------------------------------------------------------------- #
+# This program is free software; you can redistribute it and/or modify it #
+# under the terms of the GNU General Public License as published by the Free #
+# Software Foundation; version 2 of the License. #
+# #
+# This program is distributed in the hope that it will be useful, but WITHOUT #
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
+# more details. #
+# #
+# You should have received a copy of the GNU General Public License along #
+# with this program; if not, write to the Free Software Foundation, Inc., 59 #
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
+###############################################################################
+"""
+The :mod:`~openlp.core.lib.historycombobox` module contains the HistoryComboBox widget
+"""
+
+from PyQt4 import QtCore, QtGui
+
+
+class HistoryComboBox(QtGui.QComboBox):
+ """
+ The :class:`~openlp.core.lib.historycombobox.HistoryComboBox` widget emulates the QLineEdit ``returnPressed`` signal
+ for when the :kbd:`Enter` or :kbd:`Return` keys are pressed, and saves anything that is typed into the edit box into
+ its list.
+ """
+ returnPressed = QtCore.pyqtSignal()
+
+ def __init__(self, parent=None):
+ """
+ Initialise the combo box, setting duplicates to False and the insert policy to insert items at the top.
+
+ :param parent: The parent widget
+ """
+ super().__init__(parent)
+ self.setDuplicatesEnabled(False)
+ self.setEditable(True)
+ self.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Preferred)
+ self.setInsertPolicy(QtGui.QComboBox.InsertAtTop)
+
+ def keyPressEvent(self, event):
+ """
+ Override the inherited keyPressEvent method to emit the ``returnPressed`` signal and to save the current text to
+ the dropdown list.
+
+ :param event: The keyboard event
+ """
+ # Handle Enter and Return ourselves
+ if event.key() == QtCore.Qt.Key_Enter or event.key() == QtCore.Qt.Key_Return:
+ # Emit the returnPressed signal
+ self.returnPressed.emit()
+ # Save the current text to the dropdown list
+ if self.currentText() and self.findText(self.currentText()) == -1:
+ self.insertItem(0, self.currentText())
+ # Let the parent handle any keypress events
+ super().keyPressEvent(event)
+
+ def focusOutEvent(self, event):
+ """
+ Override the inherited focusOutEvent to save the current text to the dropdown list.
+
+ :param event: The focus event
+ """
+ # Save the current text to the dropdown list
+ if self.currentText() and self.findText(self.currentText()) == -1:
+ self.insertItem(0, self.currentText())
+ # Let the parent handle any keypress events
+ super().focusOutEvent(event)
+
+ def getItems(self):
+ """
+ Get all the items from the history
+
+ :return: A list of strings
+ """
+ return [self.itemText(i) for i in range(self.count())]
=== modified file 'openlp/core/resources.py'
--- openlp/core/resources.py 2013-08-31 18:17:38 +0000
+++ openlp/core/resources.py 2014-03-11 19:13:15 +0000
@@ -4,8 +4,8 @@
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
-# Copyright (c) 2008-2013 Raoul Snyman #
-# Portions copyright (c) 2008-2013 Tim Bentley, Gerald Britton, Jonathan #
+# Copyright (c) 2008-2014 Raoul Snyman #
+# Portions copyright (c) 2008-2014 Tim Bentley, Gerald Britton, Jonathan #
# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
@@ -79896,290 +79896,6 @@
\x09\x13\x26\x4c\x98\x30\x61\xc2\x06\xcb\xfe\x1f\xb5\x2a\x3a\xdb\
\x50\xaf\x4d\x17\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\
\
-\x00\x00\x02\x9a\
-\x89\
-\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
-\x00\x00\x10\x00\x00\x00\x10\x08\x06\x00\x00\x00\x1f\xf3\xff\x61\
-\x00\x00\x00\x04\x73\x42\x49\x54\x08\x08\x08\x08\x7c\x08\x64\x88\
-\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x01\xbb\x00\x00\x01\xbb\
-\x01\x3a\xec\xe3\xe2\x00\x00\x00\x19\x74\x45\x58\x74\x53\x6f\x66\
-\x74\x77\x61\x72\x65\x00\x77\x77\x77\x2e\x69\x6e\x6b\x73\x63\x61\
-\x70\x65\x2e\x6f\x72\x67\x9b\xee\x3c\x1a\x00\x00\x02\x17\x49\x44\
-\x41\x54\x38\x8d\xa5\x93\x3d\x68\x13\x71\x18\xc6\x9f\x37\xcd\x11\
-\x9b\x8f\x5e\x92\x4b\x52\xf3\x71\xf9\x20\xc1\xd2\x52\x3b\x1c\x15\
-\xc1\x82\xb5\x08\x35\x89\x10\x35\x38\x0b\x4e\x82\x60\x47\x89\x5b\
-\xea\xd4\x41\x08\x14\x1d\x1c\xd2\xbd\x08\xa5\x5c\x16\x17\x1d\x0c\
-\x38\x88\x20\x68\x87\x22\xd8\x56\x93\xab\x62\xed\xa9\x6d\x4c\xc9\
-\xe5\x7a\x7f\xa7\x0b\x67\xda\x45\xfa\x8c\xff\xf7\x7d\x7e\x3c\x2f\
-\x0f\x7f\x62\x8c\xe1\x24\xb2\x9d\xc8\xdd\x0f\x58\x21\x92\xde\xdc\
-\xbe\xf5\x7d\x95\xe3\x72\xfd\x8b\xab\x1c\x97\xfb\xf0\xe0\x7e\x73\
-\x85\x48\x3a\x16\xb0\x4c\x24\xf9\x27\xc7\x5e\x9d\x19\x1d\x0b\x46\
-\x8b\x59\xf9\x19\x51\xd6\x32\xcb\x85\xb3\xd3\x72\x3c\x18\x8c\x9e\
-\xbe\x32\x5d\x5f\xb6\x40\x7a\x00\x0d\x58\x4a\x4e\x9e\x77\x1d\x34\
-\xb7\x11\x4b\x8e\xda\xc3\xf9\x4b\xb5\x2a\x51\xbe\x42\x74\xcd\x79\
-\xf9\x42\x4d\x1c\x99\xb0\xb7\xb7\x1a\xc8\xcc\xe6\x9d\x1a\xb0\x64\
-\xfa\xec\x16\x40\x69\xad\xfe\xb2\x96\x1c\x3f\x67\x07\xb3\x21\x10\
-\x4e\xd9\x37\x2e\xb6\xe4\x5d\xc3\xa0\xd9\x44\xc6\xa6\x36\x14\x0c\
-\x38\x1d\xf8\xf6\xe2\xbd\xae\x01\x25\xd3\x47\xd6\x16\x9e\x12\x65\
-\x87\x47\xa2\x72\x4c\xcc\x70\x86\xc6\x60\xf3\xba\x71\xc0\x0c\x38\
-\x3b\x06\x1c\x89\x08\xb6\xde\xbe\xee\x2a\xef\x3e\x16\xee\x30\xf6\
-\xfc\x58\x00\x00\x2c\x12\x65\x23\x99\x61\x39\x12\x8c\x72\x87\x1a\
-\x81\x1c\x0e\xe8\xac\x83\xaf\xca\xa7\xee\xce\x97\x5f\x85\x39\x8b\
-\xf9\x9f\x13\x4c\x75\x00\x68\x5a\x17\xfa\xfa\x3a\xf4\x9f\x6d\x10\
-\x80\x01\x9f\x13\xcc\x73\x0a\x9d\xfe\xe5\xfe\x04\x0b\x44\x59\x31\
-\x21\xc8\xe3\xfb\x1d\x0e\x6a\x0b\x6d\xbf\x1b\x04\x60\x50\x6d\x01\
-\x7e\x37\xd6\x3c\x83\xdd\xc6\xe7\x9d\x42\xc9\x92\xa2\xd7\xc2\x3c\
-\x51\x4e\x4c\x45\xe4\xa9\x96\xce\x09\x6a\x0b\x2e\xc1\x8b\x27\x3c\
-\xcf\x16\x79\x2f\x73\x05\x7c\x10\xd4\x16\xa6\xfe\x1c\x72\x62\x3a\
-\x2e\x2f\xf0\xfc\xd5\x23\x00\x16\x0f\x3d\x9e\x19\xf2\x72\xa1\xdd\
-\xdf\x70\x07\xfc\xa8\x78\x79\x43\xd8\x54\x8a\xbe\xcd\xe6\xcd\x0a\
-\xcf\x1b\xee\xa0\x80\xd0\x0f\x15\x33\x9e\x21\x8e\x17\xc5\x47\xbd\
-\xd8\x8c\x31\x30\xc6\x50\x06\xa4\x6a\x22\xb6\xa7\x48\x67\x59\x39\
-\x9d\xd2\xe7\x80\xeb\xe6\xec\x2e\x50\x9c\x4f\xa7\x74\x45\x9a\x60\
-\xd5\x44\x6c\xaf\x0c\x48\xe6\xac\x07\x30\x21\x0f\x33\xd1\x8d\x7b\
-\xc0\x0d\xeb\xbb\x09\xa9\xe7\x73\xdb\x56\x33\x63\xec\x68\x8d\xff\
-\xab\x13\xff\xc6\xbf\x7b\x12\xeb\x18\x4c\xd6\x48\xe1\x00\x00\x00\
-\x00\x49\x45\x4e\x44\xae\x42\x60\x82\
-\x00\x00\x04\x95\
-\x89\
-\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
-\x00\x00\x16\x00\x00\x00\x16\x08\x06\x00\x00\x00\xc4\xb4\x6c\x3b\
-\x00\x00\x00\x06\x62\x4b\x47\x44\x00\xff\x00\xff\x00\xff\xa0\xbd\
-\xa7\x93\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x09\x84\x00\x00\
-\x09\x84\x01\xaa\xe2\x63\x79\x00\x00\x00\x07\x74\x49\x4d\x45\x07\
-\xd7\x0c\x0a\x00\x0b\x07\x14\x32\xc7\x3a\x00\x00\x04\x22\x49\x44\
-\x41\x54\x78\xda\xb5\x93\x5f\x4c\x5b\x55\x1c\xc7\xcf\xb9\xff\x7a\
-\x7b\x6f\x4b\x4b\x4b\xd9\xa4\x30\x86\xd0\x0d\xa1\xb4\xfc\x19\xb4\
-\x19\x38\x91\x0d\x35\x8e\x05\xf6\xe2\x32\x9d\x33\x99\x02\x0f\xf2\
-\x20\xc9\x12\xdf\x7c\xc2\x25\x1a\x63\x64\xf1\x4d\xcd\xb6\x84\xec\
-\xc9\xa1\x04\xb6\x6c\xa3\x26\xcb\x26\x3a\x60\x3e\x08\x48\xa4\xfc\
-\xa7\x54\x0a\x85\x02\x97\xfb\xa7\xf7\xf6\x9e\x7b\xbd\x24\x3e\x18\
-\x97\x75\xd3\xe0\x27\xf9\xe6\xe4\xbc\x7c\xf2\x3b\x39\xdf\x1f\xf8\
-\xbf\x80\xe0\x1f\x74\x77\x77\xdb\xbd\x5e\xdf\x29\x96\x65\x8e\x12\
-\x24\xe9\x52\x55\x75\x53\x92\xa4\xd1\xe9\xf0\x74\x5f\x5b\xdb\x7b\
-\xab\xff\x5a\xcc\xb2\x2c\xbc\x7a\xed\x5a\x9b\xc3\xe1\xec\xba\x3f\
-\xba\xe0\x18\x0b\xc7\x41\x82\x97\x75\x0b\x4d\xc0\x82\x1c\x2b\xac\
-\xaf\x3e\x20\x50\x24\xf6\xe9\xdb\xe7\xde\xba\xb4\xbd\xbd\x8d\x9e\
-\x55\x0c\xaf\x5c\xb9\xfa\x99\x0a\x2d\x1f\x7c\xf5\x7d\x58\xc7\xac\
-\x59\xe8\x78\xa3\x0f\xf0\x00\x43\x0e\x33\x01\x86\x7e\xfc\x5d\x4f\
-\x44\xfe\x20\x5f\xa9\xb4\xe0\xde\x42\xdb\xb7\xef\x9c\x3f\xff\x66\
-\x2a\x95\x4a\x2b\xc7\x81\x41\x57\xd7\xc7\x67\x31\xca\xf6\xc9\x97\
-\xdf\x2d\xa1\x82\x0a\xef\x56\x5d\x53\x40\x28\x2d\xcb\xd3\xd5\x4c\
-\x3b\x77\x38\x3f\x0b\x65\x1e\xcc\xe1\x08\xda\xcc\xdf\x1b\x8e\xe1\
-\x36\x4a\x29\x6f\x69\x6a\x50\xee\xdc\xbe\xfd\xe0\x69\x62\x53\x73\
-\x73\xcb\x8d\xbe\x87\xbc\x85\xc9\x2f\x8c\x56\x9d\xa8\x88\x65\xe7\
-\xd8\x64\x8b\x95\x16\xe6\x10\x8c\x3a\x19\x32\x85\x48\x62\x9b\xb5\
-\x67\xac\x13\x34\x2d\x3e\x18\x5a\x64\x6a\x3c\xe6\xa3\xeb\xeb\xf1\
-\xaf\xa3\xd1\xa8\xf4\x24\x31\x76\xe1\xc2\xbb\x35\x8a\x46\x1e\x98\
-\x8e\x6b\x9b\x19\x65\x9e\x5f\xd7\x20\x31\xbd\x8e\xe1\xe1\x09\x05\
-\x4e\xcb\x34\xb5\x3e\x96\xc2\xe6\x36\x71\x22\x3a\x87\xb0\xb0\xfc\
-\xdc\xbe\x09\x39\x23\x73\x76\x7e\x4d\xb3\x1e\x7b\xe9\xd8\x49\x90\
-\x06\x82\xa2\x48\xef\x96\x00\x71\x7a\x7f\x76\x54\x34\xd1\xab\xa1\
-\x6f\x6e\xb5\xc1\x8c\x03\x10\x92\x0c\x40\x7c\x0c\xa0\xad\x45\x80\
-\xa4\x4d\xa0\x25\xb7\x40\xf9\xc5\x0f\xbf\xb0\x1c\x74\x47\x36\xc4\
-\xb9\x62\x37\x45\x79\xd3\x89\x31\x00\x20\x0b\x20\xae\x53\x56\xcb\
-\x0e\xc6\x90\x32\xb7\x83\x80\x88\x18\x88\x68\x27\x84\x34\x0b\x35\
-\x82\x82\x72\x0a\x41\x9e\x13\x00\xc9\x9a\x92\x94\xdd\xc2\x63\x04\
-\xa9\x1a\xd0\x69\x27\x36\xaa\xb3\xe0\x29\x25\x34\xb4\xa8\x50\x1a\
-\x04\xe8\xe4\xa5\x73\x1f\x39\xcd\x84\x68\x25\x31\xd9\x84\x79\x90\
-\xaa\x9f\x80\xa2\xaa\x53\x9b\x32\xa2\x97\x37\x04\x46\x53\x11\xb6\
-\xcf\x4e\x9a\x76\x22\x42\x24\xed\xc4\xbd\xbd\xbd\x43\x14\x10\x84\
-\xe7\x2d\xd8\x7e\x24\xa5\x28\x01\x69\xa9\x14\x04\x12\x4e\x40\xde\
-\x64\x82\x1c\x45\xc1\x1d\x0d\x07\x62\x12\x00\x45\x53\x54\xc2\xc4\
-\x71\xb9\x85\xd9\x38\x36\x3c\x32\x32\x98\x56\x2c\xcb\xc9\xd5\x99\
-\xd9\x99\x9e\x26\x9f\xc9\x2d\x85\x97\xf3\xa5\x6d\x89\x4d\x22\x9d\
-\xd8\x6d\x38\x4b\x42\x05\x87\x50\x53\x34\x1d\x13\x65\x95\x92\x97\
-\x13\xae\x53\x45\x94\x6f\x69\x7e\xea\xee\xe8\xc8\xc8\x6f\x4f\xab\
-\x9b\x3e\x31\x3e\xfe\xa8\x2e\x58\xf1\x6a\xdd\x21\x77\xe5\xd4\x92\
-\x24\xf1\x34\xcd\x21\x8a\xd0\x44\x15\x10\x1b\x49\x8d\x89\x71\xb2\
-\x4d\x9c\x89\x79\x9a\x59\xa1\xa5\xc4\x99\xcc\xf4\xfb\xfc\x6c\x51\
-\x51\xe1\x60\x28\x14\x5a\x4d\xbb\x20\xc6\x16\x09\x93\x93\x93\x77\
-\xbc\x1e\xf7\x91\xd3\xfe\xdc\xc6\x3c\x00\x0a\x48\x09\x65\xcb\x5b\
-\x92\xdb\x99\x4c\x7a\xfd\x2a\xff\xf2\x6b\x19\x7c\xc3\xca\xc4\x7d\
-\x65\x64\xf8\xa1\xb9\xb8\xe4\x85\x8c\xca\xca\xca\x33\x65\x65\x65\
-\x8f\x06\x06\x06\xe6\x9f\x28\xde\x85\xe3\xb8\xad\x50\x68\xb0\x57\
-\x12\x76\xc2\x76\x4c\xcc\xcb\x41\x89\x92\x43\x70\xb3\x98\x8d\xcf\
-\x64\x25\xc2\xbf\x2c\x0f\xde\xec\xfb\xfc\xf2\xe5\xee\xf7\x6d\x36\
-\x5b\xf6\x72\x24\x52\x9e\xe5\x72\x99\x03\x81\xe0\x1b\xc1\x60\x60\
-\x6e\x61\x61\x61\x62\x65\x65\x05\x3c\x0b\x84\x91\x4c\x23\xb9\x46\
-\x9c\x46\x28\xf0\x17\x79\x79\x79\x78\x4b\x4b\x4b\x77\x47\x47\x87\
-\xde\x73\xfd\xba\xbe\x14\x89\xa8\xfd\xfd\xfd\x17\xeb\xeb\xeb\xe1\
-\xe3\x13\x3f\x8e\x66\x24\x69\x84\x33\x22\x19\x41\x7f\x7b\x99\xce\
-\xf3\xfc\x5d\x87\xc3\x81\x8b\x82\xf0\x62\x22\x91\xc0\x6a\x6b\xeb\
-\x1a\xfd\x7e\x9f\x3d\x16\x8b\xfd\x30\x3b\x3b\xab\xa5\x11\xa7\x67\
-\x57\x6e\x1c\xf7\x58\x96\xe5\x29\x8a\x3a\xbe\xb8\xb0\x88\x55\x1d\
-\xa9\x0a\xd6\x54\x57\x17\x2b\x8a\x72\x73\x6c\x6c\x4c\xc5\xc1\x7f\
-\x24\x1e\x8f\x83\xf1\xf1\xf1\x9f\x0b\x0a\x0a\x96\x5d\x2e\xd7\xeb\
-\xe1\xa9\x29\xfc\x70\x71\x71\xa9\x21\xaf\x65\x18\xa6\x1f\x82\x3d\
-\xa0\xbd\xbd\xfd\xb4\xd1\x92\x1e\x51\x14\x99\x40\x20\x00\x34\x4d\
-\xfb\x09\x82\x3d\xc2\xf8\xcc\x86\x60\x30\x78\x63\x6d\x6d\xcd\x62\
-\x5c\xcf\x82\xbd\xa4\xb3\xb3\xb3\xb2\xb5\xb5\xf5\x0c\x30\xf8\x13\
-\x74\xaa\xde\x46\xd5\x46\x63\x32\x00\x00\x00\x00\x49\x45\x4e\x44\
-\xae\x42\x60\x82\
-\x00\x00\x02\xd6\
-\x89\
-\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
-\x00\x00\x10\x00\x00\x00\x10\x08\x06\x00\x00\x00\x1f\xf3\xff\x61\
-\x00\x00\x00\x01\x73\x52\x47\x42\x00\xae\xce\x1c\xe9\x00\x00\x00\
-\x06\x62\x4b\x47\x44\x00\xff\x00\xff\x00\xff\xa0\xbd\xa7\x93\x00\
-\x00\x00\x09\x70\x48\x59\x73\x00\x00\x06\xec\x00\x00\x06\xec\x01\
-\x1e\x75\x38\x35\x00\x00\x00\x07\x74\x49\x4d\x45\x07\xd8\x0b\x11\
-\x17\x19\x36\xe0\x1f\xbc\x7d\x00\x00\x02\x56\x49\x44\x41\x54\x78\
-\xda\x8d\x91\x5d\x48\x53\x71\x18\x87\x9f\x73\x66\x52\xe1\x32\x95\
-\x30\xb2\xd5\x12\xc2\x30\xa8\x30\xbd\x31\x2f\xba\xd1\x8b\x90\xc0\
-\xa0\x4f\xa2\x20\xb2\x4c\xab\x8b\x8c\x60\x41\x12\x18\x41\x82\x91\
-\x60\x81\x1f\x45\x17\xd2\xf7\x45\x17\x61\xa4\xa1\x61\x28\xa1\xa8\
-\x91\x59\x4a\xea\x14\x5d\x73\xb6\x4c\xcf\xce\x74\xba\xb3\xfd\x3b\
-\x1c\xd8\x58\x5b\x50\x0f\xbc\xbc\xef\xb9\x78\x9f\xdf\xcb\xff\x48\
-\x60\xb0\x16\xd8\xce\x7f\x50\xb0\x5b\x5e\x79\x7b\x63\x41\x9d\xe6\
-\x9a\x1b\x23\x21\xe1\x44\x48\x90\x2f\x84\x68\xe1\x1f\x04\xfc\x8b\
-\x78\x7a\x8b\x78\x79\xdf\x4e\x46\x7b\x80\x05\x97\xab\x33\x0e\x30\
-\xd0\x05\xfc\x70\xbb\x91\x65\xd9\x28\x49\x92\x90\xf5\xd2\x07\x63\
-\x86\x20\xcb\x5f\x4b\x79\xdd\xfa\x85\xeb\xad\x32\x07\x2c\x53\x5a\
-\x96\x47\x24\xc9\x44\x60\x32\x99\xc2\x02\x53\xa8\x9b\x4c\xc6\xec\
-\xb7\x57\xd1\xdb\xd3\xc5\x8d\xa6\x78\x76\x6e\x76\x73\xfa\xac\xe4\
-\x6a\xc9\x92\xcf\xc5\x41\x18\x23\xd1\x48\xd7\x4b\x9f\xc3\xdd\x37\
-\xf5\x08\xc7\xb7\x37\xd8\xea\xe3\x59\x6f\x9e\xe1\x56\xe9\x6a\x2a\
-\xea\x97\x6a\x9e\xb7\x69\xd3\x91\x17\xfc\x99\x1e\x4a\x9e\x7d\x8f\
-\x32\xfe\x84\x0b\xd5\x3e\x56\x48\x1e\x6a\x2e\x06\x59\x48\xad\x40\
-\x5f\xf6\x00\x93\x61\x81\x14\x4a\x8c\x90\x04\xd4\x21\xb4\xe9\xc7\
-\x5c\xb9\xeb\x61\x5e\x51\xa9\x2e\x51\xd0\x52\xcb\x50\xe5\x1d\x00\
-\x0e\x60\x31\xe6\x82\x90\x24\xe0\x73\x12\x9c\x7e\x88\xed\xce\x18\
-\x9f\x87\xdd\xdc\x3c\x35\x87\x79\xd3\x41\x66\x02\x79\x58\xad\x56\
-\x80\x25\x63\x27\xea\x0d\x8c\x12\x9a\x82\xd0\x97\xab\x1a\x07\x79\
-\xd7\xed\xc4\x76\x74\x8e\x2d\xdb\x72\x19\xf5\x15\x92\x96\x96\x86\
-\xc5\x62\x01\x20\x46\x60\xfc\x2e\xe1\x27\xe0\xa8\xe3\xc1\xb3\x7e\
-\x9e\x36\x4f\x50\x52\xe8\x21\x37\x27\x9d\xfe\x5f\x47\x48\x4e\x4e\
-\x21\x33\x33\x13\x01\x61\xe2\xa2\x05\xf3\x93\x6d\xb4\x35\xb7\x53\
-\xdb\x34\x49\x51\xde\x22\x87\x0a\x12\x79\x31\xb8\x9f\x29\xe7\x00\
-\xe6\x35\x49\xf4\xf5\xf5\xb1\xca\x9c\x08\xa0\xfd\x55\xa0\x7a\x25\
-\xbc\x41\x2b\x7b\x77\x8d\x51\x7e\x58\xe6\x95\xfd\x38\xc3\x23\xdf\
-\xa9\xac\xac\xd4\x2f\x48\x46\x55\x55\x2e\x95\x97\xbf\x05\xba\x62\
-\x04\x3f\x67\x1c\xcc\x3a\x3f\x90\xbe\xce\x49\x46\x51\x36\xe3\xf1\
-\xfb\xc8\xd9\x93\x8d\x39\x65\xc8\x58\xf6\x7a\xbd\xd8\xae\xda\x06\
-\x1a\x1b\x1a\x4e\x02\x3e\x22\xc8\x17\x3a\xf7\x6a\x6b\xc4\xb5\xcb\
-\xc7\x84\x63\xa4\x53\xf8\xfd\xcb\x22\x18\x0c\xea\xdd\x2f\x3a\x3a\
-\x3a\x84\xa2\x28\xa2\xec\x7c\xd9\x27\x60\x2b\x21\xa2\x05\x13\xf6\
-\x51\x11\xcd\xb2\x16\x10\xdd\x1f\x07\x44\xf1\x99\xe2\x16\x60\x03\
-\x51\x48\x60\x90\x02\x64\x85\xbf\x63\xd1\x80\x4e\x60\x89\x28\x7e\
-\x03\x99\xc3\x0a\xf4\x03\x8f\xf6\xf6\x00\x00\x00\x00\x49\x45\x4e\
-\x44\xae\x42\x60\x82\
-\x00\x00\x02\x7e\
-\x89\
-\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
-\x00\x00\x10\x00\x00\x00\x10\x08\x06\x00\x00\x00\x1f\xf3\xff\x61\
-\x00\x00\x00\x04\x73\x42\x49\x54\x08\x08\x08\x08\x7c\x08\x64\x88\
-\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x01\xbb\x00\x00\x01\xbb\
-\x01\x3a\xec\xe3\xe2\x00\x00\x00\x19\x74\x45\x58\x74\x53\x6f\x66\
-\x74\x77\x61\x72\x65\x00\x77\x77\x77\x2e\x69\x6e\x6b\x73\x63\x61\
-\x70\x65\x2e\x6f\x72\x67\x9b\xee\x3c\x1a\x00\x00\x01\xfb\x49\x44\
-\x41\x54\x38\x8d\x95\x92\x4f\x6b\x1a\x51\x14\xc5\x7f\xef\xa9\x38\
-\xcd\x7a\x16\x5d\x14\xa4\xd0\x65\x9b\x92\x45\x05\x91\xe2\xae\xed\
-\xb6\x76\xd7\x64\x95\x0f\x60\x3f\x44\x0b\xfd\x43\xc1\x76\x15\x42\
-\x20\x10\xb2\xf6\x3b\xe8\xc2\x8a\x28\x86\x5a\x90\x11\x0c\x74\x21\
-\xb3\x10\xd4\x2c\x26\xe3\x8c\xa3\x73\xbb\x88\x63\x75\x48\x0a\x3d\
-\x70\x37\xef\x71\xce\x3d\xf7\xde\xa3\x80\x47\xc0\x2e\xff\x87\xae\
-\x88\x0c\x00\x92\xc0\xee\x68\x34\xaa\x84\x22\x68\xad\xd1\x5a\xa3\
-\x94\xda\x2a\x80\xcb\xc1\x80\x76\xbb\xcd\xde\xde\x1e\xd9\x6c\xf6\
-\x0d\x30\x00\xd0\x00\xa1\xfc\xbb\xdd\xd5\xd5\x15\xc3\xe1\x90\x83\
-\x83\x03\x5a\xad\x16\x85\x42\xe1\x69\xf4\xa7\x01\x12\x09\x4d\x22\
-\x91\x58\x3b\xd0\x5a\x93\xd8\xa8\x45\x10\x60\x9a\x26\x3b\x3b\x3b\
-\x1c\x1e\x1e\x92\xcb\xe5\xde\x95\x4a\xa5\x27\x00\x0a\x28\x8e\x27\
-\x93\x0a\x22\xa8\x48\x40\x29\xc2\x30\xa4\xd3\xe9\xe0\xba\x2e\x8e\
-\xe3\xe0\x38\x0e\xfb\xfb\xfb\x18\x86\x81\x65\x59\xfd\xa3\xa3\xa3\
-\x7b\xae\xeb\xe6\x14\x50\x9c\x4c\xa7\x15\xe0\xaf\x83\xd5\xdc\xa9\
-\x54\x6a\xed\x2c\xda\x45\x84\x5e\xaf\x57\x2b\x97\xcb\xa3\x64\x44\
-\xbc\x4d\xe0\x36\x62\x1c\x37\x02\x11\x41\xa9\x9b\xd2\x9a\xe5\x72\
-\x49\xbd\x5e\xe7\xfa\xfa\x7a\x6b\x84\x74\x3a\x8d\x65\x59\xfd\xe3\
-\xe3\xe3\x87\xc0\xdb\x24\x80\x8a\x3b\xd0\x37\x4b\xcd\xe7\xf3\x28\
-\xa5\xb0\x6d\x1b\xdb\xb6\x49\xa7\xd3\xf8\xbe\xcf\xd9\xd9\xd9\x7d\
-\x11\x79\x7e\x72\x72\x62\x27\xa3\x4d\x46\x37\x8f\xc6\x61\xe3\xcd\
-\x30\x0c\xc6\xe3\x31\x9e\xe7\x71\x7a\x7a\x4a\xa3\xd1\xf8\x5e\xad\
-\x56\x7f\xad\xcf\x48\x8c\x1c\x0f\x92\x69\x9a\x64\x32\x19\xce\xcf\
-\xcf\xc9\x66\xb3\x52\xab\xd5\x2e\xb6\x72\x10\x27\xc4\x53\xe8\x79\
-\x1e\x4a\x29\x5e\xbc\x7a\xc9\x8f\x66\xb3\x09\xfc\xdc\x5c\x64\xd1\
-\x75\x5d\xf1\x3c\x4f\xe6\xf3\xb9\x04\x41\x20\x8b\xc5\x42\x96\xcb\
-\xa5\x84\x61\x28\x41\x10\x48\xb7\xdb\x95\xf9\xdc\x97\x0f\x5f\x3e\
-\xf7\x81\xc7\x80\x12\x11\x44\x64\x25\x30\x9b\xdd\x29\xe0\x38\x8e\
-\x0c\x2e\x2f\xe5\xfd\xa7\x8f\x7d\xe0\x19\xa0\x23\x72\x24\xf0\xda\
-\x9d\xcd\x42\xdf\xf7\x25\x08\x82\x2d\x01\x11\x91\xc9\x74\x1a\x7e\
-\x2d\x7f\x6b\xac\x3a\x6f\x91\x45\x04\x05\x3c\x58\x29\xdf\x95\x98\
-\x70\x35\xf3\x6f\x89\x5a\x6e\xe0\x0f\xd5\xf2\x24\x09\x1c\xd8\x9f\
-\xe3\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\
-\x00\x00\x02\x33\
-\x89\
-\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
-\x00\x00\x10\x00\x00\x00\x10\x08\x06\x00\x00\x00\x1f\xf3\xff\x61\
-\x00\x00\x00\x04\x73\x42\x49\x54\x08\x08\x08\x08\x7c\x08\x64\x88\
-\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x01\xbb\x00\x00\x01\xbb\
-\x01\x3a\xec\xe3\xe2\x00\x00\x00\x19\x74\x45\x58\x74\x53\x6f\x66\
-\x74\x77\x61\x72\x65\x00\x77\x77\x77\x2e\x69\x6e\x6b\x73\x63\x61\
-\x70\x65\x2e\x6f\x72\x67\x9b\xee\x3c\x1a\x00\x00\x01\xb0\x49\x44\
-\x41\x54\x78\xda\xa5\x93\x3f\x48\xc3\x40\x18\xc5\x5f\xa2\xd8\x74\
-\xab\xda\xc1\x3a\xd6\x55\xc4\xcd\x41\x10\xff\xd0\xad\x45\xa1\xe2\
-\x24\xae\x8e\xea\xe0\x20\xc5\x4d\xb0\xe8\xac\xb8\xbb\xa8\xb8\xd9\
-\xc1\x41\x67\x37\x05\xc7\x42\xc1\x0e\xd6\x52\x41\xcd\x35\x7f\x9a\
-\xb6\x97\x78\x5f\x22\xe1\x42\x1d\x0a\x7d\xb9\x7c\x97\xc0\xbd\xdf\
-\x3d\xbe\x5c\x14\xcf\xf3\x30\x88\x86\xa9\xe4\xb2\xd9\xef\x56\xcb\
-\x49\xec\xec\xed\x43\x96\xa2\x52\x55\xa1\xaa\x0a\x14\x05\x50\x10\
-\xdc\xa7\x27\x45\x68\x5a\xec\xe7\xae\x54\x1a\xf5\x01\x96\x69\x25\
-\x26\x52\x13\x58\x58\x5c\x82\x27\x03\x80\xc0\x28\x0a\x41\xc4\xf0\
-\xe7\xdb\x9b\x2b\x54\x2a\x95\x44\x98\xc0\x75\x5d\x68\x31\x0d\xda\
-\xc8\x10\x2e\x1f\x5e\xa3\x29\xfc\x42\x23\x48\xb1\x95\x99\x01\xe7\
-\xdc\xf7\x84\x00\x2e\x5e\xba\xdd\xae\xa0\x03\x9b\x2b\xd3\xb4\x3e\
-\x4c\x42\x3d\x72\xbd\xbf\x59\x3c\x98\x4e\x87\xd6\xfa\x9e\x48\x02\
-\xa2\x36\xed\x36\x99\x43\x79\x01\x81\x06\x5c\x02\x04\x90\xde\x04\
-\x2e\xe7\x3e\xd5\x10\x80\xeb\xfb\x27\xc8\x0a\xbf\x12\xa5\x10\x57\
-\x3e\x33\x47\x6b\xc9\xd3\x9b\x80\x19\x36\x32\xf3\xb3\xb2\x1b\x9e\
-\x64\x26\x56\xd3\x74\xfe\x49\xe0\x72\x70\x41\x3d\xdc\xdd\x46\x9f\
-\x22\x8f\xd4\x44\x1e\x34\xb1\x7f\x05\x9e\x68\x0f\x3a\x1d\x90\x8e\
-\x8a\xc7\x88\xc7\xe3\x61\x7c\x3a\x03\x24\x8a\xbd\x91\x5f\xf7\xe7\
-\xa9\x74\x3a\xda\x83\x8e\xd8\xdd\x69\xb7\x41\x2a\x97\xcb\xb8\x38\
-\x3b\x87\x65\x5b\x38\x28\x14\x20\x2b\x35\x39\x89\xda\x47\x8d\x3e\
-\x21\x79\x24\x80\xd8\xdd\x71\x1c\x90\x18\x63\x30\x4d\x13\x86\x61\
-\x40\xd7\x75\xc8\xf2\x84\xd1\x15\xd1\x93\xc9\x24\xde\xaa\xd5\x48\
-\x13\xbf\x18\xd3\xc7\xe8\x34\x32\x9d\xc1\xb6\x6d\x4a\xd4\x03\x20\
-\x30\x6d\x66\x5b\x16\xb8\x9c\x40\xe1\x7c\x99\x35\x9b\x8f\xba\xce\
-\xc6\x1b\x9f\x0d\xe4\xd6\x56\x41\xaa\xd7\xeb\x90\xf5\x5e\xab\x51\
-\x0e\x3c\xbf\xbc\x40\x1d\x52\x7f\x20\x34\xf0\xef\xfc\x0b\xfb\xd2\
-\x1e\xf6\x17\x50\x4f\x5c\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\
-\x60\x82\
-\x00\x00\x02\x13\
-\x89\
-\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
-\x00\x00\x10\x00\x00\x00\x10\x08\x03\x00\x00\x00\x28\x2d\x0f\x53\
-\x00\x00\x00\x03\x73\x42\x49\x54\x08\x08\x08\xdb\xe1\x4f\xe0\x00\
-\x00\x00\x09\x70\x48\x59\x73\x00\x00\x0d\xd7\x00\x00\x0d\xd7\x01\
-\x42\x28\x9b\x78\x00\x00\x00\x19\x74\x45\x58\x74\x53\x6f\x66\x74\
-\x77\x61\x72\x65\x00\x77\x77\x77\x2e\x69\x6e\x6b\x73\x63\x61\x70\
-\x65\x2e\x6f\x72\x67\x9b\xee\x3c\x1a\x00\x00\x00\xe4\x50\x4c\x54\
-\x45\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
-\x42\x88\xdb\x42\x88\xdb\x42\x87\xdb\x41\x87\xdb\x21\x64\xb2\x23\
-\x6b\xbf\x23\x6c\xc1\x29\x71\xc4\x31\x66\xa6\x31\x77\xca\x3a\x7e\
-\xcf\x41\x87\xdb\x43\x85\xd5\x48\x7c\xbe\x4b\x8c\xda\x54\x93\xe0\
-\x55\x84\xc1\x68\x90\xc4\x6e\x95\xc8\x72\xa5\xe4\x78\xa8\xe6\x79\
-\xa8\xe4\x7e\x96\xb3\x7e\x97\xb4\x85\x9a\xb3\x8b\xb6\xec\x94\xa5\
-\xb7\x95\xb7\xe1\x98\xbc\xeb\xa0\xc5\xf2\xa1\xc2\xed\xa4\xc5\xec\
-\xa5\xc6\xec\xa6\xc6\xec\xa9\xc7\xee\xad\xca\xed\xaf\xcb\xed\xaf\
-\xcb\xef\xb1\xcc\xf0\xbc\xd3\xf1\xbf\xd6\xf4\xc0\xd8\xf1\xe3\xe4\
-\xe5\xe6\xe7\xe8\xe7\xe8\xe8\xe9\xea\xeb\xeb\xec\xec\xec\xed\xed\
-\xed\xee\xee\xee\xef\xef\xef\xf0\xf0\xf0\xf0\xf0\xf0\xf1\xf1\xf1\
-\xf1\xf1\xf1\xf2\xf2\xf2\xf3\xf3\xf3\xf3\xf3\xf3\xf4\xf4\xf4\xf5\
-\xf5\xf5\xf5\xf5\xf5\xf6\xf6\xf6\xf6\xf6\xf7\xf7\xf7\xf8\xf8\xf8\
-\xf9\xf9\xf9\xfa\xfa\xfa\xfb\xfb\xfb\xfc\xfc\xfc\xfd\xfd\xfd\xfe\
-\xfe\xfe\xff\xff\xff\x08\x2e\x0f\x60\x00\x00\x00\x09\x74\x52\x4e\
-\x53\x00\x1f\x3c\x3e\x3f\xfa\xfc\xfd\xfe\x0a\x2f\x02\x16\x00\x00\
-\x00\x8c\x49\x44\x41\x54\x18\x19\x05\xc1\x41\x4a\x03\x51\x14\x04\
-\xc0\xea\xfe\x2f\x82\x89\x88\x20\xb8\xf4\x3c\x1e\xd9\x03\x09\x82\
-\x3b\x03\x6e\x74\x32\x63\x55\x48\x09\x1c\xf6\xc3\xd0\x37\x00\xef\
-\x37\x73\xba\xdc\x7c\xa4\x4d\x92\x67\x4c\x5e\xbf\xb5\xed\x6a\xe2\
-\xbc\x8c\xdf\x5d\x3b\x6b\xad\xf0\xf4\xf0\x39\xd9\x76\x9d\x99\x95\
-\xb0\xdf\x4c\x42\xe7\xd4\x26\x60\x24\x66\xb5\x49\x22\xe4\x62\x0f\
-\x80\xa3\x26\x8f\xdb\xcb\x0e\xe8\xd7\x5c\xa7\xfb\xf6\xf7\x0b\xb8\
-\xdb\xda\x49\xd6\x6c\x80\x59\xc9\xf4\xb4\xf7\x0c\xd0\x53\xa7\xd3\
-\x1f\x00\xf7\xed\xe4\x0a\x00\x92\x24\x02\x70\x1c\xc7\x3f\xb4\x2c\
-\x21\xd5\x80\x04\x87\x89\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\
-\x60\x82\
\x00\x00\x02\xf9\
\x89\
\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
@@ -80230,63 +79946,6 @@
\xea\x24\x0f\x93\xcc\x00\x6a\x00\x7e\x03\x38\x00\x50\x3d\x94\x6f\
\x8c\xf9\xf3\x17\xb1\x57\xd8\xfd\x23\x30\x24\x2d\x00\x00\x00\x00\
\x49\x45\x4e\x44\xae\x42\x60\x82\
-\x00\x00\x03\x70\
-\x89\
-\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
-\x00\x00\x16\x00\x00\x00\x16\x08\x06\x00\x00\x00\xc4\xb4\x6c\x3b\
-\x00\x00\x00\x04\x73\x42\x49\x54\x08\x08\x08\x08\x7c\x08\x64\x88\
-\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x03\x76\x00\x00\x03\x76\
-\x01\x7d\xd5\x82\xcc\x00\x00\x00\x19\x74\x45\x58\x74\x53\x6f\x66\
-\x74\x77\x61\x72\x65\x00\x77\x77\x77\x2e\x69\x6e\x6b\x73\x63\x61\
-\x70\x65\x2e\x6f\x72\x67\x9b\xee\x3c\x1a\x00\x00\x02\xed\x49\x44\
-\x41\x54\x78\xda\xb5\x95\x3d\x48\x5b\x51\x18\x86\xdf\x9b\x7b\xf3\
-\xe7\x4f\x89\x15\x21\xd1\x41\x6b\x25\x85\x06\xd3\xa9\x43\x70\xa8\
-\x89\x50\x3b\x77\xeb\xda\xc5\xcd\xcd\xc5\xad\x14\x04\xe9\xe6\xe8\
-\x22\x88\xd0\xc1\xdd\x59\x1c\x2b\x1d\x1a\x74\x68\x35\x6d\x21\xd4\
-\x04\xff\x62\x34\xb9\x31\x3f\xe6\xf4\x7b\xaf\xde\x78\xbd\xe2\x1f\
-\xb4\x2f\x7c\x5c\x38\xf9\xce\x73\xbe\xf3\x7e\xe7\x9c\x68\x4a\x29\
-\xb8\xa5\x69\xda\x10\x80\x38\xee\xa7\xb4\x30\xb6\xe1\x16\xc1\xee\
-\x10\xbd\x55\xf7\xd4\x45\x2e\xdc\xe1\xc1\xff\xd1\xcd\xe0\x46\xa3\
-\xf1\x6f\xc1\xcb\xcb\xcb\xfa\xc8\xc8\xc8\xf3\x6a\xb5\x76\x27\x9c\
-\xbf\x33\x97\x73\xe0\x92\x01\x97\x6a\xb5\xda\xbb\x54\x2a\xf5\xb1\
-\x54\x2a\xe3\xec\xac\x09\xbf\xdf\x0b\x5d\x37\x24\x3c\x6c\x2a\xfd\
-\xe3\xb8\x44\x03\xd5\x6a\x1d\xcc\x95\x39\xbf\x01\x2c\xdd\x0a\x36\
-\x0c\x23\xb8\xb3\xb3\x83\x93\x93\x12\x2b\x92\x85\xfc\xf0\x7a\xbd\
-\x32\xae\xdb\x60\x19\x3f\x43\xbd\x5e\x17\x70\x15\xcc\x8d\xc5\x62\
-\xc1\x6b\x9c\xd9\xd9\xd9\x27\x00\x7e\x42\xd4\xde\xde\x6e\xc5\xfe\
-\xfe\x3e\x8e\x8e\x8a\x02\xad\x23\x10\xa8\x09\x98\x15\xeb\x8e\x8a\
-\x09\x6e\xe0\xf4\xb4\xca\x5c\x16\x30\xbf\xb8\xb8\x38\x7f\x7c\x7c\
-\x8c\x72\xb9\x4c\xd4\x20\x2b\x1e\x93\x10\x40\x00\x9d\x9d\x9d\x28\
-\x16\x8b\xd8\xdd\xdd\x45\xa1\x70\xc4\x8a\xc4\x0a\x3f\x7c\x3e\xcb\
-\x0e\x07\x98\x3b\x39\xaf\x98\xb9\x9c\xd3\xdb\xdb\x6b\x2f\x2a\x0b\
-\x9e\xa6\x08\x4e\x79\x3c\x9e\x56\xb5\xa5\x52\x09\xa1\x50\x08\x33\
-\x33\x1f\x98\x78\xe5\xac\x53\x84\x33\x6c\x49\x2e\xed\x43\x47\x47\
-\x07\x2b\xa7\x45\xec\xd3\x98\x91\x1a\x7b\x15\x1f\x7a\xfa\x0c\xb6\
-\xf6\xf6\xf6\xd0\xdf\xdf\x8f\x87\x28\x1a\x8d\xa2\xa7\xa7\x07\xb6\
-\xb6\x33\xdf\xe3\x46\xb0\xad\x4d\xb6\xea\x83\x2d\x6e\x4b\xfc\xc2\
-\x43\x34\x35\x35\x85\xbe\xbe\x3e\xd8\x12\x26\x9b\xed\x73\x82\xe9\
-\x91\xf8\x5b\x80\x2d\x36\x2d\x1c\x0e\x3b\xad\xa0\xaf\xdc\xb2\x73\
-\xce\x15\x06\x99\xda\xd6\xd6\xf6\x46\x3e\x9f\x8b\x35\x9b\x4d\x50\
-\xf2\xa5\x47\xce\x49\x6c\x06\x9c\x62\xa3\xb9\xa0\x2d\x42\xd9\x27\
-\x8a\xdf\x70\x38\xb2\x69\x68\x9a\xce\x73\x08\x5b\x84\x54\x2a\x15\
-\x38\x75\xc3\x0b\x78\xb9\xf5\x60\xd0\x5a\x6c\x6d\x6d\x0d\x89\x44\
-\x42\xee\x80\x09\x23\x9b\xfd\x23\x7e\x5c\x26\xcd\xcd\xcd\x61\x75\
-\x75\x15\xa6\x69\xba\x4e\xc4\x75\x28\xbf\x84\x26\x93\x49\x4c\x4e\
-\x4e\xb2\x28\x81\x9e\x20\x9b\xcd\x43\x5b\x58\xf8\xbc\x11\x8f\x47\
-\x59\x32\x2d\xb0\xfc\x1c\x1f\x7f\x23\xc7\xed\x13\xb7\xc8\x5b\x67\
-\x5f\x10\x06\x61\x12\x5c\x90\xa1\x30\x31\xf1\x1e\x2b\x2b\x2b\xc8\
-\xe7\xf3\x2d\x9f\xd3\xe9\x1f\x9b\xc6\xe1\x61\xc1\x1a\xa4\x78\xe0\
-\x23\x91\x08\x1f\x16\x74\x77\x3f\x96\xcb\x61\x35\x96\xe7\x94\xc1\
-\xf7\xc2\xf6\xb2\xd5\x8f\xd1\xd1\xa4\xb5\x58\x2e\x97\xb3\x2e\x13\
-\x45\xa6\xfb\x1f\x44\x2a\x9d\x51\x03\x03\x83\x6a\x78\xf8\x85\x76\
-\x0e\xf6\x5e\x40\x75\x42\x25\x68\x03\x43\x09\x58\x61\x7d\xfd\x8b\
-\x4a\xa7\xbf\x69\xd3\xd3\xd3\xda\xad\x8f\xd0\xc1\xc1\x01\x08\x0d\
-\x85\x1e\x09\xf4\x3a\xd8\x6d\x45\x57\x57\x97\xc6\x39\x77\xfe\x35\
-\x89\x5e\x67\x32\xbf\x8a\xf2\x08\x29\xd3\xac\x28\xf1\x5d\xc9\x91\
-\x53\x37\x49\x9a\x55\x04\x30\xee\xe6\xd0\x0a\x56\xa1\x03\xa0\x41\
-\x41\x89\x41\x89\x97\x12\x5e\x8e\xb9\x82\x06\x37\xd8\x0e\xf6\xda\
-\xf1\xfd\x2a\x91\x91\x30\x25\x2a\xcc\xf9\x0b\x3e\xfb\xf9\xce\xd4\
-\xa5\xbf\x61\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\
\x00\x00\x04\x9e\
\x89\
\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
@@ -80363,61 +80022,270 @@
\x59\xeb\x74\x3a\xaf\x04\x83\x41\x8d\x7c\x3d\x09\xb6\x93\x8e\x8e\
\x8e\xf2\x96\x96\x96\x66\x20\xf3\x3b\xa7\x36\xda\x5d\x07\xdf\x7a\
\xe1\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\
-\x00\x00\x03\x41\
-\x89\
-\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
-\x00\x00\x10\x00\x00\x00\x10\x08\x03\x00\x00\x00\x28\x2d\x0f\x53\
-\x00\x00\x00\x01\x73\x52\x47\x42\x00\xae\xce\x1c\xe9\x00\x00\x00\
-\x09\x70\x48\x59\x73\x00\x00\x0d\xd7\x00\x00\x0d\xd7\x01\x42\x28\
-\x9b\x78\x00\x00\x00\x07\x74\x49\x4d\x45\x07\xda\x01\x16\x02\x14\
-\x1d\x79\x4f\xdb\xf8\x00\x00\x01\xa7\x50\x4c\x54\x45\x00\x00\x00\
-\x00\x00\x00\x00\x00\x00\x02\x02\x02\x09\x09\x09\x09\x09\x09\x00\
-\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
-\x00\x02\x02\x02\x00\x00\x00\x01\x01\x01\x00\x00\x00\x00\x00\x00\
-\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
-\x00\x00\x00\x00\x00\x00\x00\x00\x02\x02\x02\x00\x00\x00\x30\x30\
-\x30\x00\x00\x00\x00\x00\x00\x3d\x3d\x3d\x00\x00\x00\x9a\x9a\x9a\
-\x10\x10\x10\x9b\x9b\x9b\x5d\x5e\x5e\x35\x36\x36\x80\x80\x81\xb0\
-\xae\xaf\xc5\xc5\xc6\xe9\xea\xea\xf1\xf1\xf1\x50\x52\x53\x51\x52\
-\x53\xfc\xfd\xff\xfd\xff\xff\xfe\xfe\xfe\x18\x18\x1a\x1c\x47\x9c\
-\x1d\x1e\x1f\x1f\x49\x9e\x2f\x56\xa4\x40\x70\xc3\x43\x71\xc4\x51\
-\x7d\xc9\x57\x8d\xe5\x59\x90\xe7\x67\x9d\xee\x74\x76\x78\x88\x9e\
-\xc8\x8a\x8b\x8d\x8a\x9f\xc9\x8d\x8d\x8e\x8d\x8d\x91\x8e\x8e\x8f\
-\x8e\xa3\xca\x90\x91\x92\x94\x95\x96\x96\x95\x97\x97\x99\x9b\x99\
-\x9a\x9b\x99\x9b\x9b\x9c\x9e\xa0\xaa\xab\xae\xcf\xd0\xd3\xd3\xd5\
-\xd9\xd6\xd5\xd2\xda\xdd\xdf\xdb\xde\xe1\xdd\xe1\xe3\xe0\xe2\xe5\
-\xe0\xe3\xe5\xe1\xe2\xe6\xe1\xe3\xe6\xe2\xe3\xe8\xe3\xe5\xe7\xe6\
-\xe8\xea\xe8\xe9\xea\xe8\xea\xec\xe8\xea\xed\xe8\xeb\xed\xe9\xea\
-\xee\xe9\xeb\xec\xea\xe8\xe4\xea\xeb\xee\xea\xed\xf3\xeb\xed\xee\
-\xeb\xee\xf5\xec\xed\xef\xec\xee\xef\xec\xef\xf5\xed\xee\xef\xed\
-\xef\xf2\xef\xf0\xf1\xef\xf1\xf1\xf0\xf2\xf2\xf1\xf1\xf1\xf1\xf2\
-\xf3\xf2\xf2\xf2\xf2\xf4\xf6\xf3\xf5\xf6\xf3\xf5\xf9\xf4\xf3\xf0\
-\xf4\xf4\xf5\xf4\xf5\xf6\xf4\xf5\xf7\xf4\xf6\xf7\xf5\xf3\xf1\xf5\
-\xf4\xf2\xf5\xf5\xf5\xf5\xf6\xf7\xf5\xf7\xf9\xf6\xf3\xf0\xf6\xf6\
-\xf7\xf6\xf8\xfa\xf7\xf7\xf8\xf8\xf9\xfa\xf8\xfa\xfc\xf9\xf7\xf4\
-\xf9\xfa\xfb\xf9\xfb\xfc\xfa\xfb\xfc\xfb\xfb\xfc\xfb\xfc\xfd\xfb\
-\xfd\xfd\xfb\xfd\xff\xfc\xfc\xfd\xfc\xfd\xff\xfd\xfd\xfe\xfd\xfe\
-\xff\xff\xff\xff\xd0\x32\x98\xa6\x00\x00\x00\x2f\x74\x52\x4e\x53\
-\x00\x01\x02\x03\x06\x08\x0d\x0f\x13\x1e\x24\x30\x33\x38\x3a\x3b\
-\x3c\x3f\x40\x46\x49\x4a\x4d\x53\x5b\x5d\x61\x63\x69\x6f\x6f\x73\
-\x91\x93\x96\x9f\xaa\xb8\xce\xde\xf2\xf7\xfe\xfe\xfe\xfe\xfe\xc1\
-\x92\xd1\x86\x00\x00\x00\x01\x62\x4b\x47\x44\x8c\x6c\x0b\xd2\x43\
-\x00\x00\x00\xd8\x49\x44\x41\x54\x18\xd3\x63\x60\x00\x02\x36\x05\
-\x25\x76\x06\x24\xc0\x22\xdd\xd3\x23\xc7\x8a\xe0\x33\x09\x68\xe8\
-\xe9\x69\x8a\x30\xc3\x05\xb8\xd4\x5a\x6a\x6b\x9b\xd5\xb9\x19\xa1\
-\x7c\x0e\xe5\xd6\x6c\x20\xa8\x53\xe5\x84\xf0\xf9\x14\xeb\x75\x13\
-\x80\x40\xa7\x47\x45\x84\x5f\x40\x80\x87\x41\xd4\x5e\x4b\xbf\x32\
-\x2c\xac\xd2\x50\xdb\xca\xa7\xa0\x34\x9f\x97\x41\x28\x2a\xc8\x35\
-\x3a\x20\x20\xc2\x23\x38\xd6\xc2\xd2\x3c\x5e\x90\x41\x38\x37\xcd\
-\x3b\xd0\xdf\xd7\xcf\x2b\xb2\xca\xc4\xcc\x34\x51\x98\x41\xac\xdd\
-\xc6\xc5\xc9\x33\x24\x34\x26\xae\xc1\xc0\xd8\x28\x45\x8c\x41\xbc\
-\xa6\xb8\xb8\x24\x3b\x35\x39\x29\xb9\xcc\xd6\xd1\xba\x46\x9c\x41\
-\xa2\x29\x3d\x3d\xa3\x22\x2f\xaf\xba\xa8\x28\x33\x27\xab\x4d\x82\
-\x41\xaa\x33\x3b\xbb\xd1\xc1\xcd\xdd\xce\xcd\x39\x3c\x3b\xbb\x5b\
-\x8a\x41\xa6\xa7\xb0\xb0\xbc\x03\x04\xba\xaa\x0b\x0b\x7b\x64\x18\
-\x64\x7b\x50\x80\x2c\x83\xa4\x3c\x0a\x90\x04\x00\x22\x75\x40\x01\
-\xd9\xb4\x9c\x69\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\
-\
+\x00\x00\x02\x74\
+\x89\
+\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
+\x00\x00\x10\x00\x00\x00\x10\x08\x06\x00\x00\x00\x1f\xf3\xff\x61\
+\x00\x00\x00\x04\x73\x42\x49\x54\x08\x08\x08\x08\x7c\x08\x64\x88\
+\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x01\xbb\x00\x00\x01\xbb\
+\x01\x3a\xec\xe3\xe2\x00\x00\x00\x19\x74\x45\x58\x74\x53\x6f\x66\
+\x74\x77\x61\x72\x65\x00\x77\x77\x77\x2e\x69\x6e\x6b\x73\x63\x61\
+\x70\x65\x2e\x6f\x72\x67\x9b\xee\x3c\x1a\x00\x00\x01\xf1\x49\x44\
+\x41\x54\x38\x8d\x95\x93\x3f\x6f\xd3\x50\x14\xc5\x7f\xef\xc5\x55\
+\x90\x53\x67\xcc\x84\xba\x84\xa1\x09\xa8\x4b\x93\x2c\xcd\x58\xa9\
+\x4b\x16\xda\xaf\x90\xa5\x9f\x03\x24\xfe\x08\x09\xb6\x6e\xf9\x06\
+\x0c\xc0\x02\x6b\x55\x84\xb2\xb5\x69\x15\xb5\x12\x55\x28\x63\x14\
+\xd1\x01\x63\x3b\xf6\xf3\xbb\x2c\xb5\xb1\x69\x19\xb8\xd2\x1d\x9e\
+\xf4\xce\xb9\xe7\x9c\xab\xab\x44\x04\x00\xa5\xd4\x03\x60\x83\xff\
+\xab\x89\x53\x78\x6c\xcc\xe7\xf3\xb7\xbf\x82\x80\xf1\x78\x4c\xdd\
+\xf3\xd8\xec\x74\x58\x59\x59\x41\x29\x85\x52\x2a\x1b\x04\x80\xd6\
+\x1a\x6f\x75\x75\x4f\x17\xe9\xac\xc0\xe7\xa3\x23\x3a\x9b\x9b\xac\
+\xad\xad\x31\x9d\x4e\xc9\x14\x66\x60\x05\x79\x03\x14\x15\x50\xa9\
+\x68\xa2\x28\xa2\xd1\x68\x50\xad\x56\x09\xc3\x90\xef\x57\x57\x34\
+\x9b\xcd\x3f\x2a\x32\x92\x4c\xd1\x70\x38\xfc\xe8\x38\xce\x8e\xeb\
+\xba\xb8\xae\x4b\xbd\x5e\xa7\xdb\xed\xb2\xb5\xb5\x85\x31\x86\xd3\
+\xb3\x33\x5a\xeb\xeb\x38\x8e\x93\x83\x01\x94\xd6\xdc\xab\x56\xf7\
+\x1c\x60\xe7\xe0\xe0\xa0\x94\x8c\xb5\x16\x6b\x2d\x95\x4a\x85\x87\
+\xed\x36\x69\x9a\xa2\xb5\xbe\x33\x8b\x92\x85\xa2\x57\x6e\x3e\x2b\
+\xa5\xd0\x5a\xa3\xb5\x2e\x01\xb3\x72\x80\x4f\xfb\xfb\xfb\x25\x0b\
+\xbd\x5e\x8f\x7e\xbf\x8f\x15\xe1\xfc\xfc\x9c\x56\xab\x75\x6b\x72\
+\x5e\x22\x92\x25\xbd\xfb\xd3\xf7\x65\x34\x1a\x89\xef\xfb\x62\x8c\
+\x91\xe3\xe3\x63\x99\x4e\xa7\x92\x24\x89\x18\x63\xc4\x18\x23\x69\
+\x9a\xe6\x0d\xec\x96\x2c\x28\xc0\x75\x5d\x16\x8b\x05\x71\x1c\x13\
+\x04\x01\xed\x76\xfb\x4e\xef\x45\x0b\x45\xf3\x6c\x6f\x6f\x73\x78\
+\x78\x88\xe7\x79\xf4\xfb\xfd\x5b\xe1\x65\x01\x27\x89\x11\xc0\x96\
+\x15\x28\x45\xad\x56\x63\x30\x18\xe4\xa0\x22\x38\x8a\x22\x66\xb3\
+\x19\x35\x6f\x95\x77\xef\x3f\x8c\x81\x93\x52\x06\x41\x10\x48\x14\
+\x45\x12\xc7\x71\xee\x3b\x4d\x53\xb1\xd6\x4a\x92\x24\x32\x99\x4c\
+\x24\x8e\x97\xf2\xf4\xe5\x8b\x0b\xe0\x11\xa0\xca\x04\x61\xf8\x4f\
+\x02\xdf\xf7\xe5\xeb\xe5\xa5\x3c\x79\xfe\xec\x02\xe8\x02\x5a\x44\
+\x4a\x5b\x78\x1c\x84\xa1\x5d\x2e\x97\x92\x24\x49\x89\x40\x44\xe4\
+\xc7\xf5\xb5\x7d\xf5\xfa\xcd\x97\x9b\xc9\x3a\xc3\xa9\xc2\x39\xdf\
+\xbf\x61\xfe\x6b\xd1\x79\x59\xe0\x04\xf8\x26\x85\x0b\xfb\x0d\xc2\
+\xe3\x2f\xb3\xa8\x69\x9b\xe3\x00\x00\x00\x00\x49\x45\x4e\x44\xae\
+\x42\x60\x82\
+\x00\x00\x03\x2f\
+\x89\
+\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
+\x00\x00\x10\x00\x00\x00\x10\x08\x06\x00\x00\x00\x1f\xf3\xff\x61\
+\x00\x00\x00\x01\x73\x52\x47\x42\x00\xae\xce\x1c\xe9\x00\x00\x00\
+\x06\x62\x4b\x47\x44\x00\xff\x00\xff\x00\xff\xa0\xbd\xa7\x93\x00\
+\x00\x00\x09\x70\x48\x59\x73\x00\x00\x03\x76\x00\x00\x03\x76\x01\
+\x7d\xd5\x82\xcc\x00\x00\x00\x07\x74\x49\x4d\x45\x07\xda\x03\x0c\
+\x0f\x1f\x23\x16\x66\x68\x50\x00\x00\x02\xaf\x49\x44\x41\x54\x38\
+\xcb\x95\x92\x4d\x6b\x24\x55\x14\x86\x9f\x5b\x1f\x5d\xd5\x5d\xdd\
+\xda\x5d\x55\x19\xa3\x61\x20\xb8\x10\x61\x42\x76\xc9\x2a\x38\x2e\
+\x8c\x3b\x37\xc1\xcd\xfc\x07\x0d\x08\x6e\x02\xd9\x38\x5b\x05\x21\
+\xce\x1f\x88\xff\x20\x30\xd9\x89\x04\x09\x04\x87\x2c\x24\x04\xc4\
+\x91\x86\x18\x8c\x4c\xba\x53\x49\x77\xd7\x47\xdf\xaa\xba\x55\xd7\
+\x45\xe8\xc4\x01\x5d\xf8\xc2\xe1\x2c\x0e\xe7\x39\x87\x97\x57\xec\
+\xef\xef\x3f\x09\x82\xe0\xbb\x76\xbb\x1d\x00\x18\x86\x81\x10\x02\
+\x21\x04\x33\x69\xad\xef\xba\xd6\x9a\xba\xae\x91\x52\x46\x83\xc1\
+\xe0\x73\x71\x74\x74\x74\xb5\xb7\xb7\x17\x44\x51\x44\xb3\xd9\xc4\
+\x71\x1c\x1a\x8d\x06\xb6\x6d\x63\x9a\x26\x00\x75\x5d\xa3\x94\xa2\
+\x2c\x4b\xf2\x3c\x47\x4a\x49\xaf\xd7\x63\x63\x63\x23\xb2\x3c\xcf\
+\x0b\xfa\xfd\x3e\x4f\x1f\x7d\x4a\x10\x86\x77\x57\x51\x35\x14\x0a\
+\x8a\x02\x2a\x05\xe5\xac\x2a\xa2\xf8\x9a\xa7\xa3\x9f\xf1\x3c\x2f\
+\xb0\x66\x17\xe6\x12\x4d\xd0\x2d\xc0\x2b\xc0\x4b\x61\x98\x40\x95\
+\x40\x91\xc1\x34\x87\x44\x42\x52\xc2\xa4\xc2\x18\x8c\xa9\x1e\x56\
+\x00\x58\x00\x55\x55\x21\x8c\x31\xb8\x0a\x3e\x19\x42\x3b\x85\xb3\
+\x09\xfc\x70\x09\x64\xa0\x25\xe4\x39\x50\x83\xaa\x10\xba\xa0\xaa\
+\xe6\x6f\x01\x33\x53\x8a\xf0\x15\x97\x4d\x8d\xb8\x98\x32\xf7\xf0\
+\x1d\x44\x47\x82\xbe\x02\x62\xb0\x26\x24\xcd\x84\xeb\x3c\x01\xa1\
+\x90\x6e\x03\xad\xdf\xba\x07\xb8\xae\xcb\xf7\xc3\x33\xbc\xc4\x21\
+\xf9\x65\x82\xa1\x5f\xa2\x8b\x29\xe9\x28\xe6\xe2\x26\x25\x8a\x53\
+\xd2\x24\xc6\x50\x05\x0d\x03\x92\x7c\x82\xbf\x24\xee\x01\x37\x37\
+\x37\xfc\x78\xf1\x2b\xf3\x0f\x7c\x16\x17\x4c\xe6\x7b\x9a\xdf\xce\
+\x46\xfc\xf1\x67\xca\x24\x9e\x92\x26\x19\x85\xaa\x10\xc2\xc0\xb2\
+\x4d\xf2\x42\xe0\x66\x19\x5a\xeb\x5b\x0f\xca\xb2\xe4\xf7\xb3\x6b\
+\x5e\x8d\xc6\xbc\xbb\x50\x51\xeb\x8a\x69\x59\xf3\xf2\xd2\x20\x95\
+\x0e\xa6\xd5\xa5\x50\x05\x9d\x4e\x07\xcb\xb2\x18\x4e\x86\x84\x65\
+\x79\x6f\xa2\x52\x8a\xce\xc2\x7b\xb8\x6f\x08\x22\xab\x46\xd6\x39\
+\x63\x53\xe1\xce\x09\x2a\xd9\xc4\x69\xb5\xa8\xeb\x1a\xd3\x34\x31\
+\x4d\x93\x6e\x6b\x0e\xa5\xd4\x2d\x20\x4d\xd3\x68\x79\x79\x39\xe8\
+\xf7\xfb\xb4\x5a\x2d\xae\x06\x4d\x12\xd7\xc5\x7f\xd3\xe5\x83\x15\
+\x07\xc3\x30\x28\x8a\xe2\x2e\x40\x52\x4a\xb2\x4c\xb3\xb8\xb8\x48\
+\x96\x65\x91\xd8\xdd\xdd\x7d\xb2\xb4\xb4\xf4\xac\xd7\xeb\xf9\xfc\
+\x0f\xc5\x71\x7c\x7d\x7a\x7a\xfa\x99\xf8\x8f\xb9\xb1\xb3\xb3\xf3\
+\x4d\x18\x86\x5f\x28\xa5\x38\x3f\x3f\xff\x76\x7b\x7b\xfb\xcb\xdb\
+\x20\xbc\xae\xd7\x00\x5b\x5b\x5b\xef\xaf\xaf\xaf\x7f\x6d\x18\xc6\
+\x63\xd7\x75\x3b\xe3\xf1\x18\x29\x25\x8e\xe3\x60\xdb\x76\x62\x9a\
+\xe6\x4f\x27\x27\x27\x5f\x6d\x6e\x6e\xbe\x98\xed\x58\xff\x04\x84\
+\x61\xf8\x61\xa7\xd3\xf9\xd8\xf7\xfd\x86\xd6\x9a\x6e\xb7\x8b\x10\
+\x02\xdb\xb6\xd1\x5a\xb7\xa3\x28\xfa\x48\x29\xf5\x1c\x78\xf1\xaf\
+\x1f\x00\xc2\xf7\xfd\x07\x6b\x6b\x6b\x8f\x57\x56\x56\xde\x5e\x5d\
+\x5d\xed\x3a\x8e\x23\x8e\x8f\x8f\x47\x87\x87\x87\x7f\x1d\x1c\x1c\
+\x1c\x8c\x46\xa3\x21\xa0\x67\x0b\x7f\x03\xda\x9e\x5f\xc6\x86\x2c\
+\xf1\x02\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\
+\x00\x00\x02\x43\
+\x89\
+\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
+\x00\x00\x10\x00\x00\x00\x10\x08\x06\x00\x00\x00\x1f\xf3\xff\x61\
+\x00\x00\x00\x04\x73\x42\x49\x54\x08\x08\x08\x08\x7c\x08\x64\x88\
+\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x01\xbb\x00\x00\x01\xbb\
+\x01\x3a\xec\xe3\xe2\x00\x00\x00\x19\x74\x45\x58\x74\x53\x6f\x66\
+\x74\x77\x61\x72\x65\x00\x77\x77\x77\x2e\x69\x6e\x6b\x73\x63\x61\
+\x70\x65\x2e\x6f\x72\x67\x9b\xee\x3c\x1a\x00\x00\x01\xc0\x49\x44\
+\x41\x54\x78\xda\x8d\x8f\xbd\x6b\x53\x51\x18\x87\x9f\x73\x72\xc1\
+\xb6\x41\x90\x82\x52\x2a\xc5\x39\xdd\x8c\x93\x75\xab\x83\x9b\xbb\
+\x53\xbb\xe4\x3f\x68\x07\x11\x8a\x25\xd4\x82\x43\x87\xa2\x20\x0e\
+\x15\x07\xe9\x6a\x16\xc5\x3d\xb5\x88\xa1\x1f\x42\xd3\x4d\x25\xe8\
+\xcd\x87\x83\x12\x92\x9b\x8f\x9b\x9c\xd7\xe6\xe0\xe1\x70\x89\x5f\
+\x3f\xf8\x71\xce\x19\x9e\xe7\x7d\x8f\x02\x2e\x00\xf3\xfc\x2b\xab\
+\xdc\xce\x5c\xcb\x2c\x65\x2f\x67\xa7\x0f\xab\x87\xf5\x72\xbb\xfc\
+\x40\x96\xe5\x49\x30\x82\x1b\x8d\xc6\x9e\x11\x41\x6b\x6d\xab\x94\
+\x4a\xf4\xd9\xc7\x1d\x76\x7f\xec\xb2\x78\x69\x91\xcd\xf9\x4d\xee\
+\x95\xef\xce\xa5\xbf\xa5\x1f\xab\x1d\x25\x1a\xc0\x08\x7f\xcd\xf6\
+\xe9\x36\xd5\x4e\x95\xfd\x4f\x05\x00\x3e\x57\x0b\x98\x41\x4d\x63\
+\x58\x0d\x00\x52\x29\xeb\xb1\xd3\xdc\x06\xda\x6f\x40\xed\x7b\x8d\
+\xe8\x4e\x84\xcb\x8b\x9b\x65\x00\xd4\x23\x35\x1b\x00\x16\x42\x04\
+\xf5\xeb\x0b\x16\x76\xe7\x59\x67\xae\xcc\x10\x3c\x57\x5c\x05\xde\
+\x2f\x09\xb9\x82\xe2\x40\x80\x8b\x84\xda\x4d\x76\xb0\x6b\xca\xdf\
+\x59\xc9\xac\x20\xe7\x35\x61\x0a\x9b\x0f\xc0\xb1\xc1\x30\xc5\x43\
+\xbf\x01\x78\x81\xff\x8a\x6d\x6e\x2e\x07\x1a\xb6\xbe\x6e\x91\x7e\
+\x99\x26\x0a\xf8\xc2\x04\x79\xb9\x25\x4f\x15\xb0\xd0\x6c\x36\xf7\
+\xbc\xc0\xd7\x6d\xe7\x4e\x97\x20\x08\x6e\x88\xc8\x5b\x7b\x07\x50\
+\x7e\x03\x57\x0f\x26\xce\x64\xbc\x00\xdc\xba\x6e\xb2\x83\xfe\x4f\
+\x40\x12\x76\x60\x42\x60\x8c\xb1\x6d\xb7\x23\x01\x62\x2f\x18\x03\
+\xc6\xe1\x4a\xa5\x42\x18\x86\x4c\x4c\x4e\xf2\xea\xf5\x9b\x77\xc0\
+\x11\xf8\x2c\x44\x51\x24\xdd\x6e\x57\xfa\xfd\xbe\xc4\x71\x2c\x83\
+\xc1\x40\x86\xc3\xa1\x18\x63\xec\xbb\x58\x2c\xda\xf7\xfd\x8d\x8d\
+\x13\x60\x4a\x44\x70\xc5\x0a\x3a\x9d\x3f\x0a\x5a\xad\x96\x94\x4a\
+\x25\x59\xcb\xe7\x47\xf0\xb4\x87\xbd\xe0\xfa\x99\xc0\xf4\x7a\xbd\
+\x11\x9c\x10\x8c\x52\xaf\x37\xcc\xda\xfa\xfa\xbe\x9f\x9c\xac\x02\
+\xce\x01\x59\x40\xf1\xfb\xc4\xc0\x91\x88\xc4\x30\x9e\x9f\xaf\xc9\
+\x06\x51\x54\x9d\xd3\x94\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\
+\x60\x82\
+\x00\x00\x02\x9a\
+\x89\
+\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
+\x00\x00\x10\x00\x00\x00\x10\x08\x06\x00\x00\x00\x1f\xf3\xff\x61\
+\x00\x00\x00\x04\x73\x42\x49\x54\x08\x08\x08\x08\x7c\x08\x64\x88\
+\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x01\xbb\x00\x00\x01\xbb\
+\x01\x3a\xec\xe3\xe2\x00\x00\x00\x19\x74\x45\x58\x74\x53\x6f\x66\
+\x74\x77\x61\x72\x65\x00\x77\x77\x77\x2e\x69\x6e\x6b\x73\x63\x61\
+\x70\x65\x2e\x6f\x72\x67\x9b\xee\x3c\x1a\x00\x00\x02\x17\x49\x44\
+\x41\x54\x38\x8d\xa5\x93\x3d\x68\x13\x71\x18\xc6\x9f\x37\xcd\x11\
+\x9b\x8f\x5e\x92\x4b\x52\xf3\x71\xf9\x20\xc1\xd2\x52\x3b\x1c\x15\
+\xc1\x82\xb5\x08\x35\x89\x10\x35\x38\x0b\x4e\x82\x60\x47\x89\x5b\
+\xea\xd4\x41\x08\x14\x1d\x1c\xd2\xbd\x08\xa5\x5c\x16\x17\x1d\x0c\
+\x38\x88\x20\x68\x87\x22\xd8\x56\x93\xab\x62\xed\xa9\x6d\x4c\xc9\
+\xe5\x7a\x7f\xa7\x0b\x67\xda\x45\xfa\x8c\xff\xf7\x7d\x7e\x3c\x2f\
+\x0f\x7f\x62\x8c\xe1\x24\xb2\x9d\xc8\xdd\x0f\x58\x21\x92\xde\xdc\
+\xbe\xf5\x7d\x95\xe3\x72\xfd\x8b\xab\x1c\x97\xfb\xf0\xe0\x7e\x73\
+\x85\x48\x3a\x16\xb0\x4c\x24\xf9\x27\xc7\x5e\x9d\x19\x1d\x0b\x46\
+\x8b\x59\xf9\x19\x51\xd6\x32\xcb\x85\xb3\xd3\x72\x3c\x18\x8c\x9e\
+\xbe\x32\x5d\x5f\xb6\x40\x7a\x00\x0d\x58\x4a\x4e\x9e\x77\x1d\x34\
+\xb7\x11\x4b\x8e\xda\xc3\xf9\x4b\xb5\x2a\x51\xbe\x42\x74\xcd\x79\
+\xf9\x42\x4d\x1c\x99\xb0\xb7\xb7\x1a\xc8\xcc\xe6\x9d\x1a\xb0\x64\
+\xfa\xec\x16\x40\x69\xad\xfe\xb2\x96\x1c\x3f\x67\x07\xb3\x21\x10\
+\x4e\xd9\x37\x2e\xb6\xe4\x5d\xc3\xa0\xd9\x44\xc6\xa6\x36\x14\x0c\
+\x38\x1d\xf8\xf6\xe2\xbd\xae\x01\x25\xd3\x47\xd6\x16\x9e\x12\x65\
+\x87\x47\xa2\x72\x4c\xcc\x70\x86\xc6\x60\xf3\xba\x71\xc0\x0c\x38\
+\x3b\x06\x1c\x89\x08\xb6\xde\xbe\xee\x2a\xef\x3e\x16\xee\x30\xf6\
+\xfc\x58\x00\x00\x2c\x12\x65\x23\x99\x61\x39\x12\x8c\x72\x87\x1a\
+\x81\x1c\x0e\xe8\xac\x83\xaf\xca\xa7\xee\xce\x97\x5f\x85\x39\x8b\
+\xf9\x9f\x13\x4c\x75\x00\x68\x5a\x17\xfa\xfa\x3a\xf4\x9f\x6d\x10\
+\x80\x01\x9f\x13\xcc\x73\x0a\x9d\xfe\xe5\xfe\x04\x0b\x44\x59\x31\
+\x21\xc8\xe3\xfb\x1d\x0e\x6a\x0b\x6d\xbf\x1b\x04\x60\x50\x6d\x01\
+\x7e\x37\xd6\x3c\x83\xdd\xc6\xe7\x9d\x42\xc9\x92\xa2\xd7\xc2\x3c\
+\x51\x4e\x4c\x45\xe4\xa9\x96\xce\x09\x6a\x0b\x2e\xc1\x8b\x27\x3c\
+\xcf\x16\x79\x2f\x73\x05\x7c\x10\xd4\x16\xa6\xfe\x1c\x72\x62\x3a\
+\x2e\x2f\xf0\xfc\xd5\x23\x00\x16\x0f\x3d\x9e\x19\xf2\x72\xa1\xdd\
+\xdf\x70\x07\xfc\xa8\x78\x79\x43\xd8\x54\x8a\xbe\xcd\xe6\xcd\x0a\
+\xcf\x1b\xee\xa0\x80\xd0\x0f\x15\x33\x9e\x21\x8e\x17\xc5\x47\xbd\
+\xd8\x8c\x31\x30\xc6\x50\x06\xa4\x6a\x22\xb6\xa7\x48\x67\x59\x39\
+\x9d\xd2\xe7\x80\xeb\xe6\xec\x2e\x50\x9c\x4f\xa7\x74\x45\x9a\x60\
+\xd5\x44\x6c\xaf\x0c\x48\xe6\xac\x07\x30\x21\x0f\x33\xd1\x8d\x7b\
+\xc0\x0d\xeb\xbb\x09\xa9\xe7\x73\xdb\x56\x33\x63\xec\x68\x8d\xff\
+\xab\x13\xff\xc6\xbf\x7b\x12\xeb\x18\x4c\xd6\x48\xe1\x00\x00\x00\
+\x00\x49\x45\x4e\x44\xae\x42\x60\x82\
+\x00\x00\x02\xd6\
+\x89\
+\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
+\x00\x00\x10\x00\x00\x00\x10\x08\x06\x00\x00\x00\x1f\xf3\xff\x61\
+\x00\x00\x00\x01\x73\x52\x47\x42\x00\xae\xce\x1c\xe9\x00\x00\x00\
+\x06\x62\x4b\x47\x44\x00\xff\x00\xff\x00\xff\xa0\xbd\xa7\x93\x00\
+\x00\x00\x09\x70\x48\x59\x73\x00\x00\x06\xec\x00\x00\x06\xec\x01\
+\x1e\x75\x38\x35\x00\x00\x00\x07\x74\x49\x4d\x45\x07\xd8\x0b\x11\
+\x17\x19\x36\xe0\x1f\xbc\x7d\x00\x00\x02\x56\x49\x44\x41\x54\x78\
+\xda\x8d\x91\x5d\x48\x53\x71\x18\x87\x9f\x73\x66\x52\xe1\x32\x95\
+\x30\xb2\xd5\x12\xc2\x30\xa8\x30\xbd\x31\x2f\xba\xd1\x8b\x90\xc0\
+\xa0\x4f\xa2\x20\xb2\x4c\xab\x8b\x8c\x60\x41\x12\x18\x41\x82\x91\
+\x60\x81\x1f\x45\x17\xd2\xf7\x45\x17\x61\xa4\xa1\x61\x28\xa1\xa8\
+\x91\x59\x4a\xea\x14\x5d\x73\xb6\x4c\xcf\xce\x74\xba\xb3\xfd\x3b\
+\x1c\xd8\x58\x5b\x50\x0f\xbc\xbc\xef\xb9\x78\x9f\xdf\xcb\xff\x48\
+\x60\xb0\x16\xd8\xce\x7f\x50\xb0\x5b\x5e\x79\x7b\x63\x41\x9d\xe6\
+\x9a\x1b\x23\x21\xe1\x44\x48\x90\x2f\x84\x68\xe1\x1f\x04\xfc\x8b\
+\x78\x7a\x8b\x78\x79\xdf\x4e\x46\x7b\x80\x05\x97\xab\x33\x0e\x30\
+\xd0\x05\xfc\x70\xbb\x91\x65\xd9\x28\x49\x92\x90\xf5\xd2\x07\x63\
+\x86\x20\xcb\x5f\x4b\x79\xdd\xfa\x85\xeb\xad\x32\x07\x2c\x53\x5a\
+\x96\x47\x24\xc9\x44\x60\x32\x99\xc2\x02\x53\xa8\x9b\x4c\xc6\xec\
+\xb7\x57\xd1\xdb\xd3\xc5\x8d\xa6\x78\x76\x6e\x76\x73\xfa\xac\xe4\
+\x6a\xc9\x92\xcf\xc5\x41\x18\x23\xd1\x48\xd7\x4b\x9f\xc3\xdd\x37\
+\xf5\x08\xc7\xb7\x37\xd8\xea\xe3\x59\x6f\x9e\xe1\x56\xe9\x6a\x2a\
+\xea\x97\x6a\x9e\xb7\x69\xd3\x91\x17\xfc\x99\x1e\x4a\x9e\x7d\x8f\
+\x32\xfe\x84\x0b\xd5\x3e\x56\x48\x1e\x6a\x2e\x06\x59\x48\xad\x40\
+\x5f\xf6\x00\x93\x61\x81\x14\x4a\x8c\x90\x04\xd4\x21\xb4\xe9\xc7\
+\x5c\xb9\xeb\x61\x5e\x51\xa9\x2e\x51\xd0\x52\xcb\x50\xe5\x1d\x00\
+\x0e\x60\x31\xe6\x82\x90\x24\xe0\x73\x12\x9c\x7e\x88\xed\xce\x18\
+\x9f\x87\xdd\xdc\x3c\x35\x87\x79\xd3\x41\x66\x02\x79\x58\xad\x56\
+\x80\x25\x63\x27\xea\x0d\x8c\x12\x9a\x82\xd0\x97\xab\x1a\x07\x79\
+\xd7\xed\xc4\x76\x74\x8e\x2d\xdb\x72\x19\xf5\x15\x92\x96\x96\x86\
+\xc5\x62\x01\x20\x46\x60\xfc\x2e\xe1\x27\xe0\xa8\xe3\xc1\xb3\x7e\
+\x9e\x36\x4f\x50\x52\xe8\x21\x37\x27\x9d\xfe\x5f\x47\x48\x4e\x4e\
+\x21\x33\x33\x13\x01\x61\xe2\xa2\x05\xf3\x93\x6d\xb4\x35\xb7\x53\
+\xdb\x34\x49\x51\xde\x22\x87\x0a\x12\x79\x31\xb8\x9f\x29\xe7\x00\
+\xe6\x35\x49\xf4\xf5\xf5\xb1\xca\x9c\x08\xa0\xfd\x55\xa0\x7a\x25\
+\xbc\x41\x2b\x7b\x77\x8d\x51\x7e\x58\xe6\x95\xfd\x38\xc3\x23\xdf\
+\xa9\xac\xac\xd4\x2f\x48\x46\x55\x55\x2e\x95\x97\xbf\x05\xba\x62\
+\x04\x3f\x67\x1c\xcc\x3a\x3f\x90\xbe\xce\x49\x46\x51\x36\xe3\xf1\
+\xfb\xc8\xd9\x93\x8d\x39\x65\xc8\x58\xf6\x7a\xbd\xd8\xae\xda\x06\
+\x1a\x1b\x1a\x4e\x02\x3e\x22\xc8\x17\x3a\xf7\x6a\x6b\xc4\xb5\xcb\
+\xc7\x84\x63\xa4\x53\xf8\xfd\xcb\x22\x18\x0c\xea\xdd\x2f\x3a\x3a\
+\x3a\x84\xa2\x28\xa2\xec\x7c\xd9\x27\x60\x2b\x21\xa2\x05\x13\xf6\
+\x51\x11\xcd\xb2\x16\x10\xdd\x1f\x07\x44\xf1\x99\xe2\x16\x60\x03\
+\x51\x48\x60\x90\x02\x64\x85\xbf\x63\xd1\x80\x4e\x60\x89\x28\x7e\
+\x03\x99\xc3\x0a\xf4\x03\x8f\xf6\xf6\x00\x00\x00\x00\x49\x45\x4e\
+\x44\xae\x42\x60\x82\
+\x00\x00\x02\x33\
+\x89\
+\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
+\x00\x00\x10\x00\x00\x00\x10\x08\x06\x00\x00\x00\x1f\xf3\xff\x61\
+\x00\x00\x00\x04\x73\x42\x49\x54\x08\x08\x08\x08\x7c\x08\x64\x88\
+\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x01\xbb\x00\x00\x01\xbb\
+\x01\x3a\xec\xe3\xe2\x00\x00\x00\x19\x74\x45\x58\x74\x53\x6f\x66\
+\x74\x77\x61\x72\x65\x00\x77\x77\x77\x2e\x69\x6e\x6b\x73\x63\x61\
+\x70\x65\x2e\x6f\x72\x67\x9b\xee\x3c\x1a\x00\x00\x01\xb0\x49\x44\
+\x41\x54\x78\xda\xa5\x93\x3f\x48\xc3\x40\x18\xc5\x5f\xa2\xd8\x74\
+\xab\xda\xc1\x3a\xd6\x55\xc4\xcd\x41\x10\xff\xd0\xad\x45\xa1\xe2\
+\x24\xae\x8e\xea\xe0\x20\xc5\x4d\xb0\xe8\xac\xb8\xbb\xa8\xb8\xd9\
+\xc1\x41\x67\x37\x05\xc7\x42\xc1\x0e\xd6\x52\x41\xcd\x35\x7f\x9a\
+\xb6\x97\x78\x5f\x22\xe1\x42\x1d\x0a\x7d\xb9\x7c\x97\xc0\xbd\xdf\
+\x3d\xbe\x5c\x14\xcf\xf3\x30\x88\x86\xa9\xe4\xb2\xd9\xef\x56\xcb\
+\x49\xec\xec\xed\x43\x96\xa2\x52\x55\xa1\xaa\x0a\x14\x05\x50\x10\
+\xdc\xa7\x27\x45\x68\x5a\xec\xe7\xae\x54\x1a\xf5\x01\x96\x69\x25\
+\x26\x52\x13\x58\x58\x5c\x82\x27\x03\x80\xc0\x28\x0a\x41\xc4\xf0\
+\xe7\xdb\x9b\x2b\x54\x2a\x95\x44\x98\xc0\x75\x5d\x68\x31\x0d\xda\
+\xc8\x10\x2e\x1f\x5e\xa3\x29\xfc\x42\x23\x48\xb1\x95\x99\x01\xe7\
+\xdc\xf7\x84\x00\x2e\x5e\xba\xdd\xae\xa0\x03\x9b\x2b\xd3\xb4\x3e\
+\x4c\x42\x3d\x72\xbd\xbf\x59\x3c\x98\x4e\x87\xd6\xfa\x9e\x48\x02\
+\xa2\x36\xed\x36\x99\x43\x79\x01\x81\x06\x5c\x02\x04\x90\xde\x04\
+\x2e\xe7\x3e\xd5\x10\x80\xeb\xfb\x27\xc8\x0a\xbf\x12\xa5\x10\x57\
+\x3e\x33\x47\x6b\xc9\xd3\x9b\x80\x19\x36\x32\xf3\xb3\xb2\x1b\x9e\
+\x64\x26\x56\xd3\x74\xfe\x49\xe0\x72\x70\x41\x3d\xdc\xdd\x46\x9f\
+\x22\x8f\xd4\x44\x1e\x34\xb1\x7f\x05\x9e\x68\x0f\x3a\x1d\x90\x8e\
+\x8a\xc7\x88\xc7\xe3\x61\x7c\x3a\x03\x24\x8a\xbd\x91\x5f\xf7\xe7\
+\xa9\x74\x3a\xda\x83\x8e\xd8\xdd\x69\xb7\x41\x2a\x97\xcb\xb8\x38\
+\x3b\x87\x65\x5b\x38\x28\x14\x20\x2b\x35\x39\x89\xda\x47\x8d\x3e\
+\x21\x79\x24\x80\xd8\xdd\x71\x1c\x90\x18\x63\x30\x4d\x13\x86\x61\
+\x40\xd7\x75\xc8\xf2\x84\xd1\x15\xd1\x93\xc9\x24\xde\xaa\xd5\x48\
+\x13\xbf\x18\xd3\xc7\xe8\x34\x32\x9d\xc1\xb6\x6d\x4a\xd4\x03\x20\
+\x30\x6d\x66\x5b\x16\xb8\x9c\x40\xe1\x7c\x99\x35\x9b\x8f\xba\xce\
+\xc6\x1b\x9f\x0d\xe4\xd6\x56\x41\xaa\xd7\xeb\x90\xf5\x5e\xab\x51\
+\x0e\x3c\xbf\xbc\x40\x1d\x52\x7f\x20\x34\xf0\xef\xfc\x0b\xfb\xd2\
+\x1e\xf6\x17\x50\x4f\x5c\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\
+\x60\x82\
\x00\x00\x04\xa7\
\x89\
\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
@@ -80495,148 +80363,6 @@
\x81\xc0\x25\xf0\x5f\x61\x32\x99\xb0\xf7\x20\x1e\x8f\xc7\x08\x20\
\x7f\x01\x05\xd6\xf6\x6e\x13\x0f\xa3\xe1\x00\x00\x00\x00\x49\x45\
\x4e\x44\xae\x42\x60\x82\
-\x00\x00\x02\x74\
-\x89\
-\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
-\x00\x00\x10\x00\x00\x00\x10\x08\x06\x00\x00\x00\x1f\xf3\xff\x61\
-\x00\x00\x00\x04\x73\x42\x49\x54\x08\x08\x08\x08\x7c\x08\x64\x88\
-\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x01\xbb\x00\x00\x01\xbb\
-\x01\x3a\xec\xe3\xe2\x00\x00\x00\x19\x74\x45\x58\x74\x53\x6f\x66\
-\x74\x77\x61\x72\x65\x00\x77\x77\x77\x2e\x69\x6e\x6b\x73\x63\x61\
-\x70\x65\x2e\x6f\x72\x67\x9b\xee\x3c\x1a\x00\x00\x01\xf1\x49\x44\
-\x41\x54\x38\x8d\x95\x93\x3f\x6f\xd3\x50\x14\xc5\x7f\xef\xc5\x55\
-\x90\x53\x67\xcc\x84\xba\x84\xa1\x09\xa8\x4b\x93\x2c\xcd\x58\xa9\
-\x4b\x16\xda\xaf\x90\xa5\x9f\x03\x24\xfe\x08\x09\xb6\x6e\xf9\x06\
-\x0c\xc0\x02\x6b\x55\x84\xb2\xb5\x69\x15\xb5\x12\x55\x28\x63\x14\
-\xd1\x01\x63\x3b\xf6\xf3\xbb\x2c\xb5\xb1\x69\x19\xb8\xd2\x1d\x9e\
-\xf4\xce\xb9\xe7\x9c\xab\xab\x44\x04\x00\xa5\xd4\x03\x60\x83\xff\
-\xab\x89\x53\x78\x6c\xcc\xe7\xf3\xb7\xbf\x82\x80\xf1\x78\x4c\xdd\
-\xf3\xd8\xec\x74\x58\x59\x59\x41\x29\x85\x52\x2a\x1b\x04\x80\xd6\
-\x1a\x6f\x75\x75\x4f\x17\xe9\xac\xc0\xe7\xa3\x23\x3a\x9b\x9b\xac\
-\xad\xad\x31\x9d\x4e\xc9\x14\x66\x60\x05\x79\x03\x14\x15\x50\xa9\
-\x68\xa2\x28\xa2\xd1\x68\x50\xad\x56\x09\xc3\x90\xef\x57\x57\x34\
-\x9b\xcd\x3f\x2a\x32\x92\x4c\xd1\x70\x38\xfc\xe8\x38\xce\x8e\xeb\
-\xba\xb8\xae\x4b\xbd\x5e\xa7\xdb\xed\xb2\xb5\xb5\x85\x31\x86\xd3\
-\xb3\x33\x5a\xeb\xeb\x38\x8e\x93\x83\x01\x94\xd6\xdc\xab\x56\xf7\
-\x1c\x60\xe7\xe0\xe0\xa0\x94\x8c\xb5\x16\x6b\x2d\x95\x4a\x85\x87\
-\xed\x36\x69\x9a\xa2\xb5\xbe\x33\x8b\x92\x85\xa2\x57\x6e\x3e\x2b\
-\xa5\xd0\x5a\xa3\xb5\x2e\x01\xb3\x72\x80\x4f\xfb\xfb\xfb\x25\x0b\
-\xbd\x5e\x8f\x7e\xbf\x8f\x15\xe1\xfc\xfc\x9c\x56\xab\x75\x6b\x72\
-\x5e\x22\x92\x25\xbd\xfb\xd3\xf7\x65\x34\x1a\x89\xef\xfb\x62\x8c\
-\x91\xe3\xe3\x63\x99\x4e\xa7\x92\x24\x89\x18\x63\xc4\x18\x23\x69\
-\x9a\xe6\x0d\xec\x96\x2c\x28\xc0\x75\x5d\x16\x8b\x05\x71\x1c\x13\
-\x04\x01\xed\x76\xfb\x4e\xef\x45\x0b\x45\xf3\x6c\x6f\x6f\x73\x78\
-\x78\x88\xe7\x79\xf4\xfb\xfd\x5b\xe1\x65\x01\x27\x89\x11\xc0\x96\
-\x15\x28\x45\xad\x56\x63\x30\x18\xe4\xa0\x22\x38\x8a\x22\x66\xb3\
-\x19\x35\x6f\x95\x77\xef\x3f\x8c\x81\x93\x52\x06\x41\x10\x48\x14\
-\x45\x12\xc7\x71\xee\x3b\x4d\x53\xb1\xd6\x4a\x92\x24\x32\x99\x4c\
-\x24\x8e\x97\xf2\xf4\xe5\x8b\x0b\xe0\x11\xa0\xca\x04\x61\xf8\x4f\
-\x02\xdf\xf7\xe5\xeb\xe5\xa5\x3c\x79\xfe\xec\x02\xe8\x02\x5a\x44\
-\x4a\x5b\x78\x1c\x84\xa1\x5d\x2e\x97\x92\x24\x49\x89\x40\x44\xe4\
-\xc7\xf5\xb5\x7d\xf5\xfa\xcd\x97\x9b\xc9\x3a\xc3\xa9\xc2\x39\xdf\
-\xbf\x61\xfe\x6b\xd1\x79\x59\xe0\x04\xf8\x26\x85\x0b\xfb\x0d\xc2\
-\xe3\x2f\xb3\xa8\x69\x9b\xe3\x00\x00\x00\x00\x49\x45\x4e\x44\xae\
-\x42\x60\x82\
-\x00\x00\x03\x2f\
-\x89\
-\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
-\x00\x00\x10\x00\x00\x00\x10\x08\x06\x00\x00\x00\x1f\xf3\xff\x61\
-\x00\x00\x00\x01\x73\x52\x47\x42\x00\xae\xce\x1c\xe9\x00\x00\x00\
-\x06\x62\x4b\x47\x44\x00\xff\x00\xff\x00\xff\xa0\xbd\xa7\x93\x00\
-\x00\x00\x09\x70\x48\x59\x73\x00\x00\x03\x76\x00\x00\x03\x76\x01\
-\x7d\xd5\x82\xcc\x00\x00\x00\x07\x74\x49\x4d\x45\x07\xda\x03\x0c\
-\x0f\x1f\x23\x16\x66\x68\x50\x00\x00\x02\xaf\x49\x44\x41\x54\x38\
-\xcb\x95\x92\x4d\x6b\x24\x55\x14\x86\x9f\x5b\x1f\x5d\xd5\x5d\xdd\
-\xda\x5d\x55\x19\xa3\x61\x20\xb8\x10\x61\x42\x76\xc9\x2a\x38\x2e\
-\x8c\x3b\x37\xc1\xcd\xfc\x07\x0d\x08\x6e\x02\xd9\x38\x5b\x05\x21\
-\xce\x1f\x88\xff\x20\x30\xd9\x89\x04\x09\x04\x87\x2c\x24\x04\xc4\
-\x91\x86\x18\x8c\x4c\xba\x53\x49\x77\xd7\x47\xdf\xaa\xba\x55\xd7\
-\x45\xe8\xc4\x01\x5d\xf8\xc2\xe1\x2c\x0e\xe7\x39\x87\x97\x57\xec\
-\xef\xef\x3f\x09\x82\xe0\xbb\x76\xbb\x1d\x00\x18\x86\x81\x10\x02\
-\x21\x04\x33\x69\xad\xef\xba\xd6\x9a\xba\xae\x91\x52\x46\x83\xc1\
-\xe0\x73\x71\x74\x74\x74\xb5\xb7\xb7\x17\x44\x51\x44\xb3\xd9\xc4\
-\x71\x1c\x1a\x8d\x06\xb6\x6d\x63\x9a\x26\x00\x75\x5d\xa3\x94\xa2\
-\x2c\x4b\xf2\x3c\x47\x4a\x49\xaf\xd7\x63\x63\x63\x23\xb2\x3c\xcf\
-\x0b\xfa\xfd\x3e\x4f\x1f\x7d\x4a\x10\x86\x77\x57\x51\x35\x14\x0a\
-\x8a\x02\x2a\x05\xe5\xac\x2a\xa2\xf8\x9a\xa7\xa3\x9f\xf1\x3c\x2f\
-\xb0\x66\x17\xe6\x12\x4d\xd0\x2d\xc0\x2b\xc0\x4b\x61\x98\x40\x95\
-\x40\x91\xc1\x34\x87\x44\x42\x52\xc2\xa4\xc2\x18\x8c\xa9\x1e\x56\
-\x00\x58\x00\x55\x55\x21\x8c\x31\xb8\x0a\x3e\x19\x42\x3b\x85\xb3\
-\x09\xfc\x70\x09\x64\xa0\x25\xe4\x39\x50\x83\xaa\x10\xba\xa0\xaa\
-\xe6\x6f\x01\x33\x53\x8a\xf0\x15\x97\x4d\x8d\xb8\x98\x32\xf7\xf0\
-\x1d\x44\x47\x82\xbe\x02\x62\xb0\x26\x24\xcd\x84\xeb\x3c\x01\xa1\
-\x90\x6e\x03\xad\xdf\xba\x07\xb8\xae\xcb\xf7\xc3\x33\xbc\xc4\x21\
-\xf9\x65\x82\xa1\x5f\xa2\x8b\x29\xe9\x28\xe6\xe2\x26\x25\x8a\x53\
-\xd2\x24\xc6\x50\x05\x0d\x03\x92\x7c\x82\xbf\x24\xee\x01\x37\x37\
-\x37\xfc\x78\xf1\x2b\xf3\x0f\x7c\x16\x17\x4c\xe6\x7b\x9a\xdf\xce\
-\x46\xfc\xf1\x67\xca\x24\x9e\x92\x26\x19\x85\xaa\x10\xc2\xc0\xb2\
-\x4d\xf2\x42\xe0\x66\x19\x5a\xeb\x5b\x0f\xca\xb2\xe4\xf7\xb3\x6b\
-\x5e\x8d\xc6\xbc\xbb\x50\x51\xeb\x8a\x69\x59\xf3\xf2\xd2\x20\x95\
-\x0e\xa6\xd5\xa5\x50\x05\x9d\x4e\x07\xcb\xb2\x18\x4e\x86\x84\x65\
-\x79\x6f\xa2\x52\x8a\xce\xc2\x7b\xb8\x6f\x08\x22\xab\x46\xd6\x39\
-\x63\x53\xe1\xce\x09\x2a\xd9\xc4\x69\xb5\xa8\xeb\x1a\xd3\x34\x31\
-\x4d\x93\x6e\x6b\x0e\xa5\xd4\x2d\x20\x4d\xd3\x68\x79\x79\x39\xe8\
-\xf7\xfb\xb4\x5a\x2d\xae\x06\x4d\x12\xd7\xc5\x7f\xd3\xe5\x83\x15\
-\x07\xc3\x30\x28\x8a\xe2\x2e\x40\x52\x4a\xb2\x4c\xb3\xb8\xb8\x48\
-\x96\x65\x91\xd8\xdd\xdd\x7d\xb2\xb4\xb4\xf4\xac\xd7\xeb\xf9\xfc\
-\x0f\xc5\x71\x7c\x7d\x7a\x7a\xfa\x99\xf8\x8f\xb9\xb1\xb3\xb3\xf3\
-\x4d\x18\x86\x5f\x28\xa5\x38\x3f\x3f\xff\x76\x7b\x7b\xfb\xcb\xdb\
-\x20\xbc\xae\xd7\x00\x5b\x5b\x5b\xef\xaf\xaf\xaf\x7f\x6d\x18\xc6\
-\x63\xd7\x75\x3b\xe3\xf1\x18\x29\x25\x8e\xe3\x60\xdb\x76\x62\x9a\
-\xe6\x4f\x27\x27\x27\x5f\x6d\x6e\x6e\xbe\x98\xed\x58\xff\x04\x84\
-\x61\xf8\x61\xa7\xd3\xf9\xd8\xf7\xfd\x86\xd6\x9a\x6e\xb7\x8b\x10\
-\x02\xdb\xb6\xd1\x5a\xb7\xa3\x28\xfa\x48\x29\xf5\x1c\x78\xf1\xaf\
-\x1f\x00\xc2\xf7\xfd\x07\x6b\x6b\x6b\x8f\x57\x56\x56\xde\x5e\x5d\
-\x5d\xed\x3a\x8e\x23\x8e\x8f\x8f\x47\x87\x87\x87\x7f\x1d\x1c\x1c\
-\x1c\x8c\x46\xa3\x21\xa0\x67\x0b\x7f\x03\xda\x9e\x5f\xc6\x86\x2c\
-\xf1\x02\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\
-\x00\x00\x02\xd0\
-\x89\
-\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
-\x00\x00\x10\x00\x00\x00\x10\x08\x06\x00\x00\x00\x1f\xf3\xff\x61\
-\x00\x00\x00\x06\x62\x4b\x47\x44\x00\xff\x00\xff\x00\xff\xa0\xbd\
-\xa7\x93\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x1b\xaf\x00\x00\
-\x1b\xaf\x01\x5e\x1a\x91\x1c\x00\x00\x00\x07\x74\x49\x4d\x45\x07\
-\xd7\x09\x1c\x09\x10\x1f\x1c\x2b\x28\x4a\x00\x00\x02\x5d\x49\x44\
-\x41\x54\x78\xda\xc5\x52\x4b\x6b\x13\x51\x14\xfe\x32\x77\xf2\x6a\
-\x3a\x4d\x22\x48\x93\xd8\xa6\x69\xb4\x26\xad\xb6\x41\x5d\x88\x20\
-\xd8\x2e\x7c\x81\x15\x1f\x08\xe2\x3f\x10\xac\xbf\xc3\xfe\x01\xe9\
-\x5a\xb0\x5d\xb9\x74\xa3\x2e\x14\x41\x62\x10\x0a\x42\x63\x93\x91\
-\xd0\xe6\xd1\x36\xe9\x98\x64\xda\xbc\x27\xcd\xf5\xdc\xc1\x94\x6c\
-\x5c\x8a\x1f\x7c\xdc\x99\x7b\xee\xf9\xce\x77\xce\xbd\xf8\xef\xb0\
-\xf4\x3f\x22\x91\x08\x5b\x5d\x7d\x7d\x75\x74\x74\x74\xc1\x6e\x77\
-\x9c\x95\x24\xe9\x24\xc0\x87\x7a\xbd\x1e\x8e\x8e\x8e\x9a\x86\x61\
-\xec\xb7\xdb\xad\x74\xa5\x52\xf9\xb8\xb4\xf4\xfc\x73\x3c\xfe\xb5\
-\x8b\x3e\x96\x97\x5f\xf8\x93\x3f\x36\xe2\xa5\x52\x91\xb7\x5a\x2d\
-\xde\xe9\x74\xcc\xb5\xd1\x68\xf0\x5a\xad\xc6\x0f\x0e\x74\x5e\xad\
-\x96\xb9\xa6\x95\xf8\xee\x6e\x81\xab\x6a\xea\xdb\xca\xca\xcb\x31\
-\x10\x24\x10\x26\x27\x43\x4f\x95\x61\xe5\xb2\xd5\x6a\x1d\x30\xc7\
-\xc1\xb9\x60\xef\xd8\xac\xc5\x62\x81\x2c\xcb\x50\x14\xe5\xd2\xf8\
-\xf8\xf8\xb3\xbe\x80\xd5\xed\xf1\xdc\x10\x41\x01\xb2\x2c\x12\x4d\
-\x76\xbb\x5d\x61\xdf\xdc\x1b\x80\x29\xe4\xf1\xb8\xaf\x8b\x5c\x69\
-\x7e\xfe\x5a\xf0\x84\xd7\x7b\x71\x20\xfe\x27\x89\x83\xe6\x00\xc2\
-\xb1\xe0\x00\x48\xc0\x13\x5b\x5c\xbc\x73\x5a\xbe\x77\xff\xee\x03\
-\x2b\x41\x1c\x38\x3c\xac\x41\xd7\x0f\xcc\xca\xcd\x66\x13\xe5\x72\
-\x19\x36\x9b\x0d\x5e\xaf\x07\x8c\x31\xaa\x2c\x51\x0b\x0c\x76\xbb\
-\x8d\xfe\x65\x76\xeb\xf6\xcd\x87\x72\xa9\xf8\xeb\x82\xa6\x95\x21\
-\x48\x3a\xa6\xbd\xf5\xf5\x75\x6c\xa6\x36\x11\xf0\x07\x30\x11\x9a\
-\x80\xd1\x31\x10\x08\x04\x30\x32\x32\x22\xda\x31\x0b\xf4\x68\x36\
-\xfb\x25\x6d\x56\xde\xde\xde\x66\xf5\x7a\xdd\x4c\xa6\xe9\xa3\x50\
-\x28\x40\xfd\xa9\x62\x7a\x7a\x1a\xb9\xec\x0e\xde\xbf\xfb\x00\xbf\
-\xdf\x07\xba\x3e\xcc\xcc\xcc\xf4\xdb\x32\x45\xf2\xf9\x02\x98\xcf\
-\xe7\x7b\x44\xc1\x73\x99\x4c\x06\x82\xe9\x74\x1a\x7a\x55\x47\xa5\
-\xda\xc6\xe3\x27\x4b\x08\x06\xc7\xb0\xb6\xf6\x0a\x21\x72\x42\xce\
-\x44\xef\x94\x98\x37\x85\x52\xa9\xd4\x86\xec\x74\x3a\xf9\xdc\xdc\
-\x1c\xfa\x57\xa8\xaa\x2a\x12\x89\x04\xb4\x4a\x03\x6f\x3f\x7d\x41\
-\xad\xae\xc3\xe9\x52\x4c\xeb\xb1\x58\xcc\x5c\xdd\x6e\x37\xe8\x9d\
-\xa0\xdd\x6e\x83\x85\xc3\xe1\x00\x6d\x4c\x91\x80\xc2\x08\x22\xa8\
-\xeb\x3a\x72\xb9\x2d\xe4\xab\x74\xa8\x75\x88\x85\x2b\xb3\x18\x56\
-\x86\xe1\x70\x38\x84\x80\x48\x36\x34\x4d\xdb\xca\x66\xb3\x6f\x2c\
-\x00\x04\x5d\x64\x29\x18\x8d\x46\xcf\xd3\x53\x9e\x72\xb9\x5c\xa7\
-\xf6\x8a\x7b\x3e\x99\xc9\x67\x86\x5c\x43\x4d\x12\xcd\x30\x89\x55\
-\x48\x78\x87\x12\xd5\x64\x32\xf9\x9d\xaa\xe7\x00\xd4\x2d\xf8\x3b\
-\x24\xa2\x8d\xd8\x23\x1a\x44\x8e\x7f\x81\xdf\xa3\x70\x33\x35\x18\
-\x40\x99\x79\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\
\x00\x00\x02\xe1\
\x89\
\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
@@ -80686,44 +80412,174 @@
\xac\xfd\xa5\x85\x3a\x8d\x10\x17\x0b\x47\xf9\x03\x3a\xca\x9b\x53\
\x60\x80\xcc\x4d\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\
\
-\x00\x00\x02\x43\
+\x00\x00\x03\x70\
\x89\
\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
-\x00\x00\x10\x00\x00\x00\x10\x08\x06\x00\x00\x00\x1f\xf3\xff\x61\
+\x00\x00\x16\x00\x00\x00\x16\x08\x06\x00\x00\x00\xc4\xb4\x6c\x3b\
\x00\x00\x00\x04\x73\x42\x49\x54\x08\x08\x08\x08\x7c\x08\x64\x88\
-\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x01\xbb\x00\x00\x01\xbb\
-\x01\x3a\xec\xe3\xe2\x00\x00\x00\x19\x74\x45\x58\x74\x53\x6f\x66\
+\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x03\x76\x00\x00\x03\x76\
+\x01\x7d\xd5\x82\xcc\x00\x00\x00\x19\x74\x45\x58\x74\x53\x6f\x66\
\x74\x77\x61\x72\x65\x00\x77\x77\x77\x2e\x69\x6e\x6b\x73\x63\x61\
-\x70\x65\x2e\x6f\x72\x67\x9b\xee\x3c\x1a\x00\x00\x01\xc0\x49\x44\
-\x41\x54\x78\xda\x8d\x8f\xbd\x6b\x53\x51\x18\x87\x9f\x73\x72\xc1\
-\xb6\x41\x90\x82\x52\x2a\xc5\x39\xdd\x8c\x93\x75\xab\x83\x9b\xbb\
-\x53\xbb\xe4\x3f\x68\x07\x11\x8a\x25\xd4\x82\x43\x87\xa2\x20\x0e\
-\x15\x07\xe9\x6a\x16\xc5\x3d\xb5\x88\xa1\x1f\x42\xd3\x4d\x25\xe8\
-\xcd\x87\x83\x12\x92\x9b\x8f\x9b\x9c\xd7\xe6\xe0\xe1\x70\x89\x5f\
-\x3f\xf8\x71\xce\x19\x9e\xe7\x7d\x8f\x02\x2e\x00\xf3\xfc\x2b\xab\
-\xdc\xce\x5c\xcb\x2c\x65\x2f\x67\xa7\x0f\xab\x87\xf5\x72\xbb\xfc\
-\x40\x96\xe5\x49\x30\x82\x1b\x8d\xc6\x9e\x11\x41\x6b\x6d\xab\x94\
-\x4a\xf4\xd9\xc7\x1d\x76\x7f\xec\xb2\x78\x69\x91\xcd\xf9\x4d\xee\
-\x95\xef\xce\xa5\xbf\xa5\x1f\xab\x1d\x25\x1a\xc0\x08\x7f\xcd\xf6\
-\xe9\x36\xd5\x4e\x95\xfd\x4f\x05\x00\x3e\x57\x0b\x98\x41\x4d\x63\
-\x58\x0d\x00\x52\x29\xeb\xb1\xd3\xdc\x06\xda\x6f\x40\xed\x7b\x8d\
-\xe8\x4e\x84\xcb\x8b\x9b\x65\x00\xd4\x23\x35\x1b\x00\x16\x42\x04\
-\xf5\xeb\x0b\x16\x76\xe7\x59\x67\xae\xcc\x10\x3c\x57\x5c\x05\xde\
-\x2f\x09\xb9\x82\xe2\x40\x80\x8b\x84\xda\x4d\x76\xb0\x6b\xca\xdf\
-\x59\xc9\xac\x20\xe7\x35\x61\x0a\x9b\x0f\xc0\xb1\xc1\x30\xc5\x43\
-\xbf\x01\x78\x81\xff\x8a\x6d\x6e\x2e\x07\x1a\xb6\xbe\x6e\x91\x7e\
-\x99\x26\x0a\xf8\xc2\x04\x79\xb9\x25\x4f\x15\xb0\xd0\x6c\x36\xf7\
-\xbc\xc0\xd7\x6d\xe7\x4e\x97\x20\x08\x6e\x88\xc8\x5b\x7b\x07\x50\
-\x7e\x03\x57\x0f\x26\xce\x64\xbc\x00\xdc\xba\x6e\xb2\x83\xfe\x4f\
-\x40\x12\x76\x60\x42\x60\x8c\xb1\x6d\xb7\x23\x01\x62\x2f\x18\x03\
-\xc6\xe1\x4a\xa5\x42\x18\x86\x4c\x4c\x4e\xf2\xea\xf5\x9b\x77\xc0\
-\x11\xf8\x2c\x44\x51\x24\xdd\x6e\x57\xfa\xfd\xbe\xc4\x71\x2c\x83\
-\xc1\x40\x86\xc3\xa1\x18\x63\xec\xbb\x58\x2c\xda\xf7\xfd\x8d\x8d\
-\x13\x60\x4a\x44\x70\xc5\x0a\x3a\x9d\x3f\x0a\x5a\xad\x96\x94\x4a\
-\x25\x59\xcb\xe7\x47\xf0\xb4\x87\xbd\xe0\xfa\x99\xc0\xf4\x7a\xbd\
-\x11\x9c\x10\x8c\x52\xaf\x37\xcc\xda\xfa\xfa\xbe\x9f\x9c\xac\x02\
-\xce\x01\x59\x40\xf1\xfb\xc4\xc0\x91\x88\xc4\x30\x9e\x9f\xaf\xc9\
-\x06\x51\x54\x9d\xd3\x94\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\
+\x70\x65\x2e\x6f\x72\x67\x9b\xee\x3c\x1a\x00\x00\x02\xed\x49\x44\
+\x41\x54\x78\xda\xb5\x95\x3d\x48\x5b\x51\x18\x86\xdf\x9b\x7b\xf3\
+\xe7\x4f\x89\x15\x21\xd1\x41\x6b\x25\x85\x06\xd3\xa9\x43\x70\xa8\
+\x89\x50\x3b\x77\xeb\xda\xc5\xcd\xcd\xc5\xad\x14\x04\xe9\xe6\xe8\
+\x22\x88\xd0\xc1\xdd\x59\x1c\x2b\x1d\x1a\x74\x68\x35\x6d\x21\xd4\
+\x04\xff\x62\x34\xb9\x31\x3f\xe6\xf4\x7b\xaf\xde\x78\xbd\xe2\x1f\
+\xb4\x2f\x7c\x5c\x38\xf9\xce\x73\xbe\xf3\x7e\xe7\x9c\x68\x4a\x29\
+\xb8\xa5\x69\xda\x10\x80\x38\xee\xa7\xb4\x30\xb6\xe1\x16\xc1\xee\
+\x10\xbd\x55\xf7\xd4\x45\x2e\xdc\xe1\xc1\xff\xd1\xcd\xe0\x46\xa3\
+\xf1\x6f\xc1\xcb\xcb\xcb\xfa\xc8\xc8\xc8\xf3\x6a\xb5\x76\x27\x9c\
+\xbf\x33\x97\x73\xe0\x92\x01\x97\x6a\xb5\xda\xbb\x54\x2a\xf5\xb1\
+\x54\x2a\xe3\xec\xac\x09\xbf\xdf\x0b\x5d\x37\x24\x3c\x6c\x2a\xfd\
+\xe3\xb8\x44\x03\xd5\x6a\x1d\xcc\x95\x39\xbf\x01\x2c\xdd\x0a\x36\
+\x0c\x23\xb8\xb3\xb3\x83\x93\x93\x12\x2b\x92\x85\xfc\xf0\x7a\xbd\
+\x32\xae\xdb\x60\x19\x3f\x43\xbd\x5e\x17\x70\x15\xcc\x8d\xc5\x62\
+\xc1\x6b\x9c\xd9\xd9\xd9\x27\x00\x7e\x42\xd4\xde\xde\x6e\xc5\xfe\
+\xfe\x3e\x8e\x8e\x8a\x02\xad\x23\x10\xa8\x09\x98\x15\xeb\x8e\x8a\
+\x09\x6e\xe0\xf4\xb4\xca\x5c\x16\x30\xbf\xb8\xb8\x38\x7f\x7c\x7c\
+\x8c\x72\xb9\x4c\xd4\x20\x2b\x1e\x93\x10\x40\x00\x9d\x9d\x9d\x28\
+\x16\x8b\xd8\xdd\xdd\x45\xa1\x70\xc4\x8a\xc4\x0a\x3f\x7c\x3e\xcb\
+\x0e\x07\x98\x3b\x39\xaf\x98\xb9\x9c\xd3\xdb\xdb\x6b\x2f\x2a\x0b\
+\x9e\xa6\x08\x4e\x79\x3c\x9e\x56\xb5\xa5\x52\x09\xa1\x50\x08\x33\
+\x33\x1f\x98\x78\xe5\xac\x53\x84\x33\x6c\x49\x2e\xed\x43\x47\x47\
+\x07\x2b\xa7\x45\xec\xd3\x98\x91\x1a\x7b\x15\x1f\x7a\xfa\x0c\xb6\
+\xf6\xf6\xf6\xd0\xdf\xdf\x8f\x87\x28\x1a\x8d\xa2\xa7\xa7\x07\xb6\
+\xb6\x33\xdf\xe3\x46\xb0\xad\x4d\xb6\xea\x83\x2d\x6e\x4b\xfc\xc2\
+\x43\x34\x35\x35\x85\xbe\xbe\x3e\xd8\x12\x26\x9b\xed\x73\x82\xe9\
+\x91\xf8\x5b\x80\x2d\x36\x2d\x1c\x0e\x3b\xad\xa0\xaf\xdc\xb2\x73\
+\xce\x15\x06\x99\xda\xd6\xd6\xf6\x46\x3e\x9f\x8b\x35\x9b\x4d\x50\
+\xf2\xa5\x47\xce\x49\x6c\x06\x9c\x62\xa3\xb9\xa0\x2d\x42\xd9\x27\
+\x8a\xdf\x70\x38\xb2\x69\x68\x9a\xce\x73\x08\x5b\x84\x54\x2a\x15\
+\x38\x75\xc3\x0b\x78\xb9\xf5\x60\xd0\x5a\x6c\x6d\x6d\x0d\x89\x44\
+\x42\xee\x80\x09\x23\x9b\xfd\x23\x7e\x5c\x26\xcd\xcd\xcd\x61\x75\
+\x75\x15\xa6\x69\xba\x4e\xc4\x75\x28\xbf\x84\x26\x93\x49\x4c\x4e\
+\x4e\xb2\x28\x81\x9e\x20\x9b\xcd\x43\x5b\x58\xf8\xbc\x11\x8f\x47\
+\x59\x32\x2d\xb0\xfc\x1c\x1f\x7f\x23\xc7\xed\x13\xb7\xc8\x5b\x67\
+\x5f\x10\x06\x61\x12\x5c\x90\xa1\x30\x31\xf1\x1e\x2b\x2b\x2b\xc8\
+\xe7\xf3\x2d\x9f\xd3\xe9\x1f\x9b\xc6\xe1\x61\xc1\x1a\xa4\x78\xe0\
+\x23\x91\x08\x1f\x16\x74\x77\x3f\x96\xcb\x61\x35\x96\xe7\x94\xc1\
+\xf7\xc2\xf6\xb2\xd5\x8f\xd1\xd1\xa4\xb5\x58\x2e\x97\xb3\x2e\x13\
+\x45\xa6\xfb\x1f\x44\x2a\x9d\x51\x03\x03\x83\x6a\x78\xf8\x85\x76\
+\x0e\xf6\x5e\x40\x75\x42\x25\x68\x03\x43\x09\x58\x61\x7d\xfd\x8b\
+\x4a\xa7\xbf\x69\xd3\xd3\xd3\xda\xad\x8f\xd0\xc1\xc1\x01\x08\x0d\
+\x85\x1e\x09\xf4\x3a\xd8\x6d\x45\x57\x57\x97\xc6\x39\x77\xfe\x35\
+\x89\x5e\x67\x32\xbf\x8a\xf2\x08\x29\xd3\xac\x28\xf1\x5d\xc9\x91\
+\x53\x37\x49\x9a\x55\x04\x30\xee\xe6\xd0\x0a\x56\xa1\x03\xa0\x41\
+\x41\x89\x41\x89\x97\x12\x5e\x8e\xb9\x82\x06\x37\xd8\x0e\xf6\xda\
+\xf1\xfd\x2a\x91\x91\x30\x25\x2a\xcc\xf9\x0b\x3e\xfb\xf9\xce\xd4\
+\xa5\xbf\x61\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\
+\x00\x00\x04\x95\
+\x89\
+\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
+\x00\x00\x16\x00\x00\x00\x16\x08\x06\x00\x00\x00\xc4\xb4\x6c\x3b\
+\x00\x00\x00\x06\x62\x4b\x47\x44\x00\xff\x00\xff\x00\xff\xa0\xbd\
+\xa7\x93\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x09\x84\x00\x00\
+\x09\x84\x01\xaa\xe2\x63\x79\x00\x00\x00\x07\x74\x49\x4d\x45\x07\
+\xd7\x0c\x0a\x00\x0b\x07\x14\x32\xc7\x3a\x00\x00\x04\x22\x49\x44\
+\x41\x54\x78\xda\xb5\x93\x5f\x4c\x5b\x55\x1c\xc7\xcf\xb9\xff\x7a\
+\x7b\x6f\x4b\x4b\x4b\xd9\xa4\x30\x86\xd0\x0d\xa1\xb4\xfc\x19\xb4\
+\x19\x38\x91\x0d\x35\x8e\x05\xf6\xe2\x32\x9d\x33\x99\x02\x0f\xf2\
+\x20\xc9\x12\xdf\x7c\xc2\x25\x1a\x63\x64\xf1\x4d\xcd\xb6\x84\xec\
+\xc9\xa1\x04\xb6\x6c\xa3\x26\xcb\x26\x3a\x60\x3e\x08\x48\xa4\xfc\
+\xa7\x54\x0a\x85\x02\x97\xfb\xa7\xf7\xf6\x9e\x7b\xbd\x24\x3e\x18\
+\x97\x75\xd3\xe0\x27\xf9\xe6\xe4\xbc\x7c\xf2\x3b\x39\xdf\x1f\xf8\
+\xbf\x80\xe0\x1f\x74\x77\x77\xdb\xbd\x5e\xdf\x29\x96\x65\x8e\x12\
+\x24\xe9\x52\x55\x75\x53\x92\xa4\xd1\xe9\xf0\x74\x5f\x5b\xdb\x7b\
+\xab\xff\x5a\xcc\xb2\x2c\xbc\x7a\xed\x5a\x9b\xc3\xe1\xec\xba\x3f\
+\xba\xe0\x18\x0b\xc7\x41\x82\x97\x75\x0b\x4d\xc0\x82\x1c\x2b\xac\
+\xaf\x3e\x20\x50\x24\xf6\xe9\xdb\xe7\xde\xba\xb4\xbd\xbd\x8d\x9e\
+\x55\x0c\xaf\x5c\xb9\xfa\x99\x0a\x2d\x1f\x7c\xf5\x7d\x58\xc7\xac\
+\x59\xe8\x78\xa3\x0f\xf0\x00\x43\x0e\x33\x01\x86\x7e\xfc\x5d\x4f\
+\x44\xfe\x20\x5f\xa9\xb4\xe0\xde\x42\xdb\xb7\xef\x9c\x3f\xff\x66\
+\x2a\x95\x4a\x2b\xc7\x81\x41\x57\xd7\xc7\x67\x31\xca\xf6\xc9\x97\
+\xdf\x2d\xa1\x82\x0a\xef\x56\x5d\x53\x40\x28\x2d\xcb\xd3\xd5\x4c\
+\x3b\x77\x38\x3f\x0b\x65\x1e\xcc\xe1\x08\xda\xcc\xdf\x1b\x8e\xe1\
+\x36\x4a\x29\x6f\x69\x6a\x50\xee\xdc\xbe\xfd\xe0\x69\x62\x53\x73\
+\x73\xcb\x8d\xbe\x87\xbc\x85\xc9\x2f\x8c\x56\x9d\xa8\x88\x65\xe7\
+\xd8\x64\x8b\x95\x16\xe6\x10\x8c\x3a\x19\x32\x85\x48\x62\x9b\xb5\
+\x67\xac\x13\x34\x2d\x3e\x18\x5a\x64\x6a\x3c\xe6\xa3\xeb\xeb\xf1\
+\xaf\xa3\xd1\xa8\xf4\x24\x31\x76\xe1\xc2\xbb\x35\x8a\x46\x1e\x98\
+\x8e\x6b\x9b\x19\x65\x9e\x5f\xd7\x20\x31\xbd\x8e\xe1\xe1\x09\x05\
+\x4e\xcb\x34\xb5\x3e\x96\xc2\xe6\x36\x71\x22\x3a\x87\xb0\xb0\xfc\
+\xdc\xbe\x09\x39\x23\x73\x76\x7e\x4d\xb3\x1e\x7b\xe9\xd8\x49\x90\
+\x06\x82\xa2\x48\xef\x96\x00\x71\x7a\x7f\x76\x54\x34\xd1\xab\xa1\
+\x6f\x6e\xb5\xc1\x8c\x03\x10\x92\x0c\x40\x7c\x0c\xa0\xad\x45\x80\
+\xa4\x4d\xa0\x25\xb7\x40\xf9\xc5\x0f\xbf\xb0\x1c\x74\x47\x36\xc4\
+\xb9\x62\x37\x45\x79\xd3\x89\x31\x00\x20\x0b\x20\xae\x53\x56\xcb\
+\x0e\xc6\x90\x32\xb7\x83\x80\x88\x18\x88\x68\x27\x84\x34\x0b\x35\
+\x82\x82\x72\x0a\x41\x9e\x13\x00\xc9\x9a\x92\x94\xdd\xc2\x63\x04\
+\xa9\x1a\xd0\x69\x27\x36\xaa\xb3\xe0\x29\x25\x34\xb4\xa8\x50\x1a\
+\x04\xe8\xe4\xa5\x73\x1f\x39\xcd\x84\x68\x25\x31\xd9\x84\x79\x90\
+\xaa\x9f\x80\xa2\xaa\x53\x9b\x32\xa2\x97\x37\x04\x46\x53\x11\xb6\
+\xcf\x4e\x9a\x76\x22\x42\x24\xed\xc4\xbd\xbd\xbd\x43\x14\x10\x84\
+\xe7\x2d\xd8\x7e\x24\xa5\x28\x01\x69\xa9\x14\x04\x12\x4e\x40\xde\
+\x64\x82\x1c\x45\xc1\x1d\x0d\x07\x62\x12\x00\x45\x53\x54\xc2\xc4\
+\x71\xb9\x85\xd9\x38\x36\x3c\x32\x32\x98\x56\x2c\xcb\xc9\xd5\x99\
+\xd9\x99\x9e\x26\x9f\xc9\x2d\x85\x97\xf3\xa5\x6d\x89\x4d\x22\x9d\
+\xd8\x6d\x38\x4b\x42\x05\x87\x50\x53\x34\x1d\x13\x65\x95\x92\x97\
+\x13\xae\x53\x45\x94\x6f\x69\x7e\xea\xee\xe8\xc8\xc8\x6f\x4f\xab\
+\x9b\x3e\x31\x3e\xfe\xa8\x2e\x58\xf1\x6a\xdd\x21\x77\xe5\xd4\x92\
+\x24\xf1\x34\xcd\x21\x8a\xd0\x44\x15\x10\x1b\x49\x8d\x89\x71\xb2\
+\x4d\x9c\x89\x79\x9a\x59\xa1\xa5\xc4\x99\xcc\xf4\xfb\xfc\x6c\x51\
+\x51\xe1\x60\x28\x14\x5a\x4d\xbb\x20\xc6\x16\x09\x93\x93\x93\x77\
+\xbc\x1e\xf7\x91\xd3\xfe\xdc\xc6\x3c\x00\x0a\x48\x09\x65\xcb\x5b\
+\x92\xdb\x99\x4c\x7a\xfd\x2a\xff\xf2\x6b\x19\x7c\xc3\xca\xc4\x7d\
+\x65\x64\xf8\xa1\xb9\xb8\xe4\x85\x8c\xca\xca\xca\x33\x65\x65\x65\
+\x8f\x06\x06\x06\xe6\x9f\x28\xde\x85\xe3\xb8\xad\x50\x68\xb0\x57\
+\x12\x76\xc2\x76\x4c\xcc\xcb\x41\x89\x92\x43\x70\xb3\x98\x8d\xcf\
+\x64\x25\xc2\xbf\x2c\x0f\xde\xec\xfb\xfc\xf2\xe5\xee\xf7\x6d\x36\
+\x5b\xf6\x72\x24\x52\x9e\xe5\x72\x99\x03\x81\xe0\x1b\xc1\x60\x60\
+\x6e\x61\x61\x61\x62\x65\x65\x05\x3c\x0b\x84\x91\x4c\x23\xb9\x46\
+\x9c\x46\x28\xf0\x17\x79\x79\x79\x78\x4b\x4b\x4b\x77\x47\x47\x87\
+\xde\x73\xfd\xba\xbe\x14\x89\xa8\xfd\xfd\xfd\x17\xeb\xeb\xeb\xe1\
+\xe3\x13\x3f\x8e\x66\x24\x69\x84\x33\x22\x19\x41\x7f\x7b\x99\xce\
+\xf3\xfc\x5d\x87\xc3\x81\x8b\x82\xf0\x62\x22\x91\xc0\x6a\x6b\xeb\
+\x1a\xfd\x7e\x9f\x3d\x16\x8b\xfd\x30\x3b\x3b\xab\xa5\x11\xa7\x67\
+\x57\x6e\x1c\xf7\x58\x96\xe5\x29\x8a\x3a\xbe\xb8\xb0\x88\x55\x1d\
+\xa9\x0a\xd6\x54\x57\x17\x2b\x8a\x72\x73\x6c\x6c\x4c\xc5\xc1\x7f\
+\x24\x1e\x8f\x83\xf1\xf1\xf1\x9f\x0b\x0a\x0a\x96\x5d\x2e\xd7\xeb\
+\xe1\xa9\x29\xfc\x70\x71\x71\xa9\x21\xaf\x65\x18\xa6\x1f\x82\x3d\
+\xa0\xbd\xbd\xfd\xb4\xd1\x92\x1e\x51\x14\x99\x40\x20\x00\x34\x4d\
+\xfb\x09\x82\x3d\xc2\xf8\xcc\x86\x60\x30\x78\x63\x6d\x6d\xcd\x62\
+\x5c\xcf\x82\xbd\xa4\xb3\xb3\xb3\xb2\xb5\xb5\xf5\x0c\x30\xf8\x13\
+\x74\xaa\xde\x46\xd5\x46\x63\x32\x00\x00\x00\x00\x49\x45\x4e\x44\
+\xae\x42\x60\x82\
+\x00\x00\x02\x13\
+\x89\
+\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
+\x00\x00\x10\x00\x00\x00\x10\x08\x03\x00\x00\x00\x28\x2d\x0f\x53\
+\x00\x00\x00\x03\x73\x42\x49\x54\x08\x08\x08\xdb\xe1\x4f\xe0\x00\
+\x00\x00\x09\x70\x48\x59\x73\x00\x00\x0d\xd7\x00\x00\x0d\xd7\x01\
+\x42\x28\x9b\x78\x00\x00\x00\x19\x74\x45\x58\x74\x53\x6f\x66\x74\
+\x77\x61\x72\x65\x00\x77\x77\x77\x2e\x69\x6e\x6b\x73\x63\x61\x70\
+\x65\x2e\x6f\x72\x67\x9b\xee\x3c\x1a\x00\x00\x00\xe4\x50\x4c\x54\
+\x45\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+\x42\x88\xdb\x42\x88\xdb\x42\x87\xdb\x41\x87\xdb\x21\x64\xb2\x23\
+\x6b\xbf\x23\x6c\xc1\x29\x71\xc4\x31\x66\xa6\x31\x77\xca\x3a\x7e\
+\xcf\x41\x87\xdb\x43\x85\xd5\x48\x7c\xbe\x4b\x8c\xda\x54\x93\xe0\
+\x55\x84\xc1\x68\x90\xc4\x6e\x95\xc8\x72\xa5\xe4\x78\xa8\xe6\x79\
+\xa8\xe4\x7e\x96\xb3\x7e\x97\xb4\x85\x9a\xb3\x8b\xb6\xec\x94\xa5\
+\xb7\x95\xb7\xe1\x98\xbc\xeb\xa0\xc5\xf2\xa1\xc2\xed\xa4\xc5\xec\
+\xa5\xc6\xec\xa6\xc6\xec\xa9\xc7\xee\xad\xca\xed\xaf\xcb\xed\xaf\
+\xcb\xef\xb1\xcc\xf0\xbc\xd3\xf1\xbf\xd6\xf4\xc0\xd8\xf1\xe3\xe4\
+\xe5\xe6\xe7\xe8\xe7\xe8\xe8\xe9\xea\xeb\xeb\xec\xec\xec\xed\xed\
+\xed\xee\xee\xee\xef\xef\xef\xf0\xf0\xf0\xf0\xf0\xf0\xf1\xf1\xf1\
+\xf1\xf1\xf1\xf2\xf2\xf2\xf3\xf3\xf3\xf3\xf3\xf3\xf4\xf4\xf4\xf5\
+\xf5\xf5\xf5\xf5\xf5\xf6\xf6\xf6\xf6\xf6\xf7\xf7\xf7\xf8\xf8\xf8\
+\xf9\xf9\xf9\xfa\xfa\xfa\xfb\xfb\xfb\xfc\xfc\xfc\xfd\xfd\xfd\xfe\
+\xfe\xfe\xff\xff\xff\x08\x2e\x0f\x60\x00\x00\x00\x09\x74\x52\x4e\
+\x53\x00\x1f\x3c\x3e\x3f\xfa\xfc\xfd\xfe\x0a\x2f\x02\x16\x00\x00\
+\x00\x8c\x49\x44\x41\x54\x18\x19\x05\xc1\x41\x4a\x03\x51\x14\x04\
+\xc0\xea\xfe\x2f\x82\x89\x88\x20\xb8\xf4\x3c\x1e\xd9\x03\x09\x82\
+\x3b\x03\x6e\x74\x32\x63\x55\x48\x09\x1c\xf6\xc3\xd0\x37\x00\xef\
+\x37\x73\xba\xdc\x7c\xa4\x4d\x92\x67\x4c\x5e\xbf\xb5\xed\x6a\xe2\
+\xbc\x8c\xdf\x5d\x3b\x6b\xad\xf0\xf4\xf0\x39\xd9\x76\x9d\x99\x95\
+\xb0\xdf\x4c\x42\xe7\xd4\x26\x60\x24\x66\xb5\x49\x22\xe4\x62\x0f\
+\x80\xa3\x26\x8f\xdb\xcb\x0e\xe8\xd7\x5c\xa7\xfb\xf6\xf7\x0b\xb8\
+\xdb\xda\x49\xd6\x6c\x80\x59\xc9\xf4\xb4\xf7\x0c\xd0\x53\xa7\xd3\
+\x1f\x00\xf7\xed\xe4\x0a\x00\x92\x24\x02\x70\x1c\xc7\x3f\xb4\x2c\
+\x21\xd5\x80\x04\x87\x89\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\
\x60\x82\
\x00\x00\x02\x0f\
\x89\
@@ -80760,6 +80616,270 @@
\x90\xd5\xd6\x3c\xe8\x74\x3a\xb7\x00\x66\x56\x1b\xfa\x5b\xaf\x37\
\x7c\x7a\x7c\xbc\x71\xf7\x61\x91\xfb\x06\x81\x94\x9d\xac\xac\xe0\
\x78\xdb\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\
+\x00\x00\x03\x8b\
+\x89\
+\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
+\x00\x00\x16\x00\x00\x00\x16\x08\x06\x00\x00\x00\xc4\xb4\x6c\x3b\
+\x00\x00\x00\x06\x62\x4b\x47\x44\x00\xff\x00\xff\x00\xff\xa0\xbd\
+\xa7\x93\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x09\x84\x00\x00\
+\x09\x84\x01\xaa\xe2\x63\x79\x00\x00\x00\x07\x74\x49\x4d\x45\x07\
+\xd7\x0c\x1c\x11\x34\x07\x24\x7a\x2c\x02\x00\x00\x03\x18\x49\x44\
+\x41\x54\x78\xda\xdd\x93\x49\x68\x14\x41\x18\x85\x5f\x55\x77\xcf\
+\xd2\xe9\x4c\xa2\x59\xc5\x2d\x26\x2a\x8a\x0b\xb8\x86\xb8\x80\xa8\
+\x78\x34\x8a\xfb\x41\x44\x41\x10\x11\x3c\x18\x45\x6f\x8a\x7a\x53\
+\x0f\x82\x10\x08\x38\x1a\x97\x93\x8a\x1a\x02\x42\x0e\x8a\x08\x82\
+\x10\x5c\x2e\x6e\xa8\x18\xd1\x10\x98\x89\x93\x64\x7a\x7a\xba\xba\
+\x16\xab\x3b\xa0\x82\x26\x2a\x7a\xf2\x35\x0f\x0a\x8a\xfa\xea\xaf\
+\xf7\xff\x8d\xff\x5f\x53\x37\x5f\x58\xbc\xf6\xe0\xcd\xfb\xed\x9d\
+\xcf\x5a\x31\x8a\xcc\xdf\x06\x6e\x4a\x53\xc9\x8b\x2d\x55\x0e\x4e\
+\x34\xcd\xae\xb1\x6e\x74\x75\x2f\x07\xb0\xe7\xaf\xc0\x0d\x9b\xd2\
+\x35\x22\x28\xb4\x37\xcd\xaa\x5d\xb3\x63\x5d\x13\x12\xf1\x18\xce\
+\xa5\x6f\xe0\xaf\x2a\x9e\xb6\xf5\xd2\x9a\x18\x61\xed\x1b\x57\xcf\
+\xae\x69\x9c\x3b\x05\x82\x73\xb8\xda\xcc\xcd\x8c\x0e\x1e\x19\x78\
+\xd9\x82\x92\x27\xc6\x8f\x8d\xb7\x6c\x5e\x35\x8b\x56\x96\x97\x20\
+\xef\x15\x41\x30\x2c\xee\x66\x51\x31\x6f\xbb\x41\xa8\x09\x62\xc4\
+\x15\x8d\xd9\x00\x08\xfa\x1e\x9c\x96\xd0\xa2\x3f\x85\x6e\xb9\x54\
+\x0f\x25\x1e\x2c\x9a\x5e\x7e\x68\xdb\xaa\x7a\x9a\xb0\x28\xdc\x82\
+\x8f\x82\x17\x9a\x45\xe6\x5e\x0e\x3c\xdf\xc7\x45\x31\xc7\x65\x50\
+\x10\x8a\xfb\xa2\xac\x24\x26\xf6\x1e\xbd\xd0\x01\x2d\xf2\x43\x93\
+\xb6\x5c\xdc\x6a\x5b\xa4\x75\xc5\xdc\x8a\xb2\xba\x71\x29\x18\xa6\
+\x09\xc3\x30\x40\x69\x68\x0a\x42\x86\x8f\x28\xa5\x22\x0b\x21\xb4\
+\x39\x78\x10\x80\x31\x1f\x6d\x57\x3a\xf0\xf6\xee\x59\x62\x7e\x37\
+\x46\x25\x80\x3a\x5b\xed\xa8\x5d\x8d\xd3\x4b\xe1\xd8\x04\x79\x5d\
+\xa5\x69\x49\x98\xa6\xa5\xe1\x2a\x82\x13\x4a\x42\x78\x04\x95\x52\
+\x46\x60\x1e\x70\x04\x8c\xc1\xd3\x51\x7d\xce\x0d\x7c\xcb\xb8\x61\
+\x43\xdb\x04\xc9\x59\xd7\xe4\x31\xc1\x8c\xfa\x5a\x1b\x3e\x63\x00\
+\x21\x88\xc5\x00\x4b\x10\x0d\xa7\xda\x44\xc3\x29\x68\x08\x86\xd2\
+\x1f\xa0\x24\x50\xf4\x05\x3e\x0f\xb8\xe8\xed\xcb\xe0\x7d\xcf\x27\
+\x68\xce\x37\xb0\x94\x01\x14\x67\xca\xcd\xfb\xe8\xf9\x54\x80\xe3\
+\x94\xc2\x76\x1c\xd8\xb6\x42\x3c\x41\x60\x59\x21\x1c\x1a\x2a\xa1\
+\x40\x20\xa4\x42\xc0\x25\x0a\x45\x16\xe5\x5e\xf4\x3c\xe4\x5d\x8e\
+\xb0\x91\x4a\x0c\x83\x0d\x68\xe5\x5e\x74\x0e\xa6\xea\x57\x9c\x1f\
+\x2c\xb0\xf2\xfe\x5c\x7e\x91\x57\x64\xc4\x63\x12\xae\xaf\xe0\x31\
+\xc0\x0b\x80\x62\xa0\xc0\x38\x10\x88\x10\x0c\x48\x45\xa2\xde\x53\
+\x42\xa2\xcb\x24\xe7\x51\xc6\xbd\x3d\xaf\xc0\xb2\xaf\x8e\x7d\xcd\
+\xb8\xe7\xce\x61\x0f\xc0\xbe\x71\xcb\x5b\x3a\x33\x59\xef\x3c\x35\
+\x8c\x5a\x27\x55\x1e\x35\xcf\xd2\x8e\x59\x96\x8e\x26\xa6\xab\x37\
+\xa3\x48\x10\xc2\x84\x88\xd6\x52\x29\xf8\x7a\x2f\x6c\xae\x9d\xb4\
+\x90\x8f\x76\x7f\xa2\xea\xc6\x3d\x55\x52\x04\x6d\x95\x55\xd5\xcd\
+\x33\xe7\x2c\x40\x2a\x55\x86\x64\x32\x81\x44\x3c\xae\xe1\x16\x4c\
+\xd3\xc0\xa9\x03\xcd\xe1\xfc\x82\x98\x49\x10\x2b\xa1\xd7\x49\x8c\
+\xad\xac\x80\x52\xf2\xd6\xc7\xee\xeb\xeb\x08\x46\x50\xe5\x82\x9d\
+\x90\xdc\xdf\xad\x7f\xdf\x33\x0b\x97\xac\x74\x26\xd6\x35\x20\x99\
+\xd0\xf0\x44\x3c\xaa\xfa\xe4\xfe\x66\xb0\xcc\xcb\x11\xcf\x53\x8c\
+\xa0\x4c\x77\x1a\xfd\x4f\xaf\xb6\xb9\x83\xfd\xf3\xef\x75\x5e\x7e\
+\xf4\xe4\x61\x57\x34\x0d\xa6\x8e\x25\xae\x9f\x4d\xa8\x85\xd1\x44\
+\xf1\x0b\x0d\xbc\xb8\xfd\x5a\x72\xb1\xec\xf1\xc3\xae\xe3\xd7\xd2\
+\xa7\xc4\x40\x7f\x5f\x04\x07\x31\xf0\xcf\x94\x1c\xbf\x78\x49\x69\
+\xdd\xd2\x37\xcd\x47\x5a\xd5\xa4\xa6\xf5\x0a\xa3\xe8\x8f\xae\xe5\
+\x43\x1f\x3f\x10\xbb\x26\x9d\xed\xfd\x60\x0c\x0d\xb9\xcf\xfd\xec\
+\xbb\x0e\xfc\x37\xfa\x02\x9d\xc7\x5e\x06\x50\xe4\x66\x9b\x00\x00\
+\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\
+\x00\x00\x02\x7e\
+\x89\
+\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
+\x00\x00\x10\x00\x00\x00\x10\x08\x06\x00\x00\x00\x1f\xf3\xff\x61\
+\x00\x00\x00\x04\x73\x42\x49\x54\x08\x08\x08\x08\x7c\x08\x64\x88\
+\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x01\xbb\x00\x00\x01\xbb\
+\x01\x3a\xec\xe3\xe2\x00\x00\x00\x19\x74\x45\x58\x74\x53\x6f\x66\
+\x74\x77\x61\x72\x65\x00\x77\x77\x77\x2e\x69\x6e\x6b\x73\x63\x61\
+\x70\x65\x2e\x6f\x72\x67\x9b\xee\x3c\x1a\x00\x00\x01\xfb\x49\x44\
+\x41\x54\x38\x8d\x95\x92\x4f\x6b\x1a\x51\x14\xc5\x7f\xef\xa9\x38\
+\xcd\x7a\x16\x5d\x14\xa4\xd0\x65\x9b\x92\x45\x05\x91\xe2\xae\xed\
+\xb6\x76\xd7\x64\x95\x0f\x60\x3f\x44\x0b\xfd\x43\xc1\x76\x15\x42\
+\x20\x10\xb2\xf6\x3b\xe8\xc2\x8a\x28\x86\x5a\x90\x11\x0c\x74\x21\
+\xb3\x10\xd4\x2c\x26\xe3\x8c\xa3\x73\xbb\x88\x63\x75\x48\x0a\x3d\
+\x70\x37\xef\x71\xce\x3d\xf7\xde\xa3\x80\x47\xc0\x2e\xff\x87\xae\
+\x88\x0c\x00\x92\xc0\xee\x68\x34\xaa\x84\x22\x68\xad\xd1\x5a\xa3\
+\x94\xda\x2a\x80\xcb\xc1\x80\x76\xbb\xcd\xde\xde\x1e\xd9\x6c\xf6\
+\x0d\x30\x00\xd0\x00\xa1\xfc\xbb\xdd\xd5\xd5\x15\xc3\xe1\x90\x83\
+\x83\x03\x5a\xad\x16\x85\x42\xe1\x69\xf4\xa7\x01\x12\x09\x4d\x22\
+\x91\x58\x3b\xd0\x5a\x93\xd8\xa8\x45\x10\x60\x9a\x26\x3b\x3b\x3b\
+\x1c\x1e\x1e\x92\xcb\xe5\xde\x95\x4a\xa5\x27\x00\x0a\x28\x8e\x27\
+\x93\x0a\x22\xa8\x48\x40\x29\xc2\x30\xa4\xd3\xe9\xe0\xba\x2e\x8e\
+\xe3\xe0\x38\x0e\xfb\xfb\xfb\x18\x86\x81\x65\x59\xfd\xa3\xa3\xa3\
+\x7b\xae\xeb\xe6\x14\x50\x9c\x4c\xa7\x15\xe0\xaf\x83\xd5\xdc\xa9\
+\x54\x6a\xed\x2c\xda\x45\x84\x5e\xaf\x57\x2b\x97\xcb\xa3\x64\x44\
+\xbc\x4d\xe0\x36\x62\x1c\x37\x02\x11\x41\xa9\x9b\xd2\x9a\xe5\x72\
+\x49\xbd\x5e\xe7\xfa\xfa\x7a\x6b\x84\x74\x3a\x8d\x65\x59\xfd\xe3\
+\xe3\xe3\x87\xc0\xdb\x24\x80\x8a\x3b\xd0\x37\x4b\xcd\xe7\xf3\x28\
+\xa5\xb0\x6d\x1b\xdb\xb6\x49\xa7\xd3\xf8\xbe\xcf\xd9\xd9\xd9\x7d\
+\x11\x79\x7e\x72\x72\x62\x27\xa3\x4d\x46\x37\x8f\xc6\x61\xe3\xcd\
+\x30\x0c\xc6\xe3\x31\x9e\xe7\x71\x7a\x7a\x4a\xa3\xd1\xf8\x5e\xad\
+\x56\x7f\xad\xcf\x48\x8c\x1c\x0f\x92\x69\x9a\x64\x32\x19\xce\xcf\
+\xcf\xc9\x66\xb3\x52\xab\xd5\x2e\xb6\x72\x10\x27\xc4\x53\xe8\x79\
+\x1e\x4a\x29\x5e\xbc\x7a\xc9\x8f\x66\xb3\x09\xfc\xdc\x5c\x64\xd1\
+\x75\x5d\xf1\x3c\x4f\xe6\xf3\xb9\x04\x41\x20\x8b\xc5\x42\x96\xcb\
+\xa5\x84\x61\x28\x41\x10\x48\xb7\xdb\x95\xf9\xdc\x97\x0f\x5f\x3e\
+\xf7\x81\xc7\x80\x12\x11\x44\x64\x25\x30\x9b\xdd\x29\xe0\x38\x8e\
+\x0c\x2e\x2f\xe5\xfd\xa7\x8f\x7d\xe0\x19\xa0\x23\x72\x24\xf0\xda\
+\x9d\xcd\x42\xdf\xf7\x25\x08\x82\x2d\x01\x11\x91\xc9\x74\x1a\x7e\
+\x2d\x7f\x6b\xac\x3a\x6f\x91\x45\x04\x05\x3c\x58\x29\xdf\x95\x98\
+\x70\x35\xf3\x6f\x89\x5a\x6e\xe0\x0f\xd5\xf2\x24\x09\x1c\xd8\x9f\
+\xe3\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\
+\x00\x00\x03\xae\
+\x89\
+\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
+\x00\x00\x16\x00\x00\x00\x16\x08\x03\x00\x00\x00\xf3\x6a\x9c\x09\
+\x00\x00\x00\x03\x73\x42\x49\x54\x08\x08\x08\xdb\xe1\x4f\xe0\x00\
+\x00\x00\x09\x70\x48\x59\x73\x00\x00\x0d\xd7\x00\x00\x0d\xd7\x01\
+\x42\x28\x9b\x78\x00\x00\x00\x19\x74\x45\x58\x74\x53\x6f\x66\x74\
+\x77\x61\x72\x65\x00\x77\x77\x77\x2e\x69\x6e\x6b\x73\x63\x61\x70\
+\x65\x2e\x6f\x72\x67\x9b\xee\x3c\x1a\x00\x00\x01\xa4\x50\x4c\x54\
+\x45\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x2e\x2e\x2e\x2f\x2f\x2f\x16\
+\x16\x16\x1a\x1a\x1a\x10\x10\x10\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+\x12\x12\x12\x07\x07\x07\x11\x11\x11\x05\x05\x05\x05\x05\x05\x03\
+\x03\x03\x05\x05\x05\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x07\x07\x07\x00\x00\x00\x02\x02\x02\x05\x05\x05\x20\x20\x20\
+\x20\x20\x20\x03\x03\x03\x00\x00\x00\x14\x14\x14\x16\x16\x16\x14\
+\x14\x14\x15\x15\x15\x0e\x0e\x0e\x3b\x3b\x3b\x2c\x2c\x2c\x37\x37\
+\x37\x37\x37\x37\x3f\x3f\x3f\x31\x31\x31\x43\x43\x43\x54\x54\x54\
+\x75\x75\x75\x11\x11\x11\x53\x53\x52\x55\x54\x53\x3c\x36\x32\x8b\
+\x8b\x8b\x4b\x4b\x4b\x50\x50\x50\x57\x57\x57\x20\x20\x20\x42\x42\
+\x42\x4a\x4a\x4a\x51\x3b\x29\x72\x72\x72\x81\x81\x81\x84\x7b\x73\
+\x9f\x91\x83\x03\x03\x03\x07\x07\x07\x0b\x0b\x0b\x0e\x0e\x0e\x10\
+\x0a\x07\x10\x10\x10\x11\x11\x11\x12\x12\x12\x14\x14\x14\x1d\x15\
+\x0f\x1e\x1e\x1e\x1f\x12\x0a\x20\x20\x20\x21\x21\x21\x22\x22\x22\
+\x23\x10\x00\x24\x1a\x16\x26\x26\x26\x2d\x1c\x11\x2d\x2d\x2d\x30\
+\x27\x21\x36\x20\x0e\x38\x38\x38\x3e\x3e\x3e\x41\x41\x41\x44\x20\
+\x03\x47\x47\x47\x49\x49\x49\x4b\x28\x0c\x4e\x28\x0c\x52\x44\x39\
+\x52\x52\x52\x54\x54\x54\x55\x55\x55\x58\x28\x00\x59\x56\x54\x5d\
+\x5d\x5d\x5f\x3c\x22\x60\x2d\x01\x60\x3f\x25\x64\x48\x30\x66\x62\
+\x61\x67\x52\x45\x69\x63\x60\x6c\x34\x01\x6f\x6f\x6f\x70\x56\x46\
+\x74\x47\x21\x77\x38\x02\x78\x44\x15\x78\x78\x78\x7b\x5d\x43\x7c\
+\x41\x0d\x7c\x65\x50\x7f\x7f\x7f\x83\x83\x83\x85\x85\x85\x89\x89\
+\x89\x8a\x8a\x8a\x8e\x8e\x8e\x90\x60\x34\x90\x90\x90\x93\x93\x93\
+\x9a\x62\x39\x9a\x63\x3a\xa4\x72\x4b\xa9\x79\x55\xb1\x99\x82\xb8\
+\xb8\xb8\xc0\xc0\xc0\x67\x17\x18\xb9\x00\x00\x00\x46\x74\x52\x4e\
+\x53\x00\x01\x02\x03\x07\x08\x0d\x0e\x1b\x1d\x23\x27\x2e\x33\x43\
+\x59\x66\x81\x82\x84\x8d\x95\x9b\xaa\xac\xae\xb5\xb5\xb8\xb9\xc0\
+\xc1\xc7\xcd\xcd\xcd\xcf\xd0\xd2\xd7\xdc\xdf\xe9\xea\xf0\xf2\xf5\
+\xf5\xf7\xf7\xf8\xf9\xf9\xf9\xfa\xfb\xfb\xfc\xfc\xfd\xfd\xfd\xfe\
+\xfe\xfe\xfe\xfe\xfe\xfe\xfe\x61\xda\xb4\x94\x00\x00\x01\x2a\x49\
+\x44\x41\x54\x78\xda\xb5\x90\x4d\x52\xc2\x30\x00\x46\xd3\x24\x6d\
+\x21\xa4\x48\x2d\x50\x08\xca\x80\xe3\xa8\x1b\xd9\xb8\x72\xc6\x85\
+\x27\x70\xe5\x91\x39\x82\xba\x71\xd4\x8a\xa3\x45\x68\xa9\x90\x4a\
+\xfa\x93\x36\x0e\x3a\x0e\x17\xd0\xb7\xf8\x16\x6f\xf7\x3d\xf0\x8f\
+\xa0\x9f\xb5\xbb\x44\x65\x80\xb6\x5a\x5a\xa6\xb6\xba\x3e\x64\x75\
+\xb9\xd4\xd8\xa0\x59\xe3\xe9\xaf\x86\x96\xd3\xb6\x61\x02\xad\x46\
+\x8b\xaa\xb4\xcc\xd5\xb7\x36\x7a\x1d\xe7\x42\x8f\xd0\xf5\xd9\x54\
+\xdf\x3f\x9d\x12\x53\x14\x1b\x6d\xf7\xae\x4e\x28\x0c\x76\x78\x54\
+\x01\x03\x7a\x70\xf4\x2a\xd6\x00\x03\xcb\xa5\x8f\xb8\xc8\xbb\x6f\
+\x1c\x18\xec\xc1\xd4\x24\x75\x53\x8e\xcc\x3d\xe7\xd2\xb1\x71\xc8\
+\x5d\x2f\x39\x9c\x29\xe6\xda\xfb\x3e\x8c\x51\xa3\x7d\xee\x3d\xcd\
+\x1a\x78\xa9\x7c\x59\x4f\x5d\xfd\xee\x85\x1f\x4f\x05\x26\x64\xe2\
+\xf4\xa5\x6f\x2b\x13\x02\x33\x46\xfe\x10\x7f\x4c\x08\xc1\xa4\x9f\
+\x2b\x1b\x16\x8b\xdc\x5b\x2b\xaf\xb2\x72\x3a\x65\x84\xfb\x73\x54\
+\x2d\x3b\x96\x4c\x84\xe7\x3f\x07\xab\x55\xa1\x76\xcb\x45\x33\xbb\
+\x0f\x60\x2c\x58\xb5\xc0\x4c\x84\x73\x91\xcc\x43\xc1\xb0\x21\x5d\
+\x11\x23\x09\x66\xd1\x68\x7c\xb3\x0c\xf2\xcd\x69\x73\x12\x8e\xc6\
+\xb7\xef\x91\x06\x74\x6a\xd5\x32\x1e\xaf\xc1\x06\x42\x2d\xe3\x93\
+\xc7\xf9\x36\xe3\xb6\xe9\x5f\xf1\x05\x32\xe0\x83\x39\x86\x2c\xe5\
+\x0a\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\
+\x00\x00\x02\xd0\
+\x89\
+\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
+\x00\x00\x10\x00\x00\x00\x10\x08\x06\x00\x00\x00\x1f\xf3\xff\x61\
+\x00\x00\x00\x06\x62\x4b\x47\x44\x00\xff\x00\xff\x00\xff\xa0\xbd\
+\xa7\x93\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x1b\xaf\x00\x00\
+\x1b\xaf\x01\x5e\x1a\x91\x1c\x00\x00\x00\x07\x74\x49\x4d\x45\x07\
+\xd7\x09\x1c\x09\x10\x1f\x1c\x2b\x28\x4a\x00\x00\x02\x5d\x49\x44\
+\x41\x54\x78\xda\xc5\x52\x4b\x6b\x13\x51\x14\xfe\x32\x77\xf2\x6a\
+\x3a\x4d\x22\x48\x93\xd8\xa6\x69\xb4\x26\xad\xb6\x41\x5d\x88\x20\
+\xd8\x2e\x7c\x81\x15\x1f\x08\xe2\x3f\x10\xac\xbf\xc3\xfe\x01\xe9\
+\x5a\xb0\x5d\xb9\x74\xa3\x2e\x14\x41\x62\x10\x0a\x42\x63\x93\x91\
+\xd0\xe6\xd1\x36\xe9\x98\x64\xda\xbc\x27\xcd\xf5\xdc\xc1\x94\x6c\
+\x5c\x8a\x1f\x7c\xdc\x99\x7b\xee\xf9\xce\x77\xce\xbd\xf8\xef\xb0\
+\xf4\x3f\x22\x91\x08\x5b\x5d\x7d\x7d\x75\x74\x74\x74\xc1\x6e\x77\
+\x9c\x95\x24\xe9\x24\xc0\x87\x7a\xbd\x1e\x8e\x8e\x8e\x9a\x86\x61\
+\xec\xb7\xdb\xad\x74\xa5\x52\xf9\xb8\xb4\xf4\xfc\x73\x3c\xfe\xb5\
+\x8b\x3e\x96\x97\x5f\xf8\x93\x3f\x36\xe2\xa5\x52\x91\xb7\x5a\x2d\
+\xde\xe9\x74\xcc\xb5\xd1\x68\xf0\x5a\xad\xc6\x0f\x0e\x74\x5e\xad\
+\x96\xb9\xa6\x95\xf8\xee\x6e\x81\xab\x6a\xea\xdb\xca\xca\xcb\x31\
+\x10\x24\x10\x26\x27\x43\x4f\x95\x61\xe5\xb2\xd5\x6a\x1d\x30\xc7\
+\xc1\xb9\x60\xef\xd8\xac\xc5\x62\x81\x2c\xcb\x50\x14\xe5\xd2\xf8\
+\xf8\xf8\xb3\xbe\x80\xd5\xed\xf1\xdc\x10\x41\x01\xb2\x2c\x12\x4d\
+\x76\xbb\x5d\x61\xdf\xdc\x1b\x80\x29\xe4\xf1\xb8\xaf\x8b\x5c\x69\
+\x7e\xfe\x5a\xf0\x84\xd7\x7b\x71\x20\xfe\x27\x89\x83\xe6\x00\xc2\
+\xb1\xe0\x00\x48\xc0\x13\x5b\x5c\xbc\x73\x5a\xbe\x77\xff\xee\x03\
+\x2b\x41\x1c\x38\x3c\xac\x41\xd7\x0f\xcc\xca\xcd\x66\x13\xe5\x72\
+\x19\x36\x9b\x0d\x5e\xaf\x07\x8c\x31\xaa\x2c\x51\x0b\x0c\x76\xbb\
+\x8d\xfe\x65\x76\xeb\xf6\xcd\x87\x72\xa9\xf8\xeb\x82\xa6\x95\x21\
+\x48\x3a\xa6\xbd\xf5\xf5\x75\x6c\xa6\x36\x11\xf0\x07\x30\x11\x9a\
+\x80\xd1\x31\x10\x08\x04\x30\x32\x32\x22\xda\x31\x0b\xf4\x68\x36\
+\xfb\x25\x6d\x56\xde\xde\xde\x66\xf5\x7a\xdd\x4c\xa6\xe9\xa3\x50\
+\x28\x40\xfd\xa9\x62\x7a\x7a\x1a\xb9\xec\x0e\xde\xbf\xfb\x00\xbf\
+\xdf\x07\xba\x3e\xcc\xcc\xcc\xf4\xdb\x32\x45\xf2\xf9\x02\x98\xcf\
+\xe7\x7b\x44\xc1\x73\x99\x4c\x06\x82\xe9\x74\x1a\x7a\x55\x47\xa5\
+\xda\xc6\xe3\x27\x4b\x08\x06\xc7\xb0\xb6\xf6\x0a\x21\x72\x42\xce\
+\x44\xef\x94\x98\x37\x85\x52\xa9\xd4\x86\xec\x74\x3a\xf9\xdc\xdc\
+\x1c\xfa\x57\xa8\xaa\x2a\x12\x89\x04\xb4\x4a\x03\x6f\x3f\x7d\x41\
+\xad\xae\xc3\xe9\x52\x4c\xeb\xb1\x58\xcc\x5c\xdd\x6e\x37\xe8\x9d\
+\xa0\xdd\x6e\x83\x85\xc3\xe1\x00\x6d\x4c\x91\x80\xc2\x08\x22\xa8\
+\xeb\x3a\x72\xb9\x2d\xe4\xab\x74\xa8\x75\x88\x85\x2b\xb3\x18\x56\
+\x86\xe1\x70\x38\x84\x80\x48\x36\x34\x4d\xdb\xca\x66\xb3\x6f\x2c\
+\x00\x04\x5d\x64\x29\x18\x8d\x46\xcf\xd3\x53\x9e\x72\xb9\x5c\xa7\
+\xf6\x8a\x7b\x3e\x99\xc9\x67\x86\x5c\x43\x4d\x12\xcd\x30\x89\x55\
+\x48\x78\x87\x12\xd5\x64\x32\xf9\x9d\xaa\xe7\x00\xd4\x2d\xf8\x3b\
+\x24\xa2\x8d\xd8\x23\x1a\x44\x8e\x7f\x81\xdf\xa3\x70\x33\x35\x18\
+\x40\x99\x79\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\
+\x00\x00\x03\x41\
+\x89\
+\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
+\x00\x00\x10\x00\x00\x00\x10\x08\x03\x00\x00\x00\x28\x2d\x0f\x53\
+\x00\x00\x00\x01\x73\x52\x47\x42\x00\xae\xce\x1c\xe9\x00\x00\x00\
+\x09\x70\x48\x59\x73\x00\x00\x0d\xd7\x00\x00\x0d\xd7\x01\x42\x28\
+\x9b\x78\x00\x00\x00\x07\x74\x49\x4d\x45\x07\xda\x01\x16\x02\x14\
+\x1d\x79\x4f\xdb\xf8\x00\x00\x01\xa7\x50\x4c\x54\x45\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x02\x02\x02\x09\x09\x09\x09\x09\x09\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x02\x02\x02\x00\x00\x00\x01\x01\x01\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x02\x02\x02\x00\x00\x00\x30\x30\
+\x30\x00\x00\x00\x00\x00\x00\x3d\x3d\x3d\x00\x00\x00\x9a\x9a\x9a\
+\x10\x10\x10\x9b\x9b\x9b\x5d\x5e\x5e\x35\x36\x36\x80\x80\x81\xb0\
+\xae\xaf\xc5\xc5\xc6\xe9\xea\xea\xf1\xf1\xf1\x50\x52\x53\x51\x52\
+\x53\xfc\xfd\xff\xfd\xff\xff\xfe\xfe\xfe\x18\x18\x1a\x1c\x47\x9c\
+\x1d\x1e\x1f\x1f\x49\x9e\x2f\x56\xa4\x40\x70\xc3\x43\x71\xc4\x51\
+\x7d\xc9\x57\x8d\xe5\x59\x90\xe7\x67\x9d\xee\x74\x76\x78\x88\x9e\
+\xc8\x8a\x8b\x8d\x8a\x9f\xc9\x8d\x8d\x8e\x8d\x8d\x91\x8e\x8e\x8f\
+\x8e\xa3\xca\x90\x91\x92\x94\x95\x96\x96\x95\x97\x97\x99\x9b\x99\
+\x9a\x9b\x99\x9b\x9b\x9c\x9e\xa0\xaa\xab\xae\xcf\xd0\xd3\xd3\xd5\
+\xd9\xd6\xd5\xd2\xda\xdd\xdf\xdb\xde\xe1\xdd\xe1\xe3\xe0\xe2\xe5\
+\xe0\xe3\xe5\xe1\xe2\xe6\xe1\xe3\xe6\xe2\xe3\xe8\xe3\xe5\xe7\xe6\
+\xe8\xea\xe8\xe9\xea\xe8\xea\xec\xe8\xea\xed\xe8\xeb\xed\xe9\xea\
+\xee\xe9\xeb\xec\xea\xe8\xe4\xea\xeb\xee\xea\xed\xf3\xeb\xed\xee\
+\xeb\xee\xf5\xec\xed\xef\xec\xee\xef\xec\xef\xf5\xed\xee\xef\xed\
+\xef\xf2\xef\xf0\xf1\xef\xf1\xf1\xf0\xf2\xf2\xf1\xf1\xf1\xf1\xf2\
+\xf3\xf2\xf2\xf2\xf2\xf4\xf6\xf3\xf5\xf6\xf3\xf5\xf9\xf4\xf3\xf0\
+\xf4\xf4\xf5\xf4\xf5\xf6\xf4\xf5\xf7\xf4\xf6\xf7\xf5\xf3\xf1\xf5\
+\xf4\xf2\xf5\xf5\xf5\xf5\xf6\xf7\xf5\xf7\xf9\xf6\xf3\xf0\xf6\xf6\
+\xf7\xf6\xf8\xfa\xf7\xf7\xf8\xf8\xf9\xfa\xf8\xfa\xfc\xf9\xf7\xf4\
+\xf9\xfa\xfb\xf9\xfb\xfc\xfa\xfb\xfc\xfb\xfb\xfc\xfb\xfc\xfd\xfb\
+\xfd\xfd\xfb\xfd\xff\xfc\xfc\xfd\xfc\xfd\xff\xfd\xfd\xfe\xfd\xfe\
+\xff\xff\xff\xff\xd0\x32\x98\xa6\x00\x00\x00\x2f\x74\x52\x4e\x53\
+\x00\x01\x02\x03\x06\x08\x0d\x0f\x13\x1e\x24\x30\x33\x38\x3a\x3b\
+\x3c\x3f\x40\x46\x49\x4a\x4d\x53\x5b\x5d\x61\x63\x69\x6f\x6f\x73\
+\x91\x93\x96\x9f\xaa\xb8\xce\xde\xf2\xf7\xfe\xfe\xfe\xfe\xfe\xc1\
+\x92\xd1\x86\x00\x00\x00\x01\x62\x4b\x47\x44\x8c\x6c\x0b\xd2\x43\
+\x00\x00\x00\xd8\x49\x44\x41\x54\x18\xd3\x63\x60\x00\x02\x36\x05\
+\x25\x76\x06\x24\xc0\x22\xdd\xd3\x23\xc7\x8a\xe0\x33\x09\x68\xe8\
+\xe9\x69\x8a\x30\xc3\x05\xb8\xd4\x5a\x6a\x6b\x9b\xd5\xb9\x19\xa1\
+\x7c\x0e\xe5\xd6\x6c\x20\xa8\x53\xe5\x84\xf0\xf9\x14\xeb\x75\x13\
+\x80\x40\xa7\x47\x45\x84\x5f\x40\x80\x87\x41\xd4\x5e\x4b\xbf\x32\
+\x2c\xac\xd2\x50\xdb\xca\xa7\xa0\x34\x9f\x97\x41\x28\x2a\xc8\x35\
+\x3a\x20\x20\xc2\x23\x38\xd6\xc2\xd2\x3c\x5e\x90\x41\x38\x37\xcd\
+\x3b\xd0\xdf\xd7\xcf\x2b\xb2\xca\xc4\xcc\x34\x51\x98\x41\xac\xdd\
+\xc6\xc5\xc9\x33\x24\x34\x26\xae\xc1\xc0\xd8\x28\x45\x8c\x41\xbc\
+\xa6\xb8\xb8\x24\x3b\x35\x39\x29\xb9\xcc\xd6\xd1\xba\x46\x9c\x41\
+\xa2\x29\x3d\x3d\xa3\x22\x2f\xaf\xba\xa8\x28\x33\x27\xab\x4d\x82\
+\x41\xaa\x33\x3b\xbb\xd1\xc1\xcd\xdd\xce\xcd\x39\x3c\x3b\xbb\x5b\
+\x8a\x41\xa6\xa7\xb0\xb0\xbc\x03\x04\xba\xaa\x0b\x0b\x7b\x64\x18\
+\x64\x7b\x50\x80\x2c\x83\xa4\x3c\x0a\x90\x04\x00\x22\x75\x40\x01\
+\xd9\xb4\x9c\x69\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\
+\
\x00\x00\x03\x2d\
\x89\
\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
@@ -82563,57 +82683,15 @@
\x00\x6f\
\x00\x70\x00\x65\x00\x6e\x00\x6c\x00\x70\x00\x2d\x00\x73\x00\x70\x00\x6c\x00\x61\x00\x73\x00\x68\x00\x2d\x00\x73\x00\x63\x00\x72\
\x00\x65\x00\x65\x00\x6e\x00\x2e\x00\x70\x00\x6e\x00\x67\
-\x00\x12\
-\x07\x1e\x3d\x27\
-\x00\x67\
-\x00\x65\x00\x6e\x00\x65\x00\x72\x00\x61\x00\x6c\x00\x5f\x00\x64\x00\x65\x00\x6c\x00\x65\x00\x74\x00\x65\x00\x2e\x00\x70\x00\x6e\
-\x00\x67\
-\x00\x14\
-\x09\xd9\xa5\x67\
-\x00\x67\
-\x00\x65\x00\x6e\x00\x65\x00\x72\x00\x61\x00\x6c\x00\x5f\x00\x7a\x00\x6f\x00\x6f\x00\x6d\x00\x5f\x00\x6f\x00\x75\x00\x74\x00\x2e\
-\x00\x70\x00\x6e\x00\x67\
-\x00\x10\
-\x02\x1c\xed\x07\
-\x00\x67\
-\x00\x65\x00\x6e\x00\x65\x00\x72\x00\x61\x00\x6c\x00\x5f\x00\x65\x00\x64\x00\x69\x00\x74\x00\x2e\x00\x70\x00\x6e\x00\x67\
-\x00\x12\
-\x0d\x2d\xfb\x87\
-\x00\x67\
-\x00\x65\x00\x6e\x00\x65\x00\x72\x00\x61\x00\x6c\x00\x5f\x00\x65\x00\x78\x00\x70\x00\x6f\x00\x72\x00\x74\x00\x2e\x00\x70\x00\x6e\
-\x00\x67\
-\x00\x10\
-\x01\xdf\xeb\x47\
-\x00\x67\
-\x00\x65\x00\x6e\x00\x65\x00\x72\x00\x61\x00\x6c\x00\x5f\x00\x73\x00\x61\x00\x76\x00\x65\x00\x2e\x00\x70\x00\x6e\x00\x67\
-\x00\x10\
-\x0f\xda\xea\xa7\
-\x00\x67\
-\x00\x65\x00\x6e\x00\x65\x00\x72\x00\x61\x00\x6c\x00\x5f\x00\x6f\x00\x70\x00\x65\x00\x6e\x00\x2e\x00\x70\x00\x6e\x00\x67\
\x00\x0f\
\x0e\x36\xec\xe7\
\x00\x67\
\x00\x65\x00\x6e\x00\x65\x00\x72\x00\x61\x00\x6c\x00\x5f\x00\x61\x00\x64\x00\x64\x00\x2e\x00\x70\x00\x6e\x00\x67\
-\x00\x11\
-\x01\xec\x8b\x07\
-\x00\x67\
-\x00\x65\x00\x6e\x00\x65\x00\x72\x00\x61\x00\x6c\x00\x5f\x00\x70\x00\x72\x00\x69\x00\x6e\x00\x74\x00\x2e\x00\x70\x00\x6e\x00\x67\
-\
\x00\x19\
\x07\x4d\x72\x87\
\x00\x67\
\x00\x65\x00\x6e\x00\x65\x00\x72\x00\x61\x00\x6c\x00\x5f\x00\x7a\x00\x6f\x00\x6f\x00\x6d\x00\x5f\x00\x6f\x00\x72\x00\x69\x00\x67\
\x00\x69\x00\x6e\x00\x61\x00\x6c\x00\x2e\x00\x70\x00\x6e\x00\x67\
-\x00\x11\
-\x06\x44\xfc\x07\
-\x00\x67\
-\x00\x65\x00\x6e\x00\x65\x00\x72\x00\x61\x00\x6c\x00\x5f\x00\x65\x00\x6d\x00\x61\x00\x69\x00\x6c\x00\x2e\x00\x70\x00\x6e\x00\x67\
-\
-\x00\x13\
-\x0e\x30\xb8\x47\
-\x00\x67\
-\x00\x65\x00\x6e\x00\x65\x00\x72\x00\x61\x00\x6c\x00\x5f\x00\x7a\x00\x6f\x00\x6f\x00\x6d\x00\x5f\x00\x69\x00\x6e\x00\x2e\x00\x70\
-\x00\x6e\x00\x67\
\x00\x12\
\x0d\x2c\x6d\x87\
\x00\x67\
@@ -82624,25 +82702,75 @@
\x00\x67\
\x00\x65\x00\x6e\x00\x65\x00\x72\x00\x61\x00\x6c\x00\x5f\x00\x70\x00\x72\x00\x65\x00\x76\x00\x69\x00\x65\x00\x77\x00\x2e\x00\x70\
\x00\x6e\x00\x67\
-\x00\x10\
-\x09\xdf\xea\x07\
-\x00\x67\
-\x00\x65\x00\x6e\x00\x65\x00\x72\x00\x61\x00\x6c\x00\x5f\x00\x6c\x00\x69\x00\x76\x00\x65\x00\x2e\x00\x70\x00\x6e\x00\x67\
+\x00\x0f\
+\x0d\x5b\xec\x87\
+\x00\x67\
+\x00\x65\x00\x6e\x00\x65\x00\x72\x00\x61\x00\x6c\x00\x5f\x00\x6e\x00\x65\x00\x77\x00\x2e\x00\x70\x00\x6e\x00\x67\
+\x00\x12\
+\x07\x1e\x3d\x27\
+\x00\x67\
+\x00\x65\x00\x6e\x00\x65\x00\x72\x00\x61\x00\x6c\x00\x5f\x00\x64\x00\x65\x00\x6c\x00\x65\x00\x74\x00\x65\x00\x2e\x00\x70\x00\x6e\
+\x00\x67\
+\x00\x10\
+\x02\x1c\xed\x07\
+\x00\x67\
+\x00\x65\x00\x6e\x00\x65\x00\x72\x00\x61\x00\x6c\x00\x5f\x00\x65\x00\x64\x00\x69\x00\x74\x00\x2e\x00\x70\x00\x6e\x00\x67\
+\x00\x10\
+\x01\xdf\xeb\x47\
+\x00\x67\
+\x00\x65\x00\x6e\x00\x65\x00\x72\x00\x61\x00\x6c\x00\x5f\x00\x73\x00\x61\x00\x76\x00\x65\x00\x2e\x00\x70\x00\x6e\x00\x67\
+\x00\x13\
+\x0e\x30\xb8\x47\
+\x00\x67\
+\x00\x65\x00\x6e\x00\x65\x00\x72\x00\x61\x00\x6c\x00\x5f\x00\x7a\x00\x6f\x00\x6f\x00\x6d\x00\x5f\x00\x69\x00\x6e\x00\x2e\x00\x70\
+\x00\x6e\x00\x67\
\x00\x12\
\x07\x2b\x7c\xe7\
\x00\x67\
\x00\x65\x00\x6e\x00\x65\x00\x72\x00\x61\x00\x6c\x00\x5f\x00\x72\x00\x65\x00\x76\x00\x65\x00\x72\x00\x74\x00\x2e\x00\x70\x00\x6e\
\x00\x67\
-\x00\x0f\
-\x0d\x5b\xec\x87\
-\x00\x67\
-\x00\x65\x00\x6e\x00\x65\x00\x72\x00\x61\x00\x6c\x00\x5f\x00\x6e\x00\x65\x00\x77\x00\x2e\x00\x70\x00\x6e\x00\x67\
+\x00\x11\
+\x01\xec\x8b\x07\
+\x00\x67\
+\x00\x65\x00\x6e\x00\x65\x00\x72\x00\x61\x00\x6c\x00\x5f\x00\x70\x00\x72\x00\x69\x00\x6e\x00\x74\x00\x2e\x00\x70\x00\x6e\x00\x67\
+\
+\x00\x14\
+\x09\xd9\xa5\x67\
+\x00\x67\
+\x00\x65\x00\x6e\x00\x65\x00\x72\x00\x61\x00\x6c\x00\x5f\x00\x7a\x00\x6f\x00\x6f\x00\x6d\x00\x5f\x00\x6f\x00\x75\x00\x74\x00\x2e\
+\x00\x70\x00\x6e\x00\x67\
+\x00\x10\
+\x0f\xda\xea\xa7\
+\x00\x67\
+\x00\x65\x00\x6e\x00\x65\x00\x72\x00\x61\x00\x6c\x00\x5f\x00\x6f\x00\x70\x00\x65\x00\x6e\x00\x2e\x00\x70\x00\x6e\x00\x67\
\x00\x11\
\x07\xff\xf0\x07\
\x00\x67\
\x00\x65\x00\x6e\x00\x65\x00\x72\x00\x61\x00\x6c\x00\x5f\x00\x63\x00\x6c\x00\x6f\x00\x6e\x00\x65\x00\x2e\x00\x70\x00\x6e\x00\x67\
\
\x00\x10\
+\x0e\x89\xed\x67\
+\x00\x67\
+\x00\x65\x00\x6e\x00\x65\x00\x72\x00\x61\x00\x6c\x00\x5f\x00\x62\x00\x61\x00\x63\x00\x6b\x00\x2e\x00\x70\x00\x6e\x00\x67\
+\x00\x12\
+\x0d\x2d\xfb\x87\
+\x00\x67\
+\x00\x65\x00\x6e\x00\x65\x00\x72\x00\x61\x00\x6c\x00\x5f\x00\x65\x00\x78\x00\x70\x00\x6f\x00\x72\x00\x74\x00\x2e\x00\x70\x00\x6e\
+\x00\x67\
+\x00\x10\
+\x09\x5c\xed\xe7\
+\x00\x67\
+\x00\x65\x00\x6e\x00\x65\x00\x72\x00\x61\x00\x6c\x00\x5f\x00\x66\x00\x69\x00\x6e\x00\x64\x00\x2e\x00\x70\x00\x6e\x00\x67\
+\x00\x10\
+\x09\xdf\xea\x07\
+\x00\x67\
+\x00\x65\x00\x6e\x00\x65\x00\x72\x00\x61\x00\x6c\x00\x5f\x00\x6c\x00\x69\x00\x76\x00\x65\x00\x2e\x00\x70\x00\x6e\x00\x67\
+\x00\x11\
+\x06\x44\xfc\x07\
+\x00\x67\
+\x00\x65\x00\x6e\x00\x65\x00\x72\x00\x61\x00\x6c\x00\x5f\x00\x65\x00\x6d\x00\x61\x00\x69\x00\x6c\x00\x2e\x00\x70\x00\x6e\x00\x67\
+\
+\x00\x10\
\x03\x10\x21\x87\
\x00\x73\
\x00\x79\x00\x73\x00\x74\x00\x65\x00\x6d\x00\x5f\x00\x63\x00\x6c\x00\x6f\x00\x73\x00\x65\x00\x2e\x00\x70\x00\x6e\x00\x67\
@@ -82759,24 +82887,24 @@
qt_resource_struct = b"\
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x13\x00\x00\x00\x01\
-\x00\x00\x00\xe6\x00\x02\x00\x00\x00\x06\x00\x00\x00\x8c\
-\x00\x00\x00\x00\x00\x02\x00\x00\x00\x04\x00\x00\x00\x88\
-\x00\x00\x00\xb4\x00\x02\x00\x00\x00\x08\x00\x00\x00\x80\
-\x00\x00\x00\xd6\x00\x02\x00\x00\x00\x14\x00\x00\x00\x6c\
-\x00\x00\x00\x2c\x00\x02\x00\x00\x00\x02\x00\x00\x00\x6a\
-\x00\x00\x00\x14\x00\x02\x00\x00\x00\x02\x00\x00\x00\x68\
-\x00\x00\x01\x06\x00\x02\x00\x00\x00\x05\x00\x00\x00\x63\
-\x00\x00\x00\xf4\x00\x02\x00\x00\x00\x02\x00\x00\x00\x61\
-\x00\x00\x01\x40\x00\x02\x00\x00\x00\x09\x00\x00\x00\x58\
-\x00\x00\x00\x8c\x00\x02\x00\x00\x00\x0a\x00\x00\x00\x4e\
-\x00\x00\x00\xc4\x00\x02\x00\x00\x00\x03\x00\x00\x00\x4b\
-\x00\x00\x00\x3c\x00\x02\x00\x00\x00\x10\x00\x00\x00\x3b\
-\x00\x00\x00\x62\x00\x02\x00\x00\x00\x03\x00\x00\x00\x38\
-\x00\x00\x00\x78\x00\x02\x00\x00\x00\x01\x00\x00\x00\x37\
-\x00\x00\x01\x54\x00\x02\x00\x00\x00\x03\x00\x00\x00\x34\
-\x00\x00\x00\x9e\x00\x02\x00\x00\x00\x08\x00\x00\x00\x2c\
-\x00\x00\x01\x2c\x00\x02\x00\x00\x00\x01\x00\x00\x00\x2b\
-\x00\x00\x00\x4e\x00\x02\x00\x00\x00\x11\x00\x00\x00\x1a\
+\x00\x00\x00\xe6\x00\x02\x00\x00\x00\x06\x00\x00\x00\x8e\
+\x00\x00\x00\x00\x00\x02\x00\x00\x00\x04\x00\x00\x00\x8a\
+\x00\x00\x00\xb4\x00\x02\x00\x00\x00\x08\x00\x00\x00\x82\
+\x00\x00\x00\xd6\x00\x02\x00\x00\x00\x14\x00\x00\x00\x6e\
+\x00\x00\x00\x2c\x00\x02\x00\x00\x00\x02\x00\x00\x00\x6c\
+\x00\x00\x00\x14\x00\x02\x00\x00\x00\x02\x00\x00\x00\x6a\
+\x00\x00\x01\x06\x00\x02\x00\x00\x00\x05\x00\x00\x00\x65\
+\x00\x00\x00\xf4\x00\x02\x00\x00\x00\x02\x00\x00\x00\x63\
+\x00\x00\x01\x40\x00\x02\x00\x00\x00\x09\x00\x00\x00\x5a\
+\x00\x00\x00\x8c\x00\x02\x00\x00\x00\x0a\x00\x00\x00\x50\
+\x00\x00\x00\xc4\x00\x02\x00\x00\x00\x03\x00\x00\x00\x4d\
+\x00\x00\x00\x3c\x00\x02\x00\x00\x00\x10\x00\x00\x00\x3d\
+\x00\x00\x00\x62\x00\x02\x00\x00\x00\x03\x00\x00\x00\x3a\
+\x00\x00\x00\x78\x00\x02\x00\x00\x00\x01\x00\x00\x00\x39\
+\x00\x00\x01\x54\x00\x02\x00\x00\x00\x03\x00\x00\x00\x36\
+\x00\x00\x00\x9e\x00\x02\x00\x00\x00\x08\x00\x00\x00\x2e\
+\x00\x00\x01\x2c\x00\x02\x00\x00\x00\x01\x00\x00\x00\x2d\
+\x00\x00\x00\x4e\x00\x02\x00\x00\x00\x13\x00\x00\x00\x1a\
\x00\x00\x01\x18\x00\x02\x00\x00\x00\x06\x00\x00\x00\x14\
\x00\x00\x04\x5e\x00\x00\x00\x00\x00\x01\x00\x0a\xa7\x31\
\x00\x00\x03\x9c\x00\x00\x00\x00\x00\x01\x00\x00\x23\xa9\
@@ -82784,23 +82912,25 @@
\x00\x00\x04\x2c\x00\x00\x00\x00\x00\x01\x00\x08\x06\x4f\
\x00\x00\x03\xce\x00\x00\x00\x00\x00\x01\x00\x02\xc4\x8b\
\x00\x00\x04\x8e\x00\x00\x00\x00\x00\x01\x00\x0d\x48\x13\
-\x00\x00\x10\xae\x00\x00\x00\x00\x00\x01\x00\x13\x80\x7d\
-\x00\x00\x11\x1e\x00\x00\x00\x00\x00\x01\x00\x13\x87\xc8\
-\x00\x00\x10\x5e\x00\x00\x00\x00\x00\x01\x00\x13\x7b\x21\
-\x00\x00\x11\xfc\x00\x00\x00\x00\x00\x01\x00\x13\x9a\x46\
-\x00\x00\x11\x7e\x00\x00\x00\x00\x00\x01\x00\x13\x8f\xde\
+\x00\x00\x11\x2c\x00\x00\x00\x00\x00\x01\x00\x13\x88\xf3\
+\x00\x00\x11\xa8\x00\x00\x00\x00\x00\x01\x00\x13\x92\xba\
+\x00\x00\x11\x06\x00\x00\x00\x00\x00\x01\x00\x13\x86\x19\
+\x00\x00\x10\x8c\x00\x00\x00\x00\x00\x01\x00\x13\x7e\x01\
+\x00\x00\x12\xe8\x00\x00\x00\x00\x00\x01\x00\x13\xab\x88\
+\x00\x00\x10\xdc\x00\x00\x00\x00\x00\x01\x00\x13\x83\x7b\
+\x00\x00\x11\x7e\x00\x00\x00\x00\x00\x01\x00\x13\x8f\xd5\
+\x00\x00\x10\x2a\x00\x00\x00\x00\x00\x01\x00\x13\x76\xe7\
+\x00\x00\x12\x24\x00\x00\x00\x00\x00\x01\x00\x13\x9c\xde\
+\x00\x00\x12\x9c\x00\x00\x00\x00\x00\x01\x00\x13\xa5\x02\
+\x00\x00\x11\xd0\x00\x00\x00\x00\x00\x01\x00\x13\x96\x2e\
+\x00\x00\x12\xc2\x00\x00\x00\x00\x00\x01\x00\x13\xa8\xb4\
+\x00\x00\x10\x62\x00\x00\x00\x00\x00\x01\x00\x13\x7b\x89\
+\x00\x00\x12\x72\x00\x00\x00\x00\x00\x01\x00\x13\xa2\x80\
+\x00\x00\x10\xb8\x00\x00\x00\x00\x00\x01\x00\x13\x81\x34\
+\x00\x00\x11\x52\x00\x00\x00\x00\x00\x01\x00\x13\x8b\x2a\
\x00\x00\x10\x06\x00\x00\x00\x00\x00\x01\x00\x13\x73\xea\
-\x00\x00\x12\x4e\x00\x00\x00\x00\x00\x01\x00\x13\xa0\x4d\
-\x00\x00\x11\x46\x00\x00\x00\x00\x00\x01\x00\x13\x8b\x3c\
-\x00\x00\x12\x9c\x00\x00\x00\x00\x00\x01\x00\x13\xa5\x79\
-\x00\x00\x10\x30\x00\x00\x00\x00\x00\x01\x00\x13\x76\x88\
-\x00\x00\x12\x28\x00\x00\x00\x00\x00\x01\x00\x13\x9d\x79\
-\x00\x00\x11\xd2\x00\x00\x00\x00\x00\x01\x00\x13\x97\xce\
-\x00\x00\x10\x84\x00\x00\x00\x00\x00\x01\x00\x13\x7d\xfb\
-\x00\x00\x12\x78\x00\x00\x00\x00\x00\x01\x00\x13\xa3\x32\
-\x00\x00\x11\xa6\x00\x00\x00\x00\x00\x01\x00\x13\x93\x23\
-\x00\x00\x10\xfa\x00\x00\x00\x00\x00\x01\x00\x13\x84\xcb\
-\x00\x00\x10\xd4\x00\x00\x00\x00\x00\x01\x00\x13\x82\xb4\
+\x00\x00\x12\x4c\x00\x00\x00\x00\x00\x01\x00\x13\x9e\xf1\
+\x00\x00\x11\xfe\x00\x00\x00\x00\x00\x01\x00\x13\x9a\xc7\
\x00\x00\x03\x78\x00\x00\x00\x00\x00\x01\x00\x00\x21\x92\
\x00\x00\x0c\xc6\x00\x00\x00\x00\x00\x01\x00\x11\xf5\x62\
\x00\x00\x0d\x46\x00\x00\x00\x00\x00\x01\x00\x11\xfc\x28\
@@ -82817,22 +82947,22 @@
\x00\x00\x0f\x80\x00\x00\x00\x00\x00\x01\x00\x12\x1f\xab\
\x00\x00\x0f\xb0\x00\x00\x00\x00\x00\x01\x00\x12\x8e\x34\
\x00\x00\x0f\xd0\x00\x00\x00\x00\x00\x01\x00\x12\x94\xe5\
-\x00\x00\x13\x1e\x00\x00\x00\x00\x00\x01\x00\x13\xac\x8d\
-\x00\x00\x12\xc4\x00\x00\x00\x00\x00\x01\x00\x13\xa7\x8c\
-\x00\x00\x15\x3a\x00\x00\x00\x00\x00\x01\x00\x13\xd6\x92\
-\x00\x00\x13\xc4\x00\x00\x00\x00\x00\x01\x00\x13\xb4\x97\
-\x00\x00\x13\x60\x00\x00\x00\x00\x00\x01\x00\x13\xaf\xe0\
-\x00\x00\x12\xea\x00\x00\x00\x00\x00\x01\x00\x13\xaa\xbd\
-\x00\x00\x14\x8c\x00\x00\x00\x00\x00\x01\x00\x13\xc7\x6d\
-\x00\x00\x14\x2a\x00\x00\x00\x00\x00\x01\x00\x13\xbf\x3d\
-\x00\x00\x15\x60\x00\x00\x00\x00\x00\x01\x00\x13\xd9\x74\
-\x00\x00\x15\x06\x00\x00\x00\x00\x00\x01\x00\x13\xd2\xb5\
-\x00\x00\x14\x56\x00\x00\x00\x00\x00\x01\x00\x13\xc4\x49\
-\x00\x00\x15\x92\x00\x00\x00\x00\x00\x01\x00\x13\xdd\x31\
-\x00\x00\x14\xae\x00\x00\x00\x00\x00\x01\x00\x13\xcb\xdc\
-\x00\x00\x13\xf2\x00\x00\x00\x00\x00\x01\x00\x13\xbc\xc7\
-\x00\x00\x14\xdc\x00\x00\x00\x00\x00\x01\x00\x13\xd0\x2d\
-\x00\x00\x13\x8e\x00\x00\x00\x00\x00\x01\x00\x13\xb1\xe7\
+\x00\x00\x13\x6a\x00\x00\x00\x00\x00\x01\x00\x13\xb3\xce\
+\x00\x00\x13\x10\x00\x00\x00\x00\x00\x01\x00\x13\xae\xcd\
+\x00\x00\x15\x86\x00\x00\x00\x00\x00\x01\x00\x13\xdd\xd3\
+\x00\x00\x14\x10\x00\x00\x00\x00\x00\x01\x00\x13\xbb\xd8\
+\x00\x00\x13\xac\x00\x00\x00\x00\x00\x01\x00\x13\xb7\x21\
+\x00\x00\x13\x36\x00\x00\x00\x00\x00\x01\x00\x13\xb1\xfe\
+\x00\x00\x14\xd8\x00\x00\x00\x00\x00\x01\x00\x13\xce\xae\
+\x00\x00\x14\x76\x00\x00\x00\x00\x00\x01\x00\x13\xc6\x7e\
+\x00\x00\x15\xac\x00\x00\x00\x00\x00\x01\x00\x13\xe0\xb5\
+\x00\x00\x15\x52\x00\x00\x00\x00\x00\x01\x00\x13\xd9\xf6\
+\x00\x00\x14\xa2\x00\x00\x00\x00\x00\x01\x00\x13\xcb\x8a\
+\x00\x00\x15\xde\x00\x00\x00\x00\x00\x01\x00\x13\xe4\x72\
+\x00\x00\x14\xfa\x00\x00\x00\x00\x00\x01\x00\x13\xd3\x1d\
+\x00\x00\x14\x3e\x00\x00\x00\x00\x00\x01\x00\x13\xc4\x08\
+\x00\x00\x15\x28\x00\x00\x00\x00\x00\x01\x00\x13\xd7\x6e\
+\x00\x00\x13\xda\x00\x00\x00\x00\x00\x01\x00\x13\xb9\x28\
\x00\x00\x0a\xa6\x00\x00\x00\x00\x00\x01\x00\x11\x96\x51\
\x00\x00\x0a\xc6\x00\x00\x00\x00\x00\x01\x00\x11\x9a\x2e\
\x00\x00\x0a\x80\x00\x00\x00\x00\x00\x01\x00\x11\x93\xb3\
@@ -82862,10 +82992,10 @@
\x00\x00\x05\x06\x00\x00\x00\x00\x00\x01\x00\x0f\xf0\xe8\
\x00\x00\x05\xa0\x00\x00\x00\x00\x00\x01\x00\x0f\xf7\x01\
\x00\x00\x05\x6e\x00\x00\x00\x00\x00\x01\x00\x0f\xf5\x39\
-\x00\x00\x15\xfa\x00\x00\x00\x00\x00\x01\x00\x13\xe6\x65\
-\x00\x00\x16\x2e\x00\x00\x00\x00\x00\x01\x00\x13\xe9\x35\
-\x00\x00\x15\xb6\x00\x00\x00\x00\x00\x01\x00\x13\xe0\xe4\
-\x00\x00\x15\xda\x00\x00\x00\x00\x00\x01\x00\x13\xe3\xe2\
+\x00\x00\x16\x46\x00\x00\x00\x00\x00\x01\x00\x13\xed\xa6\
+\x00\x00\x16\x7a\x00\x00\x00\x00\x00\x01\x00\x13\xf0\x76\
+\x00\x00\x16\x02\x00\x00\x00\x00\x00\x01\x00\x13\xe8\x25\
+\x00\x00\x16\x26\x00\x00\x00\x00\x00\x01\x00\x13\xeb\x23\
\x00\x00\x07\x7c\x00\x00\x00\x00\x00\x01\x00\x11\x54\x8c\
\x00\x00\x08\x5a\x00\x00\x00\x00\x00\x01\x00\x11\x64\xdc\
\x00\x00\x0a\x60\x00\x00\x00\x00\x00\x01\x00\x11\x8f\xc0\
@@ -82894,10 +83024,10 @@
\x00\x00\x0c\x26\x00\x00\x00\x00\x00\x01\x00\x11\xe7\x77\
\x00\x00\x0a\xe8\x00\x00\x00\x00\x00\x01\x00\x11\x9d\x68\
\x00\x00\x0b\xb0\x00\x00\x00\x00\x00\x01\x00\x11\xda\x3c\
-\x00\x00\x16\x5e\x00\x00\x00\x00\x00\x01\x00\x13\xec\x2e\
-\x00\x00\x16\xc0\x00\x00\x00\x00\x00\x01\x00\x13\xf2\xa4\
-\x00\x00\x16\x92\x00\x00\x00\x00\x00\x01\x00\x13\xef\x90\
-\x00\x00\x16\xe8\x00\x00\x00\x00\x00\x01\x00\x13\xf5\x42\
+\x00\x00\x16\xaa\x00\x00\x00\x00\x00\x01\x00\x13\xf3\x6f\
+\x00\x00\x17\x0c\x00\x00\x00\x00\x00\x01\x00\x13\xf9\xe5\
+\x00\x00\x16\xde\x00\x00\x00\x00\x00\x01\x00\x13\xf6\xd1\
+\x00\x00\x17\x34\x00\x00\x00\x00\x00\x01\x00\x13\xfc\x83\
\x00\x00\x06\xb6\x00\x00\x00\x00\x00\x01\x00\x10\x3b\xad\
\x00\x00\x06\x56\x00\x00\x00\x00\x00\x01\x00\x10\x0c\x6d\
\x00\x00\x06\x26\x00\x00\x00\x00\x00\x01\x00\x10\x01\xd9\
=== modified file 'openlp/core/ui/__init__.py'
--- openlp/core/ui/__init__.py 2013-12-31 20:29:03 +0000
+++ openlp/core/ui/__init__.py 2014-03-11 19:13:15 +0000
@@ -29,6 +29,7 @@
"""
The :mod:`ui` module provides the core user interface for OpenLP
"""
+from PyQt4 import QtGui
class HideMode(object):
@@ -77,6 +78,29 @@
Plugin = 2
+class SingleColumnTableWidget(QtGui.QTableWidget):
+ """
+ Class to for a single column table widget to use for the verse table widget.
+ """
+
+ def __init__(self, parent):
+ """
+ Constructor
+ """
+ super(SingleColumnTableWidget, self).__init__(parent)
+ self.horizontalHeader().setVisible(False)
+ self.setColumnCount(1)
+
+ def resizeEvent(self, event):
+ """
+ Resize the first column together with the widget.
+ """
+ QtGui.QTableWidget.resizeEvent(self, event)
+ if self.columnCount():
+ self.setColumnWidth(0, event.size().width())
+ self.resizeRowsToContents()
+
+
from .firsttimeform import FirstTimeForm
from .firsttimelanguageform import FirstTimeLanguageForm
from .themelayoutform import ThemeLayoutForm
@@ -101,8 +125,8 @@
from .servicemanager import ServiceManager
from .thememanager import ThemeManager
-__all__ = ['SplashScreen', 'AboutForm', 'SettingsForm', 'MainDisplay', 'SlideController', 'ServiceManager',
- 'ThemeManager', 'MediaDockManager', 'ServiceItemEditForm', 'FirstTimeForm', 'FirstTimeLanguageForm', 'ThemeForm',
- 'ThemeLayoutForm', 'FileRenameForm', 'StartTimeForm', 'MainDisplay', 'Display', 'ServiceNoteForm',
- 'SlideController', 'DisplayController', 'GeneralTab', 'ThemesTab', 'AdvancedTab', 'PluginForm',
- 'FormattingTagForm', 'ShortcutListForm', 'FormattingTagController']
+__all__ = ['SplashScreen', 'AboutForm', 'SettingsForm', 'MainDisplay', 'SlideController', 'ServiceManager', 'ThemeForm',
+ 'ThemeManager', 'MediaDockManager', 'ServiceItemEditForm', 'FirstTimeForm', 'FirstTimeLanguageForm',
+ 'Display', 'ServiceNoteForm', 'ThemeLayoutForm', 'FileRenameForm', 'StartTimeForm', 'MainDisplay',
+ 'SlideController', 'DisplayController', 'GeneralTab', 'ThemesTab', 'AdvancedTab', 'PluginForm',
+ 'FormattingTagForm', 'ShortcutListForm', 'FormattingTagController', 'SingleColumnTableWidget']
=== modified file 'openlp/core/ui/mainwindow.py'
--- openlp/core/ui/mainwindow.py 2014-02-23 15:41:09 +0000
+++ openlp/core/ui/mainwindow.py 2014-03-11 19:13:15 +0000
@@ -119,8 +119,10 @@
self.recent_files_menu = QtGui.QMenu(self.file_menu)
self.recent_files_menu.setObjectName('recentFilesMenu')
self.file_import_menu = QtGui.QMenu(self.file_menu)
+ self.file_import_menu.setIcon(build_icon(u':/general/general_import.png'))
self.file_import_menu.setObjectName('file_import_menu')
self.file_export_menu = QtGui.QMenu(self.file_menu)
+ self.file_export_menu.setIcon(build_icon(u':/general/general_export.png'))
self.file_export_menu.setObjectName('file_export_menu')
# View Menu
self.view_menu = QtGui.QMenu(self.menu_bar)
@@ -230,7 +232,7 @@
main_window, 'modeDefaultItem', checked=False, category=UiStrings().ViewMode, can_shortcuts=True)
self.mode_setup_item = create_action(main_window, 'modeSetupItem', checked=False, category=UiStrings().ViewMode,
can_shortcuts=True)
- self.mode_live_item = create_action(main_window, 'modeLiveItem', checked=True, category=UiStrings().ViewMode,
+ self.mode_live_item = create_action(main_window, 'modeLiveItem', checked=True, category=UiStrings().ViewMode,
can_shortcuts=True)
self.mode_group = QtGui.QActionGroup(main_window)
self.mode_group.addAction(self.mode_default_item)
@@ -239,10 +241,10 @@
self.mode_default_item.setChecked(True)
action_list.add_category(UiStrings().Tools, CategoryOrder.standard_menu)
self.tools_add_tool_item = create_action(main_window,
- 'toolsAddToolItem', icon=':/tools/tools_add.png',
+ 'toolsAddToolItem', icon=':/tools/tools_add.png',
category=UiStrings().Tools, can_shortcuts=True)
self.tools_open_data_folder = create_action(main_window,
- 'toolsOpenDataFolder', icon=':/general/general_open.png',
+ 'toolsOpenDataFolder', icon=':/general/general_open.png',
category=UiStrings().Tools, can_shortcuts=True)
self.tools_first_time_wizard = create_action(main_window,
'toolsFirstTimeWizard', icon=':/general/general_revert.png',
@@ -268,24 +270,24 @@
language_item = create_action(main_window, key, checked=qm_list[key] == saved_language)
add_actions(self.language_group, [language_item])
self.settings_shortcuts_item = create_action(main_window, 'settingsShortcutsItem',
- icon=':/system/system_configure_shortcuts.png',
+ icon=':/system/system_configure_shortcuts.png',
category=UiStrings().Settings, can_shortcuts=True)
# Formatting Tags were also known as display tags.
self.formatting_tag_item = create_action(main_window, 'displayTagItem',
- icon=':/system/tag_editor.png', category=UiStrings().Settings,
+ icon=':/system/tag_editor.png', category=UiStrings().Settings,
can_shortcuts=True)
self.settings_configure_item = create_action(main_window, 'settingsConfigureItem',
- icon=':/system/system_settings.png', can_shortcuts=True,
+ icon=':/system/system_settings.png', can_shortcuts=True,
category=UiStrings().Settings)
# Give QT Extra Hint that this is the Preferences Menu Item
self.settings_configure_item.setMenuRole(QtGui.QAction.PreferencesRole)
- self.settings_import_item = create_action(main_window, 'settingsImportItem',
+ self.settings_import_item = create_action(main_window, 'settingsImportItem',
category=UiStrings().Import, can_shortcuts=True)
- self.settings_export_item = create_action(main_window, 'settingsExportItem',
+ self.settings_export_item = create_action(main_window, 'settingsExportItem',
category=UiStrings().Export, can_shortcuts=True)
action_list.add_category(UiStrings().Help, CategoryOrder.standard_menu)
self.about_item = create_action(main_window, 'aboutItem', icon=':/system/system_about.png',
- can_shortcuts=True, category=UiStrings().Help,
+ can_shortcuts=True, category=UiStrings().Help,
triggers=self.on_about_item_clicked)
# Give QT Extra Hint that this is an About Menu Item
self.about_item.setMenuRole(QtGui.QAction.AboutRole)
@@ -302,13 +304,13 @@
self.web_site_item = create_action(main_window, 'webSiteItem', can_shortcuts=True, category=UiStrings().Help)
# Shortcuts not connected to buttons or menu entries.
self.search_shortcut_action = create_action(main_window,
- 'searchShortcut', can_shortcuts=True,
+ 'searchShortcut', can_shortcuts=True,
category=translate('OpenLP.MainWindow', 'General'),
triggers=self.on_search_shortcut_triggered)
- add_actions(self.file_import_menu, (self.settings_import_item, None, self.import_theme_item,
- self.import_language_item))
- add_actions(self.file_export_menu, (self.settings_export_item, None, self.export_theme_item,
- self.export_language_item))
+ add_actions(self.file_import_menu, (self.settings_import_item, self.import_theme_item,
+ self.import_language_item, None))
+ add_actions(self.file_export_menu, (self.settings_export_item, self.export_theme_item,
+ self.export_language_item, None))
add_actions(self.file_menu, (self.file_new_item, self.file_open_item,
self.file_save_item, self.file_save_as_item, self.recent_files_menu.menuAction(), None,
self.file_import_menu.menuAction(), self.file_export_menu.menuAction(), None,
@@ -651,7 +653,7 @@
'Time Wizard?\n\nRe-running this wizard may make changes to your '
'current OpenLP configuration and possibly add songs to your '
'#existing songs list and change your default theme.'),
- QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Yes |
+ QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Yes |
QtGui.QMessageBox.No),
QtGui.QMessageBox.No)
if answer == QtGui.QMessageBox.No:
=== modified file 'openlp/plugins/songs/forms/editsongdialog.py'
--- openlp/plugins/songs/forms/editsongdialog.py 2014-03-04 18:49:30 +0000
+++ openlp/plugins/songs/forms/editsongdialog.py 2014-03-11 19:13:15 +0000
@@ -32,6 +32,7 @@
from openlp.core.common import UiStrings, translate
from openlp.core.lib import build_icon
from openlp.core.lib.ui import create_button_box, create_button
+from openlp.core.ui import SingleColumnTableWidget
from openlp.plugins.songs.lib.ui import SongStrings
@@ -346,25 +347,3 @@
combo_box.setInsertPolicy(QtGui.QComboBox.NoInsert)
combo_box.setObjectName(name)
return combo_box
-
-
-class SingleColumnTableWidget(QtGui.QTableWidget):
- """
- Class to for a single column table widget to use for the verse table widget.
- """
- def __init__(self, parent):
- """
- Constructor
- """
- super(SingleColumnTableWidget, self).__init__(parent)
- self.horizontalHeader().setVisible(False)
- self.setColumnCount(1)
-
- def resizeEvent(self, event):
- """
- Resize the first column together with the widget.
- """
- QtGui.QTableWidget.resizeEvent(self, event)
- if self.columnCount():
- self.setColumnWidth(0, event.size().width())
- self.resizeRowsToContents()
=== added file 'openlp/plugins/songs/forms/songselectdialog.py'
--- openlp/plugins/songs/forms/songselectdialog.py 1970-01-01 00:00:00 +0000
+++ openlp/plugins/songs/forms/songselectdialog.py 2014-03-11 19:13:15 +0000
@@ -0,0 +1,252 @@
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
+
+###############################################################################
+# OpenLP - Open Source Lyrics Projection #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2014 Raoul Snyman #
+# Portions copyright (c) 2008-2014 Tim Bentley, Gerald Britton, Jonathan #
+# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
+# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
+# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
+# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
+# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, #
+# Frode Woldsund, Martin Zibricky, Patrick Zimmermann #
+# --------------------------------------------------------------------------- #
+# This program is free software; you can redistribute it and/or modify it #
+# under the terms of the GNU General Public License as published by the Free #
+# Software Foundation; version 2 of the License. #
+# #
+# This program is distributed in the hope that it will be useful, but WITHOUT #
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
+# more details. #
+# #
+# You should have received a copy of the GNU General Public License along #
+# with this program; if not, write to the Free Software Foundation, Inc., 59 #
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
+###############################################################################
+"""
+The :mod:`~openlp.plugins.songs.forms.songselectdialog` module contains the user interface code for the dialog
+"""
+
+from PyQt4 import QtCore, QtGui
+
+from openlp.core.common import HistoryComboBox
+from openlp.core.lib import translate, build_icon
+from openlp.core.ui import SingleColumnTableWidget
+
+
+class Ui_SongSelectDialog(object):
+ """
+ The actual Qt components that make up the dialog.
+ """
+ def setup_ui(self, songselect_dialog):
+ songselect_dialog.setObjectName('songselect_dialog')
+ songselect_dialog.resize(616, 378)
+ self.songselect_layout = QtGui.QVBoxLayout(songselect_dialog)
+ self.songselect_layout.setSpacing(0)
+ self.songselect_layout.setMargin(0)
+ self.songselect_layout.setObjectName('songselect_layout')
+ self.stacked_widget = QtGui.QStackedWidget(songselect_dialog)
+ self.stacked_widget.setObjectName('stacked_widget')
+ self.login_page = QtGui.QWidget()
+ self.login_page.setObjectName('login_page')
+ self.login_layout = QtGui.QFormLayout(self.login_page)
+ self.login_layout.setContentsMargins(120, 100, 120, 100)
+ self.login_layout.setSpacing(8)
+ self.login_layout.setObjectName('login_layout')
+ self.notice_layout = QtGui.QHBoxLayout()
+ self.notice_layout.setObjectName('notice_layout')
+ self.notice_label = QtGui.QLabel(self.login_page)
+ self.notice_label.setWordWrap(True)
+ self.notice_label.setObjectName('notice_label')
+ self.notice_layout.addWidget(self.notice_label)
+ self.login_layout.setLayout(0, QtGui.QFormLayout.SpanningRole, self.notice_layout)
+ self.username_label = QtGui.QLabel(self.login_page)
+ self.username_label.setObjectName('usernameLabel')
+ self.login_layout.setWidget(1, QtGui.QFormLayout.LabelRole, self.username_label)
+ self.username_edit = QtGui.QLineEdit(self.login_page)
+ self.username_edit.setObjectName('usernameEdit')
+ self.login_layout.setWidget(1, QtGui.QFormLayout.FieldRole, self.username_edit)
+ self.password_label = QtGui.QLabel(self.login_page)
+ self.password_label.setObjectName('passwordLabel')
+ self.login_layout.setWidget(2, QtGui.QFormLayout.LabelRole, self.password_label)
+ self.password_edit = QtGui.QLineEdit(self.login_page)
+ self.password_edit.setEchoMode(QtGui.QLineEdit.Password)
+ self.password_edit.setObjectName('passwordEdit')
+ self.login_layout.setWidget(2, QtGui.QFormLayout.FieldRole, self.password_edit)
+ self.save_password_checkbox = QtGui.QCheckBox(self.login_page)
+ self.save_password_checkbox.setTristate(False)
+ self.save_password_checkbox.setObjectName('save_password_checkbox')
+ self.login_layout.setWidget(3, QtGui.QFormLayout.FieldRole, self.save_password_checkbox)
+ self.login_button_layout = QtGui.QHBoxLayout()
+ self.login_button_layout.setSpacing(8)
+ self.login_button_layout.setContentsMargins(0, -1, -1, -1)
+ self.login_button_layout.setObjectName('login_button_layout')
+ self.login_spacer = QtGui.QWidget(self.login_page)
+ self.login_spacer.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
+ self.login_spacer.setObjectName('login_spacer')
+ self.login_button_layout.addWidget(self.login_spacer)
+ self.login_progress_bar = QtGui.QProgressBar(self.login_page)
+ self.login_progress_bar.setMinimum(0)
+ self.login_progress_bar.setMaximum(3)
+ self.login_progress_bar.setValue(0)
+ self.login_progress_bar.setMinimumWidth(200)
+ self.login_progress_bar.setVisible(False)
+ self.login_button_layout.addWidget(self.login_progress_bar)
+ self.login_button = QtGui.QPushButton(self.login_page)
+ self.login_button.setIcon(build_icon(':/songs/song_author_edit.png'))
+ self.login_button.setObjectName('login_button')
+ self.login_button_layout.addWidget(self.login_button)
+ self.login_layout.setLayout(4, QtGui.QFormLayout.SpanningRole, self.login_button_layout)
+ self.stacked_widget.addWidget(self.login_page)
+ self.search_page = QtGui.QWidget()
+ self.search_page.setObjectName('search_page')
+ self.search_layout = QtGui.QVBoxLayout(self.search_page)
+ self.search_layout.setSpacing(8)
+ self.search_layout.setMargin(8)
+ self.search_layout.setObjectName('search_layout')
+ self.search_input_layout = QtGui.QHBoxLayout()
+ self.search_input_layout.setSpacing(8)
+ self.search_input_layout.setObjectName('search_input_layout')
+ self.search_label = QtGui.QLabel(self.search_page)
+ self.search_label.setObjectName('search_label')
+ self.search_input_layout.addWidget(self.search_label)
+ self.search_combobox = HistoryComboBox(self.search_page)
+ self.search_combobox.setObjectName('search_combobox')
+ self.search_input_layout.addWidget(self.search_combobox)
+ self.search_button = QtGui.QPushButton(self.search_page)
+ self.search_button.setIcon(build_icon(':/general/general_find.png'))
+ self.search_button.setObjectName('search_button')
+ self.search_input_layout.addWidget(self.search_button)
+ self.search_layout.addLayout(self.search_input_layout)
+ self.search_progress_bar = QtGui.QProgressBar(self.search_page)
+ self.search_progress_bar.setMinimum(0)
+ self.search_progress_bar.setMaximum(3)
+ self.search_progress_bar.setValue(0)
+ self.search_progress_bar.setVisible(False)
+ self.search_layout.addWidget(self.search_progress_bar)
+ self.search_results_widget = QtGui.QListWidget(self.search_page)
+ self.search_results_widget.setProperty("showDropIndicator", False)
+ self.search_results_widget.setAlternatingRowColors(True)
+ self.search_results_widget.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
+ self.search_results_widget.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
+ self.search_results_widget.setObjectName('search_results_widget')
+ self.search_layout.addWidget(self.search_results_widget)
+ self.result_count_label = QtGui.QLabel(self.search_page)
+ self.result_count_label.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignCenter)
+ self.result_count_label.setObjectName('result_count_label')
+ self.search_layout.addWidget(self.result_count_label)
+ self.view_layout = QtGui.QHBoxLayout()
+ self.view_layout.setSpacing(8)
+ self.view_layout.setObjectName('view_layout')
+ self.logout_button = QtGui.QPushButton(self.search_page)
+ self.logout_button.setIcon(build_icon(':/songs/song_author_edit.png'))
+ self.view_layout.addWidget(self.logout_button)
+ self.view_spacer = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
+ self.view_layout.addItem(self.view_spacer)
+ self.view_button = QtGui.QPushButton(self.search_page)
+ self.view_button.setIcon(build_icon(':/songs/song_search_all.png'))
+ self.view_button.setObjectName('view_button')
+ self.view_layout.addWidget(self.view_button)
+ self.search_layout.addLayout(self.view_layout)
+ self.stacked_widget.addWidget(self.search_page)
+ self.song_page = QtGui.QWidget()
+ self.song_page.setObjectName('song_page')
+ self.song_layout = QtGui.QGridLayout(self.song_page)
+ self.song_layout.setMargin(8)
+ self.song_layout.setSpacing(8)
+ self.song_layout.setObjectName('song_layout')
+ self.title_label = QtGui.QLabel(self.song_page)
+ self.title_label.setObjectName('title_label')
+ self.song_layout.addWidget(self.title_label, 0, 0, 1, 1)
+ self.title_edit = QtGui.QLineEdit(self.song_page)
+ self.title_edit.setReadOnly(True)
+ self.title_edit.setObjectName('title_edit')
+ self.song_layout.addWidget(self.title_edit, 0, 1, 1, 1)
+ self.authors_label = QtGui.QLabel(self.song_page)
+ self.authors_label.setObjectName('authors_label')
+ self.song_layout.addWidget(self.authors_label, 0, 2, 1, 1)
+ self.author_list_widget = QtGui.QListWidget(self.song_page)
+ self.author_list_widget.setObjectName('author_list_widget')
+ self.song_layout.addWidget(self.author_list_widget, 0, 3, 3, 1)
+ self.copyright_label = QtGui.QLabel(self.song_page)
+ self.copyright_label.setObjectName('copyright_label')
+ self.song_layout.addWidget(self.copyright_label, 1, 0, 1, 1)
+ self.copyright_edit = QtGui.QLineEdit(self.song_page)
+ self.copyright_edit.setReadOnly(True)
+ self.copyright_edit.setObjectName('copyright_edit')
+ self.song_layout.addWidget(self.copyright_edit, 1, 1, 1, 1)
+ self.ccli_label = QtGui.QLabel(self.song_page)
+ self.ccli_label.setObjectName('ccli_label')
+ self.song_layout.addWidget(self.ccli_label, 2, 0, 1, 1)
+ self.ccli_edit = QtGui.QLineEdit(self.song_page)
+ self.ccli_edit.setReadOnly(True)
+ self.ccli_edit.setObjectName('ccli_edit')
+ self.song_layout.addWidget(self.ccli_edit, 2, 1, 1, 1)
+ self.lyrics_label = QtGui.QLabel(self.song_page)
+ self.lyrics_label.setAlignment(QtCore.Qt.AlignLeading | QtCore.Qt.AlignLeft | QtCore.Qt.AlignTop)
+ self.lyrics_label.setObjectName('lyrics_label')
+ self.song_layout.addWidget(self.lyrics_label, 3, 0, 1, 1)
+ self.lyrics_table_widget = SingleColumnTableWidget(self.song_page)
+ self.lyrics_table_widget.setObjectName('lyrics_table_widget')
+ self.lyrics_table_widget.setRowCount(0)
+ self.song_layout.addWidget(self.lyrics_table_widget, 3, 1, 1, 3)
+ self.song_progress_bar = QtGui.QProgressBar(self.song_page)
+ self.song_progress_bar.setMinimum(0)
+ self.song_progress_bar.setMaximum(3)
+ self.song_progress_bar.setValue(0)
+ self.song_progress_bar.setVisible(False)
+ self.song_layout.addWidget(self.song_progress_bar, 4, 0, 1, 4)
+ self.import_layout = QtGui.QHBoxLayout()
+ self.import_layout.setObjectName('import_layout')
+ self.back_button = QtGui.QPushButton(self.song_page)
+ self.back_button.setIcon(build_icon(':/general/general_back.png'))
+ self.back_button.setObjectName('back_button')
+ self.import_layout.addWidget(self.back_button)
+ self.import_spacer = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
+ self.import_layout.addItem(self.import_spacer)
+ self.import_button = QtGui.QPushButton(self.song_page)
+ self.import_button.setIcon(build_icon(':/general/general_import.png'))
+ self.import_button.setObjectName('import_button')
+ self.import_layout.addWidget(self.import_button)
+ self.song_layout.addLayout(self.import_layout, 5, 0, 1, 5)
+ self.stacked_widget.addWidget(self.song_page)
+ self.songselect_layout.addWidget(self.stacked_widget)
+ self.username_label.setBuddy(self.username_edit)
+ self.password_label.setBuddy(self.password_edit)
+ self.title_label.setBuddy(self.title_edit)
+ self.authors_label.setBuddy(self.author_list_widget)
+ self.copyright_label.setBuddy(self.copyright_edit)
+ self.ccli_label.setBuddy(self.ccli_edit)
+ self.lyrics_label.setBuddy(self.lyrics_table_widget)
+
+ self.retranslate_ui(songselect_dialog)
+ self.stacked_widget.setCurrentIndex(0)
+
+ def retranslate_ui(self, songselect_dialog):
+ """
+ Translate the GUI.
+ """
+ songselect_dialog.setWindowTitle(translate('SongsPlugin.SongSelectForm', 'CCLI SongSelect Importer'))
+ self.notice_label.setText(
+ translate('SongsPlugin.SongSelectForm', '<strong>Note:</strong> '
+ 'An Internet connection is required in order to import songs from CCLI SongSelect.')
+ )
+ self.username_label.setText(translate('SongsPlugin.SongSelectForm', 'Username:'))
+ self.password_label.setText(translate('SongsPlugin.SongSelectForm', 'Password:'))
+ self.save_password_checkbox.setText(translate('SongsPlugin.SongSelectForm', 'Save username and password'))
+ self.login_button.setText(translate('SongsPlugin.SongSelectForm', 'Login'))
+ self.search_label.setText(translate('SongsPlugin.SongSelectForm', 'Search Text:'))
+ self.search_button.setText(translate('SongsPlugin.SongSelectForm', 'Search'))
+ self.result_count_label.setText(translate('SongsPlugin.SongSelectForm', 'Found %s song(s)') % 0)
+ self.logout_button.setText(translate('SongsPlugin.SongSelectForm', 'Logout'))
+ self.view_button.setText(translate('SongsPlugin.SongSelectForm', 'View'))
+ self.title_label.setText(translate('SongsPlugin.SongSelectForm', 'Title:'))
+ self.authors_label.setText(translate('SongsPlugin.SongSelectForm', 'Author(s):'))
+ self.copyright_label.setText(translate('SongsPlugin.SongSelectForm', 'Copyright:'))
+ self.ccli_label.setText(translate('SongsPlugin.SongSelectForm', 'CCLI Number:'))
+ self.lyrics_label.setText(translate('SongsPlugin.SongSelectForm', 'Lyrics:'))
+ self.back_button.setText(translate('SongsPlugin.SongSelectForm', 'Back'))
+ self.import_button.setText(translate('SongsPlugin.SongSelectForm', 'Import'))
=== added file 'openlp/plugins/songs/forms/songselectform.py'
--- openlp/plugins/songs/forms/songselectform.py 1970-01-01 00:00:00 +0000
+++ openlp/plugins/songs/forms/songselectform.py 2014-03-11 19:13:15 +0000
@@ -0,0 +1,387 @@
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
+
+###############################################################################
+# OpenLP - Open Source Lyrics Projection #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2014 Raoul Snyman #
+# Portions copyright (c) 2008-2014 Tim Bentley, Gerald Britton, Jonathan #
+# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
+# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
+# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
+# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
+# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, #
+# Frode Woldsund, Martin Zibricky, Patrick Zimmermann #
+# --------------------------------------------------------------------------- #
+# This program is free software; you can redistribute it and/or modify it #
+# under the terms of the GNU General Public License as published by the Free #
+# Software Foundation; version 2 of the License. #
+# #
+# This program is distributed in the hope that it will be useful, but WITHOUT #
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
+# more details. #
+# #
+# You should have received a copy of the GNU General Public License along #
+# with this program; if not, write to the Free Software Foundation, Inc., 59 #
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
+###############################################################################
+"""
+The :mod:`~openlp.plugins.songs.forms.songselectform` module contains the GUI for the SongSelect importer
+"""
+
+import logging
+import os
+from time import sleep
+
+from PyQt4 import QtCore, QtGui
+
+from openlp.core import Settings
+from openlp.core.common import Registry
+from openlp.core.lib import translate
+from openlp.plugins.songs.forms.songselectdialog import Ui_SongSelectDialog
+from openlp.plugins.songs.lib.songselect import SongSelectImport
+
+log = logging.getLogger(__name__)
+
+
+class SearchWorker(QtCore.QObject):
+ """
+ Run the actual SongSelect search, and notify the GUI when we find each song.
+ """
+ show_info = QtCore.pyqtSignal(str, str)
+ found_song = QtCore.pyqtSignal(dict)
+ finished = QtCore.pyqtSignal()
+ quit = QtCore.pyqtSignal()
+
+ def __init__(self, importer, search_text):
+ super().__init__()
+ self.importer = importer
+ self.search_text = search_text
+
+ def start(self):
+ """
+ Run a search and then parse the results page of the search.
+ """
+ songs = self.importer.search(self.search_text, 1000, self._found_song_callback)
+ if len(songs) >= 1000:
+ self.show_info.emit(
+ translate('SongsPlugin.SongSelectForm', 'More than 1000 results'),
+ translate('SongsPlugin.SongSelectForm', 'Your search has returned more than 1000 results, it has '
+ 'been stopped. Please refine your search to fetch better '
+ 'results.'))
+ self.finished.emit()
+ self.quit.emit()
+
+ def _found_song_callback(self, song):
+ """
+ A callback used by the paginate function to notify watching processes when it finds a song.
+
+ :param song: The song that was found
+ """
+ self.found_song.emit(song)
+
+
+class SongSelectForm(QtGui.QDialog, Ui_SongSelectDialog):
+ """
+ The :class:`SongSelectForm` class is the SongSelect dialog.
+ """
+
+ def __init__(self, parent=None, plugin=None, db_manager=None):
+ QtGui.QDialog.__init__(self, parent)
+ self.setup_ui(self)
+ self.thread = None
+ self.worker = None
+ self.song_count = 0
+ self.song = None
+ self.plugin = plugin
+ self.song_select_importer = SongSelectImport(db_manager)
+ self.save_password_checkbox.toggled.connect(self.on_save_password_checkbox_toggled)
+ self.login_button.clicked.connect(self.on_login_button_clicked)
+ self.search_button.clicked.connect(self.on_search_button_clicked)
+ self.search_combobox.returnPressed.connect(self.on_search_button_clicked)
+ self.logout_button.clicked.connect(self.done)
+ self.search_results_widget.itemDoubleClicked.connect(self.on_search_results_widget_double_clicked)
+ self.search_results_widget.itemSelectionChanged.connect(self.on_search_results_widget_selection_changed)
+ self.view_button.clicked.connect(self.on_view_button_clicked)
+ self.back_button.clicked.connect(self.on_back_button_clicked)
+ self.import_button.clicked.connect(self.on_import_button_clicked)
+
+ def exec_(self):
+ """
+ Execute the dialog. This method sets everything back to its initial
+ values.
+ """
+ self.stacked_widget.setCurrentIndex(0)
+ self.username_edit.setEnabled(True)
+ self.password_edit.setEnabled(True)
+ self.save_password_checkbox.setEnabled(True)
+ self.search_combobox.clearEditText()
+ self.search_combobox.clear()
+ self.search_results_widget.clear()
+ self.view_button.setEnabled(False)
+ if Settings().contains(self.plugin.settings_section + '/songselect password'):
+ self.username_edit.setText(Settings().value(self.plugin.settings_section + '/songselect username'))
+ self.password_edit.setText(Settings().value(self.plugin.settings_section + '/songselect password'))
+ self.save_password_checkbox.setChecked(True)
+ if Settings().contains(self.plugin.settings_section + '/songselect searches'):
+ self.search_combobox.addItems(
+ Settings().value(self.plugin.settings_section + '/songselect searches').split('|'))
+ self.username_edit.setFocus()
+ return QtGui.QDialog.exec_(self)
+
+ def done(self, r):
+ """
+ Log out of SongSelect.
+
+ :param r: The result of the dialog.
+ """
+ log.debug('Closing SongSelectForm')
+ if self.stacked_widget.currentIndex() > 0:
+ progress_dialog = QtGui.QProgressDialog(
+ translate('SongsPlugin.SongSelectForm', 'Logging out...'), '', 0, 2, self)
+ progress_dialog.setWindowModality(QtCore.Qt.WindowModal)
+ progress_dialog.setCancelButton(None)
+ progress_dialog.setValue(1)
+ progress_dialog.show()
+ progress_dialog.setFocus()
+ self.application.process_events()
+ sleep(0.5)
+ self.application.process_events()
+ self.song_select_importer.logout()
+ self.application.process_events()
+ progress_dialog.setValue(2)
+ return QtGui.QDialog.done(self, r)
+
+ def _update_login_progress(self):
+ self.login_progress_bar.setValue(self.login_progress_bar.value() + 1)
+ self.application.process_events()
+
+ def _update_song_progress(self):
+ self.song_progress_bar.setValue(self.song_progress_bar.value() + 1)
+ self.application.process_events()
+
+ def _view_song(self, current_item):
+ if not current_item:
+ return
+ else:
+ current_item = current_item.data(QtCore.Qt.UserRole)
+ self.song_progress_bar.setVisible(True)
+ self.import_button.setEnabled(False)
+ self.back_button.setEnabled(False)
+ self.title_edit.setText('')
+ self.title_edit.setEnabled(False)
+ self.copyright_edit.setText('')
+ self.copyright_edit.setEnabled(False)
+ self.ccli_edit.setText('')
+ self.ccli_edit.setEnabled(False)
+ self.author_list_widget.clear()
+ self.author_list_widget.setEnabled(False)
+ self.lyrics_table_widget.clear()
+ self.lyrics_table_widget.setRowCount(0)
+ self.lyrics_table_widget.setEnabled(False)
+ self.stacked_widget.setCurrentIndex(2)
+ song = {}
+ for key, value in current_item.items():
+ song[key] = value
+ self.song_progress_bar.setValue(0)
+ self.application.process_events()
+ # Get the full song
+ song = self.song_select_importer.get_song(song, self._update_song_progress)
+ # Update the UI
+ self.title_edit.setText(song['title'])
+ self.copyright_edit.setText(song['copyright'])
+ self.ccli_edit.setText(song['ccli_number'])
+ for author in song['authors']:
+ QtGui.QListWidgetItem(author, self.author_list_widget)
+ for counter, verse in enumerate(song['verses']):
+ self.lyrics_table_widget.setRowCount(self.lyrics_table_widget.rowCount() + 1)
+ item = QtGui.QTableWidgetItem(verse['lyrics'])
+ item.setData(QtCore.Qt.UserRole, verse['label'])
+ item.setFlags(item.flags() ^ QtCore.Qt.ItemIsEditable)
+ self.lyrics_table_widget.setItem(counter, 0, item)
+ self.lyrics_table_widget.setVerticalHeaderLabels([verse['label'] for verse in song['verses']])
+ self.lyrics_table_widget.resizeRowsToContents()
+ self.title_edit.setEnabled(True)
+ self.copyright_edit.setEnabled(True)
+ self.ccli_edit.setEnabled(True)
+ self.author_list_widget.setEnabled(True)
+ self.lyrics_table_widget.setEnabled(True)
+ self.lyrics_table_widget.repaint()
+ self.import_button.setEnabled(True)
+ self.back_button.setEnabled(True)
+ self.song_progress_bar.setVisible(False)
+ self.song_progress_bar.setValue(0)
+ self.song = song
+ self.application.process_events()
+
+ def on_save_password_checkbox_toggled(self, checked):
+ """
+ Show a warning dialog when the user toggles the save checkbox on or off.
+
+ :param checked: If the combobox is checked or not
+ """
+ if checked and self.login_page.isVisible():
+ answer = QtGui.QMessageBox.question(
+ self, translate('SongsPlugin.SongSelectForm', 'Save Username and Password'),
+ translate('SongsPlugin.SongSelectForm', 'WARNING: Saving your username and password is INSECURE, your '
+ 'password is stored in PLAIN TEXT. Click Yes to save your '
+ 'password or No to cancel this.'),
+ QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Yes | QtGui.QMessageBox.No), QtGui.QMessageBox.No)
+ if answer == QtGui.QMessageBox.No:
+ self.save_password_checkbox.setChecked(False)
+
+ def on_login_button_clicked(self):
+ """
+ Log the user in to SongSelect.
+ """
+ self.username_edit.setEnabled(False)
+ self.password_edit.setEnabled(False)
+ self.save_password_checkbox.setEnabled(False)
+ self.login_button.setEnabled(False)
+ self.login_spacer.setVisible(False)
+ self.login_progress_bar.setValue(0)
+ self.login_progress_bar.setVisible(True)
+ self.application.process_events()
+ # Log the user in
+ if not self.song_select_importer.login(
+ self.username_edit.text(), self.password_edit.text(), self._update_login_progress):
+ QtGui.QMessageBox.critical(
+ self,
+ translate('SongsPlugin.SongSelectForm', 'Error Logging In'),
+ translate('SongsPlugin.SongSelectForm',
+ 'There was a problem logging in, perhaps your username or password is incorrect?')
+ )
+ else:
+ if self.save_password_checkbox.isChecked():
+ Settings().setValue(self.plugin.settings_section + '/songselect username', self.username_edit.text())
+ Settings().setValue(self.plugin.settings_section + '/songselect password', self.password_edit.text())
+ else:
+ Settings().remove(self.plugin.settings_section + '/songselect username')
+ Settings().remove(self.plugin.settings_section + '/songselect password')
+ self.stacked_widget.setCurrentIndex(1)
+ self.login_progress_bar.setVisible(False)
+ self.login_progress_bar.setValue(0)
+ self.login_spacer.setVisible(True)
+ self.login_button.setEnabled(True)
+ self.search_combobox.setFocus()
+ self.application.process_events()
+
+ def on_search_button_clicked(self):
+ """
+ Run a search on SongSelect.
+ """
+ # Set up UI components
+ self.view_button.setEnabled(False)
+ self.search_button.setEnabled(False)
+ self.search_progress_bar.setMinimum(0)
+ self.search_progress_bar.setMaximum(0)
+ self.search_progress_bar.setValue(0)
+ self.search_progress_bar.setVisible(True)
+ self.search_results_widget.clear()
+ self.result_count_label.setText(translate('SongsPlugin.SongSelectForm', 'Found %s song(s)') % self.song_count)
+ self.application.process_events()
+ self.song_count = 0
+ search_history = self.search_combobox.getItems()
+ Settings().setValue(self.plugin.settings_section + '/songselect searches', '|'.join(search_history))
+ # Create thread and run search
+ self.thread = QtCore.QThread()
+ self.worker = SearchWorker(self.song_select_importer, self.search_combobox.currentText())
+ self.worker.moveToThread(self.thread)
+ self.thread.started.connect(self.worker.start)
+ self.worker.show_info.connect(self.on_search_show_info)
+ self.worker.found_song.connect(self.on_search_found_song)
+ self.worker.finished.connect(self.on_search_finished)
+ self.worker.quit.connect(self.thread.quit)
+ self.worker.quit.connect(self.worker.deleteLater)
+ self.thread.finished.connect(self.thread.deleteLater)
+ self.thread.start()
+
+ def on_search_show_info(self, title, message):
+ """
+ Show an informational message from the search thread
+ :param title:
+ :param message:
+ """
+ QtGui.QMessageBox.information(self, title, message)
+
+ def on_search_found_song(self, song):
+ """
+ Add a song to the list when one is found.
+ :param song:
+ """
+ self.song_count += 1
+ self.result_count_label.setText(translate('SongsPlugin.SongSelectForm', 'Found %s song(s)') % self.song_count)
+ item_title = song['title'] + ' (' + ', '.join(song['authors']) + ')'
+ song_item = QtGui.QListWidgetItem(item_title, self.search_results_widget)
+ song_item.setData(QtCore.Qt.UserRole, song)
+
+ def on_search_finished(self):
+ """
+ Slot which is called when the search is completed.
+
+ :param songs:
+ """
+ self.application.process_events()
+ self.search_progress_bar.setVisible(False)
+ self.search_button.setEnabled(True)
+ self.application.process_events()
+
+ def on_search_results_widget_selection_changed(self):
+ """
+ Enable or disable the view button when the selection changes.
+ """
+ self.view_button.setEnabled(len(self.search_results_widget.selectedItems()) > 0)
+
+ def on_view_button_clicked(self):
+ """
+ View a song from SongSelect.
+ """
+ self._view_song(self.search_results_widget.currentItem())
+
+ def on_search_results_widget_double_clicked(self, current_item):
+ """
+ View a song from SongSelect
+
+ :param current_item:
+ """
+ self._view_song(current_item)
+
+ def on_back_button_clicked(self):
+ """
+ Go back to the search page.
+ """
+ self.stacked_widget.setCurrentIndex(1)
+ self.search_combobox.setFocus()
+
+ def on_import_button_clicked(self):
+ """
+ Import a song from SongSelect.
+ """
+ self.song_select_importer.save_song(self.song)
+ question_dialog = QtGui.QMessageBox()
+ question_dialog.setWindowTitle(translate('SongsPlugin.SongSelectForm', 'Song Imported'))
+ question_dialog.setText(translate('SongsPlugin.SongSelectForm', 'Your song has been imported, would you like '
+ 'to exit now, or import more songs?'))
+ question_dialog.addButton(QtGui.QPushButton(translate('SongsPlugin.SongSelectForm', 'Import More Songs')),
+ QtGui.QMessageBox.YesRole)
+ question_dialog.addButton(QtGui.QPushButton(translate('SongsPlugin.SongSelectForm', 'Exit Now')),
+ QtGui.QMessageBox.NoRole)
+ if question_dialog.exec_() == QtGui.QMessageBox.Yes:
+ self.on_back_button_clicked()
+ else:
+ self.application.process_events()
+ self.done(QtGui.QDialog.Accepted)
+
+ @property
+ def application(self):
+ """
+ Adds the openlp to the class dynamically.
+ Windows needs to access the application in a dynamic manner.
+ """
+ if os.name == 'nt':
+ return Registry().get('application')
+ else:
+ if not hasattr(self, '_application'):
+ self._application = Registry().get('application')
+ return self._application
=== modified file 'openlp/plugins/songs/lib/__init__.py'
--- openlp/plugins/songs/lib/__init__.py 2013-12-24 09:24:32 +0000
+++ openlp/plugins/songs/lib/__init__.py 2014-03-11 19:13:15 +0000
@@ -53,64 +53,41 @@
# \# - where # is a single non-alpha character, representing a special symbol
# { or } - marking the beginning/end of a group
# a run of characters without any \ { } or end-of-line
-PATTERN = re.compile(r"(\\\*)?\\([a-z]{1,32})(-?\d{1,10})?[ ]?|\\'([0-9a-f]{2})|\\([^a-z*])|([{}])|[\r\n]+|([^\\{}\r\n]+)", re.I)
+PATTERN = re.compile(
+ r"(\\\*)?\\([a-z]{1,32})(-?\d{1,10})?[ ]?|\\'([0-9a-f]{2})|\\([^a-z*])|([{}])|[\r\n]+|([^\\{}\r\n]+)", re.I)
# RTF control words which specify a "destination" to be ignored.
DESTINATIONS = frozenset((
- 'aftncn', 'aftnsep', 'aftnsepc', 'annotation', 'atnauthor',
- 'atndate', 'atnicn', 'atnid', 'atnparent', 'atnref', 'atntime',
- 'atrfend', 'atrfstart', 'author', 'background', 'bkmkend',
- 'bkmkstart', 'blipuid', 'buptim', 'category',
- 'colorschememapping', 'colortbl', 'comment', 'company', 'creatim',
- 'datafield', 'datastore', 'defchp', 'defpap', 'do', 'doccomm',
- 'docvar', 'dptxbxtext', 'ebcend', 'ebcstart', 'factoidname',
- 'falt', 'fchars', 'ffdeftext', 'ffentrymcr', 'ffexitmcr',
- 'ffformat', 'ffhelptext', 'ffl', 'ffname', 'ffstattext',
- 'file', 'filetbl', 'fldinst', 'fldtype', 'fname',
- 'fontemb', 'fontfile', 'footer', 'footerf', 'footerl', 'footerr',
- 'footnote', 'formfield', 'ftncn', 'ftnsep', 'ftnsepc', 'g',
- 'generator', 'gridtbl', 'header', 'headerf', 'headerl',
- 'headerr', 'hl', 'hlfr', 'hlinkbase', 'hlloc', 'hlsrc', 'hsv',
- 'htmltag', 'info', 'keycode', 'keywords', 'latentstyles',
- 'lchars', 'levelnumbers', 'leveltext', 'lfolevel', 'linkval',
- 'list', 'listlevel', 'listname', 'listoverride',
- 'listoverridetable', 'listpicture', 'liststylename', 'listtable',
- 'listtext', 'lsdlockedexcept', 'macc', 'maccPr', 'mailmerge',
- 'maln', 'malnScr', 'manager', 'margPr', 'mbar', 'mbarPr',
- 'mbaseJc', 'mbegChr', 'mborderBox', 'mborderBoxPr', 'mbox',
- 'mboxPr', 'mchr', 'mcount', 'mctrlPr', 'md', 'mdeg', 'mdegHide',
- 'mden', 'mdiff', 'mdPr', 'me', 'mendChr', 'meqArr', 'meqArrPr',
- 'mf', 'mfName', 'mfPr', 'mfunc', 'mfuncPr', 'mgroupChr',
- 'mgroupChrPr', 'mgrow', 'mhideBot', 'mhideLeft', 'mhideRight',
- 'mhideTop', 'mhtmltag', 'mlim', 'mlimloc', 'mlimlow',
- 'mlimlowPr', 'mlimupp', 'mlimuppPr', 'mm', 'mmaddfieldname',
- 'mmath', 'mmathPict', 'mmathPr', 'mmaxdist', 'mmc', 'mmcJc',
- 'mmconnectstr', 'mmconnectstrdata', 'mmcPr', 'mmcs',
- 'mmdatasource', 'mmheadersource', 'mmmailsubject', 'mmodso',
- 'mmodsofilter', 'mmodsofldmpdata', 'mmodsomappedname',
- 'mmodsoname', 'mmodsorecipdata', 'mmodsosort', 'mmodsosrc',
- 'mmodsotable', 'mmodsoudl', 'mmodsoudldata', 'mmodsouniquetag',
- 'mmPr', 'mmquery', 'mmr', 'mnary', 'mnaryPr', 'mnoBreak',
- 'mnum', 'mobjDist', 'moMath', 'moMathPara', 'moMathParaPr',
- 'mopEmu', 'mphant', 'mphantPr', 'mplcHide', 'mpos', 'mr',
- 'mrad', 'mradPr', 'mrPr', 'msepChr', 'mshow', 'mshp', 'msPre',
- 'msPrePr', 'msSub', 'msSubPr', 'msSubSup', 'msSubSupPr', 'msSup',
- 'msSupPr', 'mstrikeBLTR', 'mstrikeH', 'mstrikeTLBR', 'mstrikeV',
- 'msub', 'msubHide', 'msup', 'msupHide', 'mtransp', 'mtype',
- 'mvertJc', 'mvfmf', 'mvfml', 'mvtof', 'mvtol', 'mzeroAsc',
- 'mzFrodesc', 'mzeroWid', 'nesttableprops', 'nextfile',
- 'nonesttables', 'objalias', 'objclass', 'objdata', 'object',
- 'objname', 'objsect', 'objtime', 'oldcprops', 'oldpprops',
- 'oldsprops', 'oldtprops', 'oleclsid', 'operator', 'panose',
- 'password', 'passwordhash', 'pgp', 'pgptbl', 'picprop', 'pict',
- 'pn', 'pnseclvl', 'pntext', 'pntxta', 'pntxtb', 'printim',
- 'private', 'propname', 'protend', 'protstart', 'protusertbl',
- 'pxe', 'result', 'revtbl', 'revtim', 'rsidtbl', 'rxe', 'shp',
- 'shpgrp', 'shpinst', 'shppict', 'shprslt', 'shptxt', 'sn', 'sp',
- 'staticval', 'stylesheet', 'subject', 'sv', 'svb', 'tc',
- 'template', 'themedata', 'title', 'txe', 'ud', 'upr',
- 'userprops', 'wgrffmtfilter', 'windowcaption', 'writereservation',
- 'writereservhash', 'xe', 'xform', 'xmlattrname', 'xmlattrvalue',
- 'xmlclose', 'xmlname', 'xmlnstbl', 'xmlopen'))
+ 'aftncn', 'aftnsep', 'aftnsepc', 'annotation', 'atnauthor', 'atndate', 'atnicn', 'atnid', 'atnparent', 'atnref',
+ 'atntime', 'atrfend', 'atrfstart', 'author', 'background', 'bkmkend', 'bkmkstart', 'blipuid', 'buptim', 'category',
+ 'colorschememapping', 'colortbl', 'comment', 'company', 'creatim', 'datafield', 'datastore', 'defchp', 'defpap',
+ 'do', 'doccomm', 'docvar', 'dptxbxtext', 'ebcend', 'ebcstart', 'factoidname', 'falt', 'fchars', 'ffdeftext',
+ 'ffentrymcr', 'ffexitmcr', 'ffformat', 'ffhelptext', 'ffl', 'ffname', 'ffstattext', 'file', 'filetbl', 'fldinst',
+ 'fldtype', 'fname', 'fontemb', 'fontfile', 'footer', 'footerf', 'footerl', 'footerr', 'footnote', 'formfield',
+ 'ftncn', 'ftnsep', 'ftnsepc', 'g', 'generator', 'gridtbl', 'header', 'headerf', 'headerl', 'headerr', 'hl', 'hlfr',
+ 'hlinkbase', 'hlloc', 'hlsrc', 'hsv', 'htmltag', 'info', 'keycode', 'keywords', 'latentstyles', 'lchars',
+ 'levelnumbers', 'leveltext', 'lfolevel', 'linkval', 'list', 'listlevel', 'listname', 'listoverride',
+ 'listoverridetable', 'listpicture', 'liststylename', 'listtable', 'listtext', 'lsdlockedexcept', 'macc', 'maccPr',
+ 'mailmerge', 'maln', 'malnScr', 'manager', 'margPr', 'mbar', 'mbarPr', 'mbaseJc', 'mbegChr', 'mborderBox',
+ 'mborderBoxPr', 'mbox', 'mboxPr', 'mchr', 'mcount', 'mctrlPr', 'md', 'mdeg', 'mdegHide', 'mden', 'mdiff', 'mdPr',
+ 'me', 'mendChr', 'meqArr', 'meqArrPr', 'mf', 'mfName', 'mfPr', 'mfunc', 'mfuncPr', 'mgroupChr', 'mgroupChrPr',
+ 'mgrow', 'mhideBot', 'mhideLeft', 'mhideRight', 'mhideTop', 'mhtmltag', 'mlim', 'mlimloc', 'mlimlow', 'mlimlowPr',
+ 'mlimupp', 'mlimuppPr', 'mm', 'mmaddfieldname', 'mmath', 'mmathPict', 'mmathPr', 'mmaxdist', 'mmc', 'mmcJc',
+ 'mmconnectstr', 'mmconnectstrdata', 'mmcPr', 'mmcs', 'mmdatasource', 'mmheadersource', 'mmmailsubject', 'mmodso',
+ 'mmodsofilter', 'mmodsofldmpdata', 'mmodsomappedname', 'mmodsoname', 'mmodsorecipdata', 'mmodsosort', 'mmodsosrc',
+ 'mmodsotable', 'mmodsoudl', 'mmodsoudldata', 'mmodsouniquetag', 'mmPr', 'mmquery', 'mmr', 'mnary', 'mnaryPr',
+ 'mnoBreak', 'mnum', 'mobjDist', 'moMath', 'moMathPara', 'moMathParaPr', 'mopEmu', 'mphant', 'mphantPr', 'mplcHide',
+ 'mpos', 'mr', 'mrad', 'mradPr', 'mrPr', 'msepChr', 'mshow', 'mshp', 'msPre', 'msPrePr', 'msSub', 'msSubPr',
+ 'msSubSup', 'msSubSupPr', 'msSup', 'msSupPr', 'mstrikeBLTR', 'mstrikeH', 'mstrikeTLBR', 'mstrikeV', 'msub',
+ 'msubHide', 'msup', 'msupHide', 'mtransp', 'mtype', 'mvertJc', 'mvfmf', 'mvfml', 'mvtof', 'mvtol', 'mzeroAsc',
+ 'mzFrodesc', 'mzeroWid', 'nesttableprops', 'nextfile', 'nonesttables', 'objalias', 'objclass', 'objdata', 'object',
+ 'objname', 'objsect', 'objtime', 'oldcprops', 'oldpprops', 'oldsprops', 'oldtprops', 'oleclsid', 'operator',
+ 'panose', 'password', 'passwordhash', 'pgp', 'pgptbl', 'picprop', 'pict', 'pn', 'pnseclvl', 'pntext', 'pntxta',
+ 'pntxtb', 'printim', 'private', 'propname', 'protend', 'protstart', 'protusertbl', 'pxe', 'result', 'revtbl',
+ 'revtim', 'rsidtbl', 'rxe', 'shp', 'shpgrp', 'shpinst', 'shppict', 'shprslt', 'shptxt', 'sn', 'sp', 'staticval',
+ 'stylesheet', 'subject', 'sv', 'svb', 'tc', 'template', 'themedata', 'title', 'txe', 'ud', 'upr', 'userprops',
+ 'wgrffmtfilter', 'windowcaption', 'writereservation', 'writereservhash', 'xe', 'xform', 'xmlattrname',
+ 'xmlattrvalue', 'xmlclose', 'xmlname', 'xmlnstbl', 'xmlopen'
+))
# Translation of some special characters.
SPECIAL_CHARS = {
'\n': '\n',
@@ -142,7 +119,8 @@
'ltrmark': '\u200E',
'rtlmark': '\u200F',
'zwj': '\u200D',
- 'zwnj': '\u200C'}
+ 'zwnj': '\u200C'
+}
CHARSET_MAPPING = {
'0': 'cp1252',
'128': 'cp932',
@@ -156,7 +134,8 @@
'186': 'cp1257',
'204': 'cp1251',
'222': 'cp874',
- '238': 'cp1250'}
+ '238': 'cp1250'
+}
class VerseType(object):
@@ -171,14 +150,7 @@
Ending = 5
Other = 6
- names = [
- 'Verse',
- 'Chorus',
- 'Bridge',
- 'Pre-Chorus',
- 'Intro',
- 'Ending',
- 'Other']
+ names = ['Verse', 'Chorus', 'Bridge', 'Pre-Chorus', 'Intro', 'Ending', 'Other']
tags = [name[0].lower() for name in names]
translated_names = [
@@ -197,11 +169,9 @@
"""
Return the translated UPPERCASE tag for a given tag, used to show translated verse tags in UI
- ``verse_tag``
- The string to return a VerseType for
-
- ``default``
- Default return value if no matching tag is found
+ :param verse_tag: The string to return a VerseType for
+ :param default: Default return value if no matching tag is found
+ :return: A translated UPPERCASE tag
"""
verse_tag = verse_tag[0].lower()
for num, tag in enumerate(VerseType.tags):
@@ -217,11 +187,9 @@
"""
Return the translated name for a given tag
- ``verse_tag``
- The string to return a VerseType for
-
- ``default``
- Default return value if no matching tag is found
+ :param verse_tag: The string to return a VerseType for
+ :param default: Default return value if no matching tag is found
+ :return: Translated name for the given tag
"""
verse_tag = verse_tag[0].lower()
for num, tag in enumerate(VerseType.tags):
@@ -237,11 +205,9 @@
"""
Return the VerseType for a given tag
- ``verse_tag``
- The string to return a VerseType for
-
- ``default``
- Default return value if no matching tag is found
+ :param verse_tag: The string to return a VerseType for
+ :param default: Default return value if no matching tag is found
+ :return: A VerseType of the tag
"""
verse_tag = verse_tag[0].lower()
for num, tag in enumerate(VerseType.tags):
@@ -257,11 +223,9 @@
"""
Return the VerseType for a given tag
- ``verse_tag``
- The string to return a VerseType for
-
- ``default``
- Default return value if no matching tag is found
+ :param verse_tag: The string to return a VerseType for
+ :param default: Default return value if no matching tag is found
+ :return: The VerseType of a translated tag
"""
verse_tag = verse_tag[0].lower()
for num, tag in enumerate(VerseType.translated_tags):
@@ -277,11 +241,9 @@
"""
Return the VerseType for a given string
- ``verse_name``
- The string to return a VerseType for
-
- ``default``
- Default return value if no matching tag is found
+ :param verse_name: The string to return a VerseType for
+ :param default: Default return value if no matching tag is found
+ :return: The VerseType determined from the string
"""
verse_name = verse_name.lower()
for num, name in enumerate(VerseType.names):
@@ -294,8 +256,8 @@
"""
Return the VerseType for a given string
- ``verse_name``
- The string to return a VerseType for
+ :param verse_name: The string to return a VerseType for
+ :return: A VerseType
"""
verse_name = verse_name.lower()
for num, translation in enumerate(VerseType.translated_names):
@@ -307,11 +269,9 @@
"""
Return the VerseType for a given string
- ``verse_name``
- The string to return a VerseType for
-
- ``default``
- Default return value if no matching tag is found
+ :param verse_name: The string to return a VerseType for
+ :param default: Default return value if no matching tag is found
+ :return: A VerseType
"""
if len(verse_name) > 1:
verse_index = VerseType.from_translated_string(verse_name)
@@ -331,22 +291,21 @@
Determines which encoding to use on an information source. The process uses both automated detection, which is
passed to this method as a recommendation, and user confirmation to return an encoding.
- ``recommendation``
- A recommended encoding discovered programmatically for the user to confirm.
+ :param recommendation: A recommended encoding discovered programmatically for the user to confirm.
+ :return: A list of recommended encodings, or None
"""
# map chardet result to compatible windows standard code page
- codepage_mapping = {'IBM866': 'cp866', 'TIS-620': 'cp874',
- 'SHIFT_JIS': 'cp932', 'GB2312': 'cp936', 'HZ-GB-2312': 'cp936',
- 'EUC-KR': 'cp949', 'Big5': 'cp950', 'ISO-8859-2': 'cp1250',
- 'windows-1250': 'cp1250', 'windows-1251': 'cp1251',
- 'windows-1252': 'cp1252', 'ISO-8859-7': 'cp1253',
- 'windows-1253': 'cp1253', 'ISO-8859-8': 'cp1255',
- 'windows-1255': 'cp1255'}
+ codepage_mapping = {'IBM866': 'cp866', 'TIS-620': 'cp874', 'SHIFT_JIS': 'cp932', 'GB2312': 'cp936',
+ 'HZ-GB-2312': 'cp936', 'EUC-KR': 'cp949', 'Big5': 'cp950', 'ISO-8859-2': 'cp1250',
+ 'windows-1250': 'cp1250', 'windows-1251': 'cp1251', 'windows-1252': 'cp1252',
+ 'ISO-8859-7': 'cp1253', 'windows-1253': 'cp1253', 'ISO-8859-8': 'cp1255',
+ 'windows-1255': 'cp1255'}
if recommendation in codepage_mapping:
recommendation = codepage_mapping[recommendation]
# Show dialog for encoding selection
- encodings = [('cp1256', translate('SongsPlugin', 'Arabic (CP-1256)')),
+ encodings = [
+ ('cp1256', translate('SongsPlugin', 'Arabic (CP-1256)')),
('cp1257', translate('SongsPlugin', 'Baltic (CP-1257)')),
('cp1250', translate('SongsPlugin', 'Central European (CP-1250)')),
('cp1251', translate('SongsPlugin', 'Cyrillic (CP-1251)')),
@@ -359,7 +318,8 @@
('cp950', translate('SongsPlugin', 'Traditional Chinese (CP-950)')),
('cp1254', translate('SongsPlugin', 'Turkish (CP-1254)')),
('cp1258', translate('SongsPlugin', 'Vietnam (CP-1258)')),
- ('cp1252', translate('SongsPlugin', 'Western European (CP-1252)'))]
+ ('cp1252', translate('SongsPlugin', 'Western European (CP-1252)'))
+ ]
recommended_index = -1
if recommendation:
for index in range(len(encodings)):
@@ -367,17 +327,20 @@
recommended_index = index
break
if recommended_index > -1:
- choice = QtGui.QInputDialog.getItem(None,
+ choice = QtGui.QInputDialog.getItem(
+ None,
translate('SongsPlugin', 'Character Encoding'),
translate('SongsPlugin', 'The codepage setting is responsible\n'
- 'for the correct character representation.\nUsually you are fine with the preselected choice.'),
+ 'for the correct character representation.\n'
+ 'Usually you are fine with the preselected choice.'),
[pair[1] for pair in encodings], recommended_index, False)
else:
- choice = QtGui.QInputDialog.getItem(None,
+ choice = QtGui.QInputDialog.getItem(
+ None,
translate('SongsPlugin', 'Character Encoding'),
translate('SongsPlugin', 'Please choose the character encoding.\n'
- 'The encoding is responsible for the correct character representation.'),
- [pair[1] for pair in encodings], 0, False)
+ 'The encoding is responsible for the correct character representation.'),
+ [pair[1] for pair in encodings], 0, False)
if not choice[1]:
return None
return next(filter(lambda item: item[1] == choice[0], encodings))[0]
@@ -386,6 +349,9 @@
def clean_string(string):
"""
Strips punctuation from the passed string to assist searching.
+
+ :param string: The string to clean
+ :return: A clean string
"""
return WHITESPACE.sub(' ', APOSTROPHE.sub('', string)).lower()
@@ -393,6 +359,9 @@
def clean_title(title):
"""
Cleans the song title by removing Unicode control chars groups C0 & C1, as well as any trailing spaces.
+
+ :param title: The song title to clean
+ :return: A clean title
"""
return CONTROL_CHARS.sub('', title).rstrip()
@@ -402,11 +371,8 @@
Cleans the search title, rebuilds the search lyrics, adds a default author if the song does not have one and other
clean ups. This should always called when a new song is added or changed.
- ``manager``
- The song's manager.
-
- ``song``
- The song object.
+ :param manager: The song database manager object.
+ :param song: The song object.
"""
from .xml import SongXML
@@ -419,55 +385,10 @@
else:
song.alternate_title = ''
song.search_title = clean_string(song.title) + '@' + clean_string(song.alternate_title)
- # Only do this, if we the song is a 1.9.4 song (or older).
- if song.lyrics.find('<lyrics language="en">') != -1:
- # Remove the old "language" attribute from lyrics tag (prior to 1.9.5). This is not very important, but this
- # keeps the database clean. This can be removed when everybody has cleaned his songs.
- song.lyrics = song.lyrics.replace('<lyrics language="en">', '<lyrics>')
- verses = SongXML().get_verses(song.lyrics)
- song.search_lyrics = ' '.join([clean_string(verse[1])
- for verse in verses])
- # We need a new and clean SongXML instance.
- sxml = SongXML()
- # Rebuild the song's verses, to remove any wrong verse names (for example translated ones), which might have
- # been added prior to 1.9.5.
- # List for later comparison.
- compare_order = []
- for verse in verses:
- verse_type = VerseType.tags[VerseType.from_loose_input(verse[0]['type'])]
- sxml.add_verse_to_lyrics(
- verse_type,
- verse[0]['label'],
- verse[1],
- verse[0].get('lang')
- )
- compare_order.append(('%s%s' % (verse_type, verse[0]['label'])).upper())
- if verse[0]['label'] == '1':
- compare_order.append(verse_type.upper())
- song.lyrics = str(sxml.extract_xml(), 'utf-8')
- # Rebuild the verse order, to convert translated verse tags, which might have been added prior to 1.9.5.
- if song.verse_order:
- order = CONTROL_CHARS.sub('', song.verse_order).strip().split()
- else:
- order = []
- new_order = []
- for verse_def in order:
- verse_type = VerseType.tags[
- VerseType.from_loose_input(verse_def[0])]
- if len(verse_def) > 1:
- new_order.append(('%s%s' % (verse_type, verse_def[1:])).upper())
- else:
- new_order.append(verse_type.upper())
- song.verse_order = ' '.join(new_order)
- # Check if the verse order contains tags for verses which do not exist.
- for order in new_order:
- if order not in compare_order:
- song.verse_order = ''
- break
- else:
- verses = SongXML().get_verses(song.lyrics)
- song.search_lyrics = ' '.join([clean_string(verse[1])
- for verse in verses])
+ if isinstance(song.lyrics, bytes):
+ song.lyrics = str(song.lyrics, encoding='utf8')
+ verses = SongXML().get_verses(song.lyrics)
+ song.search_lyrics = ' '.join([clean_string(verse[1]) for verse in verses])
# The song does not have any author, add one.
if not song.authors:
@@ -484,17 +405,10 @@
"""
Finds an encoding to use. Asks user, if necessary.
- ``font``
- The number of currently active font.
-
- ``font_table``
- Dictionary of fonts and respective encodings.
-
- ``default_encoding``
- The default encoding to use when font_table is empty or no font is used.
-
- ``failed``
- A boolean indicating whether the previous encoding didn't work.
+ :param font: The number of currently active font.
+ :param font_table: Dictionary of fonts and respective encodings.
+ :param default_encoding: The default encoding to use when font_table is empty or no font is used.
+ :param failed: A boolean indicating whether the previous encoding didn't work.
"""
encoding = None
if font in font_table:
@@ -512,14 +426,11 @@
"""
This function strips RTF control structures and returns an unicode string.
- Thanks to Markus Jarderot (MizardX) for this code, used by permission.
- http://stackoverflow.com/questions/188545
-
- ``text``
- RTF-encoded text, a string.
-
- ``default_encoding``
- Default encoding to use when no encoding is specified.
+ Thanks to Markus Jarderot (MizardX) for this code, used by permission. http://stackoverflow.com/questions/188545
+
+ :param text: RTF-encoded text, a string.
+ :param default_encoding: Default encoding to use when no encoding is specified.
+ :return: A tuple ``(text, encoding)`` where ``text`` is the clean text and ``encoding`` is the detected encoding
"""
# Current font is the font tag we last met.
font = ''
@@ -620,20 +531,17 @@
def delete_song(song_id, song_plugin):
"""
- Deletes a song from the database. Media files associated to the song
- are removed prior to the deletion of the song.
-
- ``song_id``
- The ID of the song to delete.
-
- ``song_plugin``
- The song plugin instance.
+ Deletes a song from the database. Media files associated to the song are removed prior to the deletion of the song.
+
+ :param song_id: The ID of the song to delete.
+ :param song_plugin: The song plugin instance.
"""
+ save_path = ''
media_files = song_plugin.manager.get_all_objects(MediaFile, MediaFile.song_id == song_id)
for media_file in media_files:
try:
os.remove(media_file.file_name)
- except:
+ except OSError:
log.exception('Could not remove file: %s', media_file.file_name)
try:
save_path = os.path.join(AppLocation.get_section_data_path(song_plugin.name), 'audio', str(song_id))
=== added file 'openlp/plugins/songs/lib/songselect.py'
--- openlp/plugins/songs/lib/songselect.py 1970-01-01 00:00:00 +0000
+++ openlp/plugins/songs/lib/songselect.py 2014-03-11 19:13:15 +0000
@@ -0,0 +1,208 @@
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
+
+###############################################################################
+# OpenLP - Open Source Lyrics Projection #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2014 Raoul Snyman #
+# Portions copyright (c) 2008-2014 Tim Bentley, Gerald Britton, Jonathan #
+# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
+# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
+# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
+# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
+# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, #
+# Frode Woldsund, Martin Zibricky, Patrick Zimmermann #
+# --------------------------------------------------------------------------- #
+# This program is free software; you can redistribute it and/or modify it #
+# under the terms of the GNU General Public License as published by the Free #
+# Software Foundation; version 2 of the License. #
+# #
+# This program is distributed in the hope that it will be useful, but WITHOUT #
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
+# more details. #
+# #
+# You should have received a copy of the GNU General Public License along #
+# with this program; if not, write to the Free Software Foundation, Inc., 59 #
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
+###############################################################################
+"""
+The :mod:`~openlp.plugins.songs.lib.songselect` module contains the SongSelect importer itself.
+"""
+import logging
+from http.cookiejar import CookieJar
+from urllib.parse import urlencode
+from urllib.request import HTTPCookieProcessor, HTTPError, build_opener
+from html.parser import HTMLParser
+
+from bs4 import BeautifulSoup, NavigableString
+
+from openlp.plugins.songs.lib import Song, VerseType, clean_song, Author
+from openlp.plugins.songs.lib.xml import SongXML
+
+USER_AGENT = 'Mozilla/5.0 (Linux; U; Android 4.0.3; en-us; GT-I9000 ' \
+ 'Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 ' \
+ 'Mobile Safari/534.30'
+BASE_URL = 'https://mobile.songselect.com'
+LOGIN_URL = BASE_URL + '/account/login'
+LOGOUT_URL = BASE_URL + '/account/logout'
+SEARCH_URL = BASE_URL + '/search/results'
+
+log = logging.getLogger(__name__)
+
+
+class SongSelectImport(object):
+ """
+ The :class:`~openlp.plugins.songs.lib.songselect.SongSelectImport` class contains all the code which interfaces
+ with CCLI's SongSelect service and downloads the songs.
+ """
+ def __init__(self, db_manager):
+ """
+ Set up the song select importer
+
+ :param db_manager: The song database manager
+ """
+ self.db_manager = db_manager
+ self.html_parser = HTMLParser()
+ self.opener = build_opener(HTTPCookieProcessor(CookieJar()))
+ self.opener.addheaders = [('User-Agent', USER_AGENT)]
+
+ def login(self, username, password, callback=None):
+ """
+ Log the user into SongSelect. This method takes a username and password, and runs ``callback()`` at various
+ points which can be used to give the user some form of feedback.
+
+ :param username: SongSelect username
+ :param password: SongSelect password
+ :param callback: Method to notify of progress.
+ :return: True on success, False on failure.
+ """
+ if callback:
+ callback()
+ login_page = BeautifulSoup(self.opener.open(LOGIN_URL).read(), 'lxml')
+ if callback:
+ callback()
+ token_input = login_page.find('input', attrs={'name': '__RequestVerificationToken'})
+ data = urlencode({
+ '__RequestVerificationToken': token_input['value'],
+ 'UserName': username,
+ 'Password': password,
+ 'RememberMe': 'false'
+ })
+ posted_page = BeautifulSoup(self.opener.open(LOGIN_URL, data.encode('utf-8')).read(), 'lxml')
+ if callback:
+ callback()
+ return not posted_page.find('input', attrs={'name': '__RequestVerificationToken'})
+
+ def logout(self):
+ """
+ Log the user out of SongSelect
+ """
+ self.opener.open(LOGOUT_URL)
+
+ def search(self, search_text, max_results, callback=None):
+ """
+ Set up a search.
+
+ :param search_text: The text to search for.
+ :param max_results: Maximum number of results to fetch.
+ :param callback: A method which is called when each song is found, with the song as a parameter.
+ :return: List of songs
+ """
+ params = {'allowredirect': 'false', 'SearchTerm': search_text}
+ current_page = 1
+ songs = []
+ while True:
+ if current_page > 1:
+ params['page'] = current_page
+ results_page = BeautifulSoup(self.opener.open(SEARCH_URL + '?' + urlencode(params)).read(), 'lxml')
+ search_results = results_page.find_all('li', 'result pane')
+ if not search_results:
+ break
+ for result in search_results:
+ song = {
+ 'title': self.html_parser.unescape(result.find('h3').string),
+ 'authors': [self.html_parser.unescape(author.string) for author in result.find_all('li')],
+ 'link': BASE_URL + result.find('a')['href']
+ }
+ if callback:
+ callback(song)
+ songs.append(song)
+ if len(songs) >= max_results:
+ break
+ current_page += 1
+ return songs
+
+ def get_song(self, song, callback=None):
+ """
+ Get the full song from SongSelect
+
+ :param song: The song dictionary to update
+ :param callback: A callback which can be used to indicate progress
+ :return: The updated song dictionary
+ """
+ if callback:
+ callback()
+ try:
+ song_page = BeautifulSoup(self.opener.open(song['link']).read(), 'lxml')
+ except (TypeError, HTTPError) as e:
+ log.exception(u'Could not get song from SongSelect, %s', e)
+ return None
+ if callback:
+ callback()
+ try:
+ lyrics_page = BeautifulSoup(self.opener.open(song['link'] + '/lyrics').read(), 'lxml')
+ except (TypeError, HTTPError):
+ log.exception(u'Could not get lyrics from SongSelect')
+ return None
+ if callback:
+ callback()
+ song['copyright'] = '/'.join([li.string for li in song_page.find('ul', 'copyright').find_all('li')])
+ song['copyright'] = self.html_parser.unescape(song['copyright'])
+ song['ccli_number'] = song_page.find('ul', 'info').find('li').string.split(':')[1].strip()
+ song['verses'] = []
+ verses = lyrics_page.find('section', 'lyrics').find_all('p')
+ verse_labels = lyrics_page.find('section', 'lyrics').find_all('h3')
+ for counter in range(len(verses)):
+ verse = {'label': verse_labels[counter].string, 'lyrics': ''}
+ for v in verses[counter].contents:
+ if isinstance(v, NavigableString):
+ verse['lyrics'] = verse['lyrics'] + v.string
+ else:
+ verse['lyrics'] += '\n'
+ verse['lyrics'] = verse['lyrics'].strip(' \n\r\t')
+ song['verses'].append(self.html_parser.unescape(verse))
+ for counter, author in enumerate(song['authors']):
+ song['authors'][counter] = self.html_parser.unescape(author)
+ return song
+
+ def save_song(self, song):
+ """
+ Save a song to the database, using the db_manager
+
+ :param song:
+ :return:
+ """
+ db_song = Song.populate(title=song['title'], copyright=song['copyright'], ccli_number=song['ccli_number'])
+ song_xml = SongXML()
+ verse_order = []
+ for verse in song['verses']:
+ verse_type, verse_number = verse['label'].split(' ')[:2]
+ verse_type = VerseType.from_loose_input(verse_type)
+ verse_number = int(verse_number)
+ song_xml.add_verse_to_lyrics(VerseType.tags[verse_type], verse_number, verse['lyrics'])
+ verse_order.append('%s%s' % (VerseType.tags[verse_type], verse_number))
+ db_song.verse_order = ' '.join(verse_order)
+ db_song.lyrics = song_xml.extract_xml()
+ clean_song(self.db_manager, db_song)
+ self.db_manager.save_object(db_song)
+ db_song.authors = []
+ for author_name in song['authors']:
+ author = self.db_manager.get_object_filtered(Author, Author.display_name == author_name)
+ if not author:
+ author = Author.populate(first_name=author_name.rsplit(' ', 1)[0],
+ last_name=author_name.rsplit(' ', 1)[1],
+ display_name=author_name)
+ db_song.authors.append(author)
+ self.db_manager.save_object(db_song)
+ return db_song
=== modified file 'openlp/plugins/songs/songsplugin.py'
--- openlp/plugins/songs/songsplugin.py 2014-03-04 18:49:30 +0000
+++ openlp/plugins/songs/songsplugin.py 2014-03-11 19:13:15 +0000
@@ -38,11 +38,13 @@
from PyQt4 import QtCore, QtGui
-from openlp.core.common import UiStrings, translate
+from openlp.core.common import UiStrings, Registry, translate
from openlp.core.lib import Plugin, StringContent, build_icon
from openlp.core.lib.db import Manager
from openlp.core.lib.ui import create_action
from openlp.core.utils.actions import ActionList
+from openlp.plugins.songs.forms.duplicatesongremovalform import DuplicateSongRemovalForm
+from openlp.plugins.songs.forms.songselectform import SongSelectForm
from openlp.plugins.songs.lib import clean_song, upgrade
from openlp.plugins.songs.lib.db import init_schema, Song
from openlp.plugins.songs.lib.mediaitem import SongSearch
@@ -50,27 +52,29 @@
from openlp.plugins.songs.lib.olpimport import OpenLPSongImport
from openlp.plugins.songs.lib.mediaitem import SongMediaItem
from openlp.plugins.songs.lib.songstab import SongsTab
-from openlp.plugins.songs.forms.duplicatesongremovalform import DuplicateSongRemovalForm
log = logging.getLogger(__name__)
-__default_settings__ = {'songs/db type': 'sqlite',
- 'songs/last search type': SongSearch.Entire,
- 'songs/last import type': SongFormat.OpenLyrics,
- 'songs/update service on edit': False,
- 'songs/search as type': False,
- 'songs/add song from service': True,
- 'songs/display songbar': True,
- 'songs/last directory import': '',
- 'songs/last directory export': ''
- }
+__default_settings__ = {
+ 'songs/db type': 'sqlite',
+ 'songs/last search type': SongSearch.Entire,
+ 'songs/last import type': SongFormat.OpenLyrics,
+ 'songs/update service on edit': False,
+ 'songs/search as type': False,
+ 'songs/add song from service': True,
+ 'songs/display songbar': True,
+ 'songs/last directory import': '',
+ 'songs/last directory export': '',
+ 'songs/songselect username': '',
+ 'songs/songselect password': '',
+ 'songs/songselect searches': ''
+}
class SongsPlugin(Plugin):
"""
- This is the number 1 plugin, if importance were placed on any plugins. This plugin enables the user to create,
- edit and display songs. Songs are divided into verses, and the verse order can be specified. Authors, topics and
- song books can be assigned to songs as well.
+ This plugin enables the user to create, edit and display songs. Songs are divided into verses, and the verse order
+ can be specified. Authors, topics and song books can be assigned to songs as well.
"""
log.info('Song Plugin loaded')
@@ -83,6 +87,7 @@
self.weight = -10
self.icon_path = ':/plugins/plugin_songs.png'
self.icon = build_icon(self.icon_path)
+ self.songselect_form = None
def check_pre_conditions(self):
"""
@@ -92,10 +97,11 @@
def initialise(self):
"""
- Lets Initialise the plugin
+ Initialise the plugin
"""
log.info('Songs Initialising')
super(SongsPlugin, self).initialise()
+ self.songselect_form = SongSelectForm(Registry().get('main_window'), self, self.manager)
self.song_import_item.setVisible(True)
self.song_export_item.setVisible(True)
self.tools_reindex_item.setVisible(True)
@@ -119,12 +125,18 @@
tooltip=translate('SongsPlugin', 'Import songs using the import wizard.'),
triggers=self.on_song_import_item_clicked)
import_menu.addAction(self.song_import_item)
+ self.import_songselect_item = create_action(
+ import_menu, 'import_songselect_item', text=translate('SongsPlugin', 'CCLI SongSelect'),
+ statustip=translate('SongsPlugin', 'Import songs from CCLI\'s SongSelect service.'),
+ triggers=self.on_import_songselect_item_triggered
+ )
+ import_menu.addAction(self.import_songselect_item)
def add_export_menu_Item(self, export_menu):
"""
Give the Songs plugin the opportunity to add items to the **Export** menu.
- :param export_menu: The actual **Export** menu item, so that your actions can use it as their parent.
+ :param export_menu: The actual **Export** menu item, so that your actions can use it as their parent.
"""
# Main song import menu item - will eventually be the only one
self.song_export_item = create_action(
@@ -179,29 +191,42 @@
"""
DuplicateSongRemovalForm(self).exec_()
+ def on_import_songselect_item_triggered(self):
+ """
+ Run the SongSelect importer.
+ """
+ self.songselect_form.exec_()
+ self.media_item.on_search_text_button_clicked()
+
def on_song_import_item_clicked(self):
"""
- The song import option has been selected
+ Run the song import wizard.
"""
if self.media_item:
self.media_item.on_import_click()
def on_song_export_item_clicked(self):
"""
- The song export option has been selected
+ Run the song export wizard.
"""
if self.media_item:
self.media_item.on_export_click()
def about(self):
+ """
+ Provides information for the plugin manager to display.
+
+ :return: A translatable string with some basic information about the Songs plugin
+ """
return translate('SongsPlugin', '<strong>Songs Plugin</strong>'
- '<br />The songs plugin provides the ability to display and manage songs.')
+ '<br />The songs plugin provides the ability to display and manage songs.')
def uses_theme(self, theme):
"""
Called to find out if the song plugin is currently using a theme.
- Returns True if the theme is being used, otherwise returns False.
+ :param theme: The theme to check for usage
+ :return: True if the theme is being used, otherwise returns False
"""
if self.manager.get_all_objects(Song, Song.theme_name == theme):
return True
=== added file 'resources/images/general_back.png'
Binary files resources/images/general_back.png 1970-01-01 00:00:00 +0000 and resources/images/general_back.png 2014-03-11 19:13:15 +0000 differ
=== added file 'resources/images/general_find.png'
Binary files resources/images/general_find.png 1970-01-01 00:00:00 +0000 and resources/images/general_find.png 2014-03-11 19:13:15 +0000 differ
=== modified file 'resources/images/openlp-2.qrc'
--- resources/images/openlp-2.qrc 2013-04-06 10:20:17 +0000
+++ resources/images/openlp-2.qrc 2014-03-11 19:13:15 +0000
@@ -61,6 +61,8 @@
<file>general_email.png</file>
<file>general_revert.png</file>
<file>general_clone.png</file>
+ <file>general_find.png</file>
+ <file>general_back.png</file>
</qresource>
<qresource prefix="slides">
<file>slide_close.png</file>
=== modified file 'tests/functional/__init__.py'
--- tests/functional/__init__.py 2013-12-18 21:54:56 +0000
+++ tests/functional/__init__.py 2014-03-11 19:13:15 +0000
@@ -1,3 +1,7 @@
+# -*- coding: utf-8 -*-
+"""
+Base directory for tests
+"""
import sip
sip.setapi('QDate', 2)
sip.setapi('QDateTime', 2)
@@ -11,9 +15,11 @@
from PyQt4 import QtGui
if sys.version_info[1] >= 3:
- from unittest.mock import MagicMock, patch, mock_open
+ from unittest.mock import MagicMock, patch, mock_open, call
else:
- from mock import MagicMock, patch, mock_open
+ from mock import MagicMock, patch, mock_open, call
# Only one QApplication can be created. Use QtGui.QApplication.instance() when you need to "create" a QApplication.
application = QtGui.QApplication([])
+
+__all__ = ['MagicMock', 'patch', 'mock_open', 'call', 'application']
=== modified file 'tests/functional/openlp_plugins/songs/test_songbeamerimport.py'
--- tests/functional/openlp_plugins/songs/test_songbeamerimport.py 2013-12-24 08:56:50 +0000
+++ tests/functional/openlp_plugins/songs/test_songbeamerimport.py 2014-03-11 19:13:15 +0000
@@ -38,20 +38,20 @@
TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__),
'..', '..', '..', 'resources', 'songbeamersongs'))
-SONG_TEST_DATA = {'Lobsinget dem Herrn.sng':
- {'title': 'GL 1 - Lobsinget dem Herrn',
- 'verses':
- [('1. Lobsinget dem Herrn,\no preiset Ihn gern!\n'
- 'Anbetung und Lob Ihm gebühret.\n', 'v'),
- ('2. Lobsingt Seiner Lieb´,\ndie einzig ihn trieb,\n'
- 'zu sterben für unsere Sünden!\n', 'v'),
- ('3. Lobsingt Seiner Macht!\nSein Werk ist vollbracht:\n'
- 'Er sitzet zur Rechten des Vaters.\n', 'v'),
- ('4. Lobsingt seiner Treu´,\ndie immerdar neu,\n'
- 'bis Er uns zur Herrlichket führet!\n\n', 'v')],
- 'song_book_name': 'Glaubenslieder I',
- 'song_number': "1"}
- }
+SONG_TEST_DATA = {
+ 'Lobsinget dem Herrn.sng': {
+ 'title': 'GL 1 - Lobsinget dem Herrn',
+ 'verses': [
+ ('1. Lobsinget dem Herrn,\no preiset Ihn gern!\nAnbetung und Lob Ihm gebühret.\n', 'v'),
+ ('2. Lobsingt Seiner Lieb´,\ndie einzig ihn trieb,\nzu sterben für unsere Sünden!\n', 'v'),
+ ('3. Lobsingt Seiner Macht!\nSein Werk ist vollbracht:\nEr sitzet zur Rechten des Vaters.\n', 'v'),
+ ('4. Lobsingt seiner Treu´,\ndie immerdar neu,\nbis Er uns zur Herrlichket führet!\n\n', 'v')
+ ],
+ 'song_book_name': 'Glaubenslieder I',
+ 'song_number': "1"
+ }
+}
+
class TestSongBeamerImport(TestCase):
"""
=== added file 'tests/functional/openlp_plugins/songs/test_songselect.py'
--- tests/functional/openlp_plugins/songs/test_songselect.py 1970-01-01 00:00:00 +0000
+++ tests/functional/openlp_plugins/songs/test_songselect.py 2014-03-11 19:13:15 +0000
@@ -0,0 +1,382 @@
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
+
+###############################################################################
+# OpenLP - Open Source Lyrics Projection #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2014 Raoul Snyman #
+# Portions copyright (c) 2008-2014 Tim Bentley, Gerald Britton, Jonathan #
+# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
+# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
+# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
+# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
+# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, #
+# Frode Woldsund, Martin Zibricky, Patrick Zimmermann #
+# --------------------------------------------------------------------------- #
+# This program is free software; you can redistribute it and/or modify it #
+# under the terms of the GNU General Public License as published by the Free #
+# Software Foundation; version 2 of the License. #
+# #
+# This program is distributed in the hope that it will be useful, but WITHOUT #
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
+# more details. #
+# #
+# You should have received a copy of the GNU General Public License along #
+# with this program; if not, write to the Free Software Foundation, Inc., 59 #
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
+###############################################################################
+"""
+This module contains tests for the CCLI SongSelect importer.
+"""
+from unittest import TestCase
+from urllib.error import URLError
+from openlp.plugins.songs.lib import Author, Song
+
+from openlp.plugins.songs.lib.songselect import SongSelectImport, LOGOUT_URL, BASE_URL
+
+from tests.functional import MagicMock, patch, call
+
+
+class TestSongSelect(TestCase):
+ """
+ Test the :class:`~openlp.plugins.songs.lib.songselect.SongSelectImport` class
+ """
+ def constructor_test(self):
+ """
+ Test that constructing a basic SongSelectImport object works correctly
+ """
+ # GIVEN: The SongSelectImporter class and a mocked out build_opener
+ with patch('openlp.plugins.songs.lib.songselect.build_opener') as mocked_build_opener:
+ # WHEN: An object is instantiated
+ importer = SongSelectImport(None)
+
+ # THEN: The object should have the correct properties
+ self.assertIsNone(importer.db_manager, 'The db_manager should be None')
+ self.assertIsNotNone(importer.html_parser, 'There should be a valid html_parser object')
+ self.assertIsNotNone(importer.opener, 'There should be a valid opener object')
+ self.assertEqual(1, mocked_build_opener.call_count, 'The build_opener method should have been called once')
+
+ def login_fails_test(self):
+ """
+ Test that when logging in to SongSelect fails, the login method returns False
+ """
+ # GIVEN: A bunch of mocked out stuff and an importer object
+ with patch('openlp.plugins.songs.lib.songselect.build_opener') as mocked_build_opener, \
+ patch('openlp.plugins.songs.lib.songselect.BeautifulSoup') as MockedBeautifulSoup:
+ mocked_opener = MagicMock()
+ mocked_build_opener.return_value = mocked_opener
+ mocked_login_page = MagicMock()
+ mocked_login_page.find.return_value = {'value': 'blah'}
+ MockedBeautifulSoup.return_value = mocked_login_page
+ mock_callback = MagicMock()
+ importer = SongSelectImport(None)
+
+ # WHEN: The login method is called after being rigged to fail
+ result = importer.login('username', 'password', mock_callback)
+
+ # THEN: callback was called 3 times, open was called twice, find was called twice, and False was returned
+ self.assertEqual(3, mock_callback.call_count, 'callback should have been called 3 times')
+ self.assertEqual(2, mocked_login_page.find.call_count, 'find should have been called twice')
+ self.assertEqual(2, mocked_opener.open.call_count, 'opener should have been called twice')
+ self.assertFalse(result, 'The login method should have returned False')
+
+ def login_succeeds_test(self):
+ """
+ Test that when logging in to SongSelect succeeds, the login method returns True
+ """
+ # GIVEN: A bunch of mocked out stuff and an importer object
+ with patch('openlp.plugins.songs.lib.songselect.build_opener') as mocked_build_opener, \
+ patch('openlp.plugins.songs.lib.songselect.BeautifulSoup') as MockedBeautifulSoup:
+ mocked_opener = MagicMock()
+ mocked_build_opener.return_value = mocked_opener
+ mocked_login_page = MagicMock()
+ mocked_login_page.find.side_effect = [{'value': 'blah'}, None]
+ MockedBeautifulSoup.return_value = mocked_login_page
+ mock_callback = MagicMock()
+ importer = SongSelectImport(None)
+
+ # WHEN: The login method is called after being rigged to fail
+ result = importer.login('username', 'password', mock_callback)
+
+ # THEN: callback was called 3 times, open was called twice, find was called twice, and True was returned
+ self.assertEqual(3, mock_callback.call_count, 'callback should have been called 3 times')
+ self.assertEqual(2, mocked_login_page.find.call_count, 'find should have been called twice')
+ self.assertEqual(2, mocked_opener.open.call_count, 'opener should have been called twice')
+ self.assertTrue(result, 'The login method should have returned True')
+
+ def logout_test(self):
+ """
+ Test that when the logout method is called, it logs the user out of SongSelect
+ """
+ # GIVEN: A bunch of mocked out stuff and an importer object
+ with patch('openlp.plugins.songs.lib.songselect.build_opener') as mocked_build_opener:
+ mocked_opener = MagicMock()
+ mocked_build_opener.return_value = mocked_opener
+ importer = SongSelectImport(None)
+
+ # WHEN: The login method is called after being rigged to fail
+ importer.logout()
+
+ # THEN: The opener is called once with the logout url
+ self.assertEqual(1, mocked_opener.open.call_count, 'opener should have been called once')
+ mocked_opener.open.assert_called_with(LOGOUT_URL)
+
+ def search_returns_no_results_test(self):
+ """
+ Test that when the search finds no results, it simply returns an empty list
+ """
+ # GIVEN: A bunch of mocked out stuff and an importer object
+ with patch('openlp.plugins.songs.lib.songselect.build_opener') as mocked_build_opener, \
+ patch('openlp.plugins.songs.lib.songselect.BeautifulSoup') as MockedBeautifulSoup:
+ mocked_opener = MagicMock()
+ mocked_build_opener.return_value = mocked_opener
+ mocked_results_page = MagicMock()
+ mocked_results_page.find_all.return_value = []
+ MockedBeautifulSoup.return_value = mocked_results_page
+ mock_callback = MagicMock()
+ importer = SongSelectImport(None)
+
+ # WHEN: The login method is called after being rigged to fail
+ results = importer.search('text', 1000, mock_callback)
+
+ # THEN: callback was never called, open was called once, find_all was called once, an empty list returned
+ self.assertEqual(0, mock_callback.call_count, 'callback should not have been called')
+ self.assertEqual(1, mocked_opener.open.call_count, 'open should have been called once')
+ self.assertEqual(1, mocked_results_page.find_all.call_count, 'find_all should have been called once')
+ mocked_results_page.find_all.assert_called_with('li', 'result pane')
+ self.assertEqual([], results, 'The search method should have returned an empty list')
+
+ def search_returns_two_results_test(self):
+ """
+ Test that when the search finds 2 results, it simply returns a list with 2 results
+ """
+ # GIVEN: A bunch of mocked out stuff and an importer object
+ with patch('openlp.plugins.songs.lib.songselect.build_opener') as mocked_build_opener, \
+ patch('openlp.plugins.songs.lib.songselect.BeautifulSoup') as MockedBeautifulSoup:
+ # first search result
+ mocked_result1 = MagicMock()
+ mocked_result1.find.side_effect = [MagicMock(string='Title 1'), {'href': '/url1'}]
+ mocked_result1.find_all.return_value = [MagicMock(string='Author 1-1'), MagicMock(string='Author 1-2')]
+ # second search result
+ mocked_result2 = MagicMock()
+ mocked_result2.find.side_effect = [MagicMock(string='Title 2'), {'href': '/url2'}]
+ mocked_result2.find_all.return_value = [MagicMock(string='Author 2-1'), MagicMock(string='Author 2-2')]
+ # rest of the stuff
+ mocked_opener = MagicMock()
+ mocked_build_opener.return_value = mocked_opener
+ mocked_results_page = MagicMock()
+ mocked_results_page.find_all.side_effect = [[mocked_result1, mocked_result2], []]
+ MockedBeautifulSoup.return_value = mocked_results_page
+ mock_callback = MagicMock()
+ importer = SongSelectImport(None)
+
+ # WHEN: The login method is called after being rigged to fail
+ results = importer.search('text', 1000, mock_callback)
+
+ # THEN: callback was never called, open was called once, find_all was called once, an empty list returned
+ self.assertEqual(2, mock_callback.call_count, 'callback should have been called twice')
+ self.assertEqual(2, mocked_opener.open.call_count, 'open should have been called twice')
+ self.assertEqual(2, mocked_results_page.find_all.call_count, 'find_all should have been called twice')
+ mocked_results_page.find_all.assert_called_with('li', 'result pane')
+ expected_list = [
+ {'title': 'Title 1', 'authors': ['Author 1-1', 'Author 1-2'], 'link': BASE_URL + '/url1'},
+ {'title': 'Title 2', 'authors': ['Author 2-1', 'Author 2-2'], 'link': BASE_URL + '/url2'}
+ ]
+ self.assertListEqual(expected_list, results, 'The search method should have returned two songs')
+
+ def search_reaches_max_results_test(self):
+ """
+ Test that when the search finds MAX (2) results, it simply returns a list with those (2)
+ """
+ # GIVEN: A bunch of mocked out stuff and an importer object
+ with patch('openlp.plugins.songs.lib.songselect.build_opener') as mocked_build_opener, \
+ patch('openlp.plugins.songs.lib.songselect.BeautifulSoup') as MockedBeautifulSoup:
+ # first search result
+ mocked_result1 = MagicMock()
+ mocked_result1.find.side_effect = [MagicMock(string='Title 1'), {'href': '/url1'}]
+ mocked_result1.find_all.return_value = [MagicMock(string='Author 1-1'), MagicMock(string='Author 1-2')]
+ # second search result
+ mocked_result2 = MagicMock()
+ mocked_result2.find.side_effect = [MagicMock(string='Title 2'), {'href': '/url2'}]
+ mocked_result2.find_all.return_value = [MagicMock(string='Author 2-1'), MagicMock(string='Author 2-2')]
+ # third search result
+ mocked_result3 = MagicMock()
+ mocked_result3.find.side_effect = [MagicMock(string='Title 3'), {'href': '/url3'}]
+ mocked_result3.find_all.return_value = [MagicMock(string='Author 3-1'), MagicMock(string='Author 3-2')]
+ # rest of the stuff
+ mocked_opener = MagicMock()
+ mocked_build_opener.return_value = mocked_opener
+ mocked_results_page = MagicMock()
+ mocked_results_page.find_all.side_effect = [[mocked_result1, mocked_result2, mocked_result3], []]
+ MockedBeautifulSoup.return_value = mocked_results_page
+ mock_callback = MagicMock()
+ importer = SongSelectImport(None)
+
+ # WHEN: The login method is called after being rigged to fail
+ results = importer.search('text', 2, mock_callback)
+
+ # THEN: callback was never called, open was called once, find_all was called once, an empty list returned
+ self.assertEqual(2, mock_callback.call_count, 'callback should have been called twice')
+ self.assertEqual(2, mocked_opener.open.call_count, 'open should have been called twice')
+ self.assertEqual(2, mocked_results_page.find_all.call_count, 'find_all should have been called twice')
+ mocked_results_page.find_all.assert_called_with('li', 'result pane')
+ expected_list = [{'title': 'Title 1', 'authors': ['Author 1-1', 'Author 1-2'], 'link': BASE_URL + '/url1'},
+ {'title': 'Title 2', 'authors': ['Author 2-1', 'Author 2-2'], 'link': BASE_URL + '/url2'}]
+ self.assertListEqual(expected_list, results, 'The search method should have returned two songs')
+
+ def get_song_page_raises_exception_test(self):
+ """
+ Test that when BeautifulSoup gets a bad song page the get_song() method returns None
+ """
+ # GIVEN: A bunch of mocked out stuff and an importer object
+ with patch('openlp.plugins.songs.lib.songselect.build_opener') as mocked_build_opener:
+ mocked_opener = MagicMock()
+ mocked_build_opener.return_value = mocked_opener
+ mocked_opener.open.read.side_effect = URLError('[Errno -2] Name or service not known')
+ mocked_callback = MagicMock()
+ importer = SongSelectImport(None)
+
+ # WHEN: get_song is called
+ result = importer.get_song({'link': 'link'}, callback=mocked_callback)
+
+ # THEN: The callback should have been called once and None should be returned
+ mocked_callback.assert_called_with()
+ self.assertIsNone(result, 'The get_song() method should have returned None')
+
+ def get_song_lyrics_raise_exception_test(self):
+ """
+ Test that when BeautifulSoup gets a bad lyrics page the get_song() method returns None
+ """
+ # GIVEN: A bunch of mocked out stuff and an importer object
+ with patch('openlp.plugins.songs.lib.songselect.build_opener'), \
+ patch('openlp.plugins.songs.lib.songselect.BeautifulSoup') as MockedBeautifulSoup:
+ MockedBeautifulSoup.side_effect = [None, TypeError('Test Error')]
+ mocked_callback = MagicMock()
+ importer = SongSelectImport(None)
+
+ # WHEN: get_song is called
+ result = importer.get_song({'link': 'link'}, callback=mocked_callback)
+
+ # THEN: The callback should have been called twice and None should be returned
+ self.assertEqual(2, mocked_callback.call_count, 'The callback should have been called twice')
+ self.assertIsNone(result, 'The get_song() method should have returned None')
+
+ def get_song_test(self):
+ """
+ Test that the get_song() method returns the correct song details
+ """
+ # GIVEN: A bunch of mocked out stuff and an importer object
+ with patch('openlp.plugins.songs.lib.songselect.build_opener'), \
+ patch('openlp.plugins.songs.lib.songselect.BeautifulSoup') as MockedBeautifulSoup:
+ mocked_song_page = MagicMock()
+ mocked_copyright = MagicMock()
+ mocked_copyright.find_all.return_value = [MagicMock(string='Copyright 1'), MagicMock(string='Copyright 2')]
+ mocked_song_page.find.side_effect = [
+ mocked_copyright,
+ MagicMock(find=MagicMock(string='CCLI: 123456'))
+ ]
+ mocked_lyrics_page = MagicMock()
+ mocked_find_all = MagicMock()
+ mocked_find_all.side_effect = [
+ [
+ MagicMock(contents='The Lord told Noah: there\'s gonna be a floody, floody'),
+ MagicMock(contents='So, rise and shine, and give God the glory, glory'),
+ MagicMock(contents='The Lord told Noah to build him an arky, arky')
+ ],
+ [MagicMock(string='Verse 1'), MagicMock(string='Chorus'), MagicMock(string='Verse 2')]
+ ]
+ mocked_lyrics_page.find.return_value = MagicMock(find_all=mocked_find_all)
+ MockedBeautifulSoup.side_effect = [mocked_song_page, mocked_lyrics_page]
+ mocked_callback = MagicMock()
+ importer = SongSelectImport(None)
+ fake_song = {'title': 'Title', 'authors': ['Author 1', 'Author 2'], 'link': 'url'}
+
+ # WHEN: get_song is called
+ result = importer.get_song(fake_song, callback=mocked_callback)
+
+ # THEN: The callback should have been called three times and the song should be returned
+ self.assertEqual(3, mocked_callback.call_count, 'The callback should have been called twice')
+ self.assertIsNotNone(result, 'The get_song() method should have returned a song dictionary')
+ self.assertEqual(2, mocked_lyrics_page.find.call_count, 'The find() method should have been called twice')
+ self.assertEqual(2, mocked_find_all.call_count, 'The find_all() method should have been called twice')
+ self.assertEqual([call('section', 'lyrics'), call('section', 'lyrics')],
+ mocked_lyrics_page.find.call_args_list,
+ 'The find() method should have been called with the right arguments')
+ self.assertEqual([call('p'), call('h3')], mocked_find_all.call_args_list,
+ 'The find_all() method should have been called with the right arguments')
+ self.assertIn('copyright', result, 'The returned song should have a copyright')
+ self.assertIn('ccli_number', result, 'The returned song should have a CCLI number')
+ self.assertIn('verses', result, 'The returned song should have verses')
+ self.assertEqual(3, len(result['verses']), 'Three verses should have been returned')
+
+ def save_song_new_author_test(self):
+ """
+ Test that saving a song with a new author performs the correct actions
+ """
+ # GIVEN: A song to save, and some mocked out objects
+ with patch('openlp.plugins.songs.lib.songselect.clean_song') as mocked_clean_song, \
+ patch('openlp.plugins.songs.lib.songselect.Author') as MockedAuthor:
+ song_dict = {
+ 'title': 'Arky Arky',
+ 'authors': ['Public Domain'],
+ 'verses': [
+ {'label': 'Verse 1', 'lyrics': 'The Lord told Noah: there\'s gonna be a floody, floody'},
+ {'label': 'Chorus 1', 'lyrics': 'So, rise and shine, and give God the glory, glory'},
+ {'label': 'Verse 2', 'lyrics': 'The Lord told Noah to build him an arky, arky'}
+ ],
+ 'copyright': 'Public Domain',
+ 'ccli_number': '123456'
+ }
+ MockedAuthor.display_name.__eq__.return_value = False
+ mocked_db_manager = MagicMock()
+ mocked_db_manager.get_object_filtered.return_value = None
+ importer = SongSelectImport(mocked_db_manager)
+
+ # WHEN: The song is saved to the database
+ result = importer.save_song(song_dict)
+
+ # THEN: The return value should be a Song class and the mocked_db_manager should have been called
+ self.assertIsInstance(result, Song, 'The returned value should be a Song object')
+ mocked_clean_song.assert_called_with(mocked_db_manager, result)
+ self.assertEqual(2, mocked_db_manager.save_object.call_count,
+ 'The save_object() method should have been called twice')
+ mocked_db_manager.get_object_filtered.assert_called_with(MockedAuthor, False)
+ MockedAuthor.populate.assert_called_with(first_name='Public', last_name='Domain',
+ display_name='Public Domain')
+ self.assertEqual(1, len(result.authors), 'There should only be one author')
+
+ def save_song_existing_author_test(self):
+ """
+ Test that saving a song with an existing author performs the correct actions
+ """
+ # GIVEN: A song to save, and some mocked out objects
+ with patch('openlp.plugins.songs.lib.songselect.clean_song') as mocked_clean_song, \
+ patch('openlp.plugins.songs.lib.songselect.Author') as MockedAuthor:
+ song_dict = {
+ 'title': 'Arky Arky',
+ 'authors': ['Public Domain'],
+ 'verses': [
+ {'label': 'Verse 1', 'lyrics': 'The Lord told Noah: there\'s gonna be a floody, floody'},
+ {'label': 'Chorus 1', 'lyrics': 'So, rise and shine, and give God the glory, glory'},
+ {'label': 'Verse 2', 'lyrics': 'The Lord told Noah to build him an arky, arky'}
+ ],
+ 'copyright': 'Public Domain',
+ 'ccli_number': '123456'
+ }
+ MockedAuthor.display_name.__eq__.return_value = False
+ mocked_db_manager = MagicMock()
+ mocked_db_manager.get_object_filtered.return_value = MagicMock()
+ importer = SongSelectImport(mocked_db_manager)
+
+ # WHEN: The song is saved to the database
+ result = importer.save_song(song_dict)
+
+ # THEN: The return value should be a Song class and the mocked_db_manager should have been called
+ self.assertIsInstance(result, Song, 'The returned value should be a Song object')
+ mocked_clean_song.assert_called_with(mocked_db_manager, result)
+ self.assertEqual(2, mocked_db_manager.save_object.call_count,
+ 'The save_object() method should have been called twice')
+ mocked_db_manager.get_object_filtered.assert_called_with(MockedAuthor, False)
+ self.assertEqual(0, MockedAuthor.populate.call_count, 'A new author should not have been instantiated')
+ self.assertEqual(1, len(result.authors), 'There should only be one author')
=== modified file 'tests/functional/openlp_plugins/songs/test_songshowplusimport.py'
--- tests/functional/openlp_plugins/songs/test_songshowplusimport.py 2013-12-24 08:56:50 +0000
+++ tests/functional/openlp_plugins/songs/test_songshowplusimport.py 2014-03-11 19:13:15 +0000
@@ -41,6 +41,7 @@
TEST_PATH = os.path.abspath(
os.path.join(os.path.dirname(__file__), '..', '..', '..', 'resources', 'songshowplussongs'))
+
class TestSongShowPlusFileImport(SongImportTestHelper):
def __init__(self, *args, **kwargs):
self.importer_class_name = 'SongShowPlusImport'
@@ -48,10 +49,13 @@
super(TestSongShowPlusFileImport, self).__init__(*args, **kwargs)
def test_song_import(self):
- test_import = self.file_import(os.path.join(TEST_PATH, 'Amazing Grace.sbsong'),
- self.load_external_result_data(os.path.join(TEST_PATH, 'Amazing Grace.json')))
- test_import = self.file_import(os.path.join(TEST_PATH, 'Beautiful Garden Of Prayer.sbsong'),
- self.load_external_result_data(os.path.join(TEST_PATH, 'Beautiful Garden Of Prayer.json')))
+ """
+ Test that loading a SongShow Plus file works correctly on various files
+ """
+ self.file_import(os.path.join(TEST_PATH, 'Amazing Grace.sbsong'),
+ self.load_external_result_data(os.path.join(TEST_PATH, 'Amazing Grace.json')))
+ self.file_import(os.path.join(TEST_PATH, 'Beautiful Garden Of Prayer.sbsong'),
+ self.load_external_result_data(os.path.join(TEST_PATH, 'Beautiful Garden Of Prayer.json')))
class TestSongShowPlusImport(TestCase):
=== added file 'tests/helpers/__init__.py'
--- tests/helpers/__init__.py 1970-01-01 00:00:00 +0000
+++ tests/helpers/__init__.py 2014-03-11 19:13:15 +0000
@@ -0,0 +1,31 @@
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
+
+###############################################################################
+# OpenLP - Open Source Lyrics Projection #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2014 Raoul Snyman #
+# Portions copyright (c) 2008-2014 Tim Bentley, Gerald Britton, Jonathan #
+# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
+# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
+# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
+# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
+# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, #
+# Frode Woldsund, Martin Zibricky, Patrick Zimmermann #
+# --------------------------------------------------------------------------- #
+# This program is free software; you can redistribute it and/or modify it #
+# under the terms of the GNU General Public License as published by the Free #
+# Software Foundation; version 2 of the License. #
+# #
+# This program is distributed in the hope that it will be useful, but WITHOUT #
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
+# more details. #
+# #
+# You should have received a copy of the GNU General Public License along #
+# with this program; if not, write to the Free Software Foundation, Inc., 59 #
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
+###############################################################################
+"""
+The :mod:`~tests.helpers` module provides helper classes for use in the tests.
+"""
=== modified file 'tests/helpers/songfileimport.py'
--- tests/helpers/songfileimport.py 2013-12-24 08:56:50 +0000
+++ tests/helpers/songfileimport.py 2014-03-11 19:13:15 +0000
@@ -35,6 +35,7 @@
from tests.functional import patch, MagicMock
+
class SongImportTestHelper(TestCase):
"""
This class is designed to be a helper class to reduce repition when testing the import of song files.
Follow ups