forked from openlp/openlp
Merged trunk on 11.4.2016
This commit is contained in:
commit
6273cc911d
@ -27,26 +27,26 @@ All the core functions of the OpenLP application including the GUI, settings,
|
|||||||
logging and a plugin framework are contained within the openlp.core module.
|
logging and a plugin framework are contained within the openlp.core module.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
import logging
|
|
||||||
import argparse
|
import argparse
|
||||||
from traceback import format_exception
|
import logging
|
||||||
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
|
import sys
|
||||||
import time
|
import time
|
||||||
|
from traceback import format_exception
|
||||||
|
|
||||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
from openlp.core.common import Registry, OpenLPMixin, AppLocation, LanguageManager, Settings, UiStrings, \
|
from openlp.core.common import Registry, OpenLPMixin, AppLocation, LanguageManager, Settings, UiStrings, \
|
||||||
check_directory_exists, is_macosx, is_win, translate
|
check_directory_exists, is_macosx, is_win, translate
|
||||||
|
from openlp.core.common.versionchecker import VersionThread, get_application_version
|
||||||
from openlp.core.lib import ScreenList
|
from openlp.core.lib import ScreenList
|
||||||
from openlp.core.resources import qInitResources
|
from openlp.core.resources import qInitResources
|
||||||
from openlp.core.ui.mainwindow import MainWindow
|
|
||||||
from openlp.core.ui.firsttimelanguageform import FirstTimeLanguageForm
|
|
||||||
from openlp.core.ui.firsttimeform import FirstTimeForm
|
|
||||||
from openlp.core.ui.exceptionform import ExceptionForm
|
|
||||||
from openlp.core.ui import SplashScreen
|
from openlp.core.ui import SplashScreen
|
||||||
from openlp.core.utils import VersionThread, get_application_version
|
from openlp.core.ui.exceptionform import ExceptionForm
|
||||||
|
from openlp.core.ui.firsttimeform import FirstTimeForm
|
||||||
|
from openlp.core.ui.firsttimelanguageform import FirstTimeLanguageForm
|
||||||
|
from openlp.core.ui.mainwindow import MainWindow
|
||||||
|
|
||||||
__all__ = ['OpenLP', 'main']
|
__all__ = ['OpenLP', 'main']
|
||||||
|
|
||||||
|
@ -24,15 +24,15 @@ The :mod:`common` module contains most of the components and libraries that make
|
|||||||
OpenLP work.
|
OpenLP work.
|
||||||
"""
|
"""
|
||||||
import hashlib
|
import hashlib
|
||||||
import re
|
|
||||||
import os
|
|
||||||
import logging
|
import logging
|
||||||
|
import os
|
||||||
|
import re
|
||||||
import sys
|
import sys
|
||||||
import traceback
|
import traceback
|
||||||
from ipaddress import IPv4Address, IPv6Address, AddressValueError
|
from ipaddress import IPv4Address, IPv6Address, AddressValueError
|
||||||
from codecs import decode, encode
|
from shutil import which
|
||||||
|
|
||||||
from PyQt5 import QtCore
|
from PyQt5 import QtCore, QtGui
|
||||||
from PyQt5.QtCore import QCryptographicHash as QHash
|
from PyQt5.QtCore import QCryptographicHash as QHash
|
||||||
|
|
||||||
log = logging.getLogger(__name__ + '.__init__')
|
log = logging.getLogger(__name__ + '.__init__')
|
||||||
@ -40,6 +40,9 @@ log = logging.getLogger(__name__ + '.__init__')
|
|||||||
|
|
||||||
FIRST_CAMEL_REGEX = re.compile('(.)([A-Z][a-z]+)')
|
FIRST_CAMEL_REGEX = re.compile('(.)([A-Z][a-z]+)')
|
||||||
SECOND_CAMEL_REGEX = re.compile('([a-z0-9])([A-Z])')
|
SECOND_CAMEL_REGEX = re.compile('([a-z0-9])([A-Z])')
|
||||||
|
CONTROL_CHARS = re.compile(r'[\x00-\x1F\x7F-\x9F]', re.UNICODE)
|
||||||
|
INVALID_FILE_CHARS = re.compile(r'[\\/:\*\?"<>\|\+\[\]%]', re.UNICODE)
|
||||||
|
IMAGES_FILTER = None
|
||||||
|
|
||||||
|
|
||||||
def trace_error_handler(logger):
|
def trace_error_handler(logger):
|
||||||
@ -241,6 +244,130 @@ from .registryproperties import RegistryProperties
|
|||||||
from .uistrings import UiStrings
|
from .uistrings import UiStrings
|
||||||
from .settings import Settings
|
from .settings import Settings
|
||||||
from .applocation import AppLocation
|
from .applocation import AppLocation
|
||||||
from .historycombobox import HistoryComboBox
|
|
||||||
from .actions import ActionList
|
from .actions import ActionList
|
||||||
from .languagemanager import LanguageManager
|
from .languagemanager import LanguageManager
|
||||||
|
|
||||||
|
|
||||||
|
def add_actions(target, actions):
|
||||||
|
"""
|
||||||
|
Adds multiple actions to a menu or toolbar in one command.
|
||||||
|
|
||||||
|
:param target: The menu or toolbar to add actions to
|
||||||
|
:param actions: The actions to be added. An action consisting of the keyword ``None``
|
||||||
|
will result in a separator being inserted into the target.
|
||||||
|
"""
|
||||||
|
for action in actions:
|
||||||
|
if action is None:
|
||||||
|
target.addSeparator()
|
||||||
|
else:
|
||||||
|
target.addAction(action)
|
||||||
|
|
||||||
|
|
||||||
|
def get_uno_command(connection_type='pipe'):
|
||||||
|
"""
|
||||||
|
Returns the UNO command to launch an libreoffice.org instance.
|
||||||
|
"""
|
||||||
|
for command in ['libreoffice', 'soffice']:
|
||||||
|
if which(command):
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
raise FileNotFoundError('Command not found')
|
||||||
|
|
||||||
|
OPTIONS = '--nologo --norestore --minimized --nodefault --nofirststartwizard'
|
||||||
|
if connection_type == 'pipe':
|
||||||
|
CONNECTION = '"--accept=pipe,name=openlp_pipe;urp;"'
|
||||||
|
else:
|
||||||
|
CONNECTION = '"--accept=socket,host=localhost,port=2002;urp;"'
|
||||||
|
return '%s %s %s' % (command, OPTIONS, CONNECTION)
|
||||||
|
|
||||||
|
|
||||||
|
def get_uno_instance(resolver, connection_type='pipe'):
|
||||||
|
"""
|
||||||
|
Returns a running libreoffice.org instance.
|
||||||
|
|
||||||
|
:param resolver: The UNO resolver to use to find a running instance.
|
||||||
|
"""
|
||||||
|
log.debug('get UNO Desktop Openoffice - resolve')
|
||||||
|
if connection_type == 'pipe':
|
||||||
|
return resolver.resolve('uno:pipe,name=openlp_pipe;urp;StarOffice.ComponentContext')
|
||||||
|
else:
|
||||||
|
return resolver.resolve('uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext')
|
||||||
|
|
||||||
|
|
||||||
|
def get_filesystem_encoding():
|
||||||
|
"""
|
||||||
|
Returns the name of the encoding used to convert Unicode filenames into system file names.
|
||||||
|
"""
|
||||||
|
encoding = sys.getfilesystemencoding()
|
||||||
|
if encoding is None:
|
||||||
|
encoding = sys.getdefaultencoding()
|
||||||
|
return encoding
|
||||||
|
|
||||||
|
|
||||||
|
def split_filename(path):
|
||||||
|
"""
|
||||||
|
Return a list of the parts in a given path.
|
||||||
|
"""
|
||||||
|
path = os.path.abspath(path)
|
||||||
|
if not os.path.isfile(path):
|
||||||
|
return path, ''
|
||||||
|
else:
|
||||||
|
return os.path.split(path)
|
||||||
|
|
||||||
|
|
||||||
|
def delete_file(file_path_name):
|
||||||
|
"""
|
||||||
|
Deletes a file from the system.
|
||||||
|
|
||||||
|
:param file_path_name: The file, including path, to delete.
|
||||||
|
"""
|
||||||
|
if not file_path_name:
|
||||||
|
return False
|
||||||
|
try:
|
||||||
|
if os.path.exists(file_path_name):
|
||||||
|
os.remove(file_path_name)
|
||||||
|
return True
|
||||||
|
except (IOError, OSError):
|
||||||
|
log.exception("Unable to delete file %s" % file_path_name)
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def get_images_filter():
|
||||||
|
"""
|
||||||
|
Returns a filter string for a file dialog containing all the supported image formats.
|
||||||
|
"""
|
||||||
|
global IMAGES_FILTER
|
||||||
|
if not IMAGES_FILTER:
|
||||||
|
log.debug('Generating images filter.')
|
||||||
|
formats = list(map(bytes.decode, list(map(bytes, QtGui.QImageReader.supportedImageFormats()))))
|
||||||
|
visible_formats = '(*.%s)' % '; *.'.join(formats)
|
||||||
|
actual_formats = '(*.%s)' % ' *.'.join(formats)
|
||||||
|
IMAGES_FILTER = '%s %s %s' % (translate('OpenLP', 'Image Files'), visible_formats, actual_formats)
|
||||||
|
return IMAGES_FILTER
|
||||||
|
|
||||||
|
|
||||||
|
def is_not_image_file(file_name):
|
||||||
|
"""
|
||||||
|
Validate that the file is not an image file.
|
||||||
|
|
||||||
|
:param file_name: File name to be checked.
|
||||||
|
"""
|
||||||
|
if not file_name:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
formats = [bytes(fmt).decode().lower() for fmt in QtGui.QImageReader.supportedImageFormats()]
|
||||||
|
file_part, file_extension = os.path.splitext(str(file_name))
|
||||||
|
if file_extension[1:].lower() in formats and os.path.exists(file_name):
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def clean_filename(filename):
|
||||||
|
"""
|
||||||
|
Removes invalid characters from the given ``filename``.
|
||||||
|
|
||||||
|
:param filename: The "dirty" file name to clean.
|
||||||
|
"""
|
||||||
|
if not isinstance(filename, str):
|
||||||
|
filename = str(filename, 'utf-8')
|
||||||
|
return INVALID_FILE_CHARS.sub('_', CONTROL_CHARS.sub('', filename))
|
||||||
|
@ -22,9 +22,9 @@
|
|||||||
"""
|
"""
|
||||||
The :mod:`languagemanager` module provides all the translation settings and language file loading for OpenLP.
|
The :mod:`languagemanager` module provides all the translation settings and language file loading for OpenLP.
|
||||||
"""
|
"""
|
||||||
|
import locale
|
||||||
import logging
|
import logging
|
||||||
import re
|
import re
|
||||||
import sys
|
|
||||||
|
|
||||||
from PyQt5 import QtCore, QtWidgets
|
from PyQt5 import QtCore, QtWidgets
|
||||||
|
|
||||||
@ -33,6 +33,9 @@ from openlp.core.common import AppLocation, Settings, translate, is_win, is_maco
|
|||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
ICU_COLLATOR = None
|
||||||
|
DIGITS_OR_NONDIGITS = re.compile(r'\d+|\D+', re.UNICODE)
|
||||||
|
|
||||||
|
|
||||||
class LanguageManager(object):
|
class LanguageManager(object):
|
||||||
"""
|
"""
|
||||||
@ -144,3 +147,60 @@ class LanguageManager(object):
|
|||||||
if not LanguageManager.__qm_list__:
|
if not LanguageManager.__qm_list__:
|
||||||
LanguageManager.init_qm_list()
|
LanguageManager.init_qm_list()
|
||||||
return LanguageManager.__qm_list__
|
return LanguageManager.__qm_list__
|
||||||
|
|
||||||
|
|
||||||
|
def format_time(text, local_time):
|
||||||
|
"""
|
||||||
|
Workaround for Python built-in time formatting function time.strftime().
|
||||||
|
|
||||||
|
time.strftime() accepts only ascii characters. This function accepts
|
||||||
|
unicode string and passes individual % placeholders to time.strftime().
|
||||||
|
This ensures only ascii characters are passed to time.strftime().
|
||||||
|
|
||||||
|
:param text: The text to be processed.
|
||||||
|
:param local_time: The time to be used to add to the string. This is a time object
|
||||||
|
"""
|
||||||
|
|
||||||
|
def match_formatting(match):
|
||||||
|
"""
|
||||||
|
Format the match
|
||||||
|
"""
|
||||||
|
return local_time.strftime(match.group())
|
||||||
|
|
||||||
|
return re.sub('\%[a-zA-Z]', match_formatting, text)
|
||||||
|
|
||||||
|
|
||||||
|
def get_locale_key(string):
|
||||||
|
"""
|
||||||
|
Creates a key for case insensitive, locale aware string sorting.
|
||||||
|
|
||||||
|
:param string: The corresponding string.
|
||||||
|
"""
|
||||||
|
string = string.lower()
|
||||||
|
# ICU is the prefered way to handle locale sort key, we fallback to locale.strxfrm which will work in most cases.
|
||||||
|
global ICU_COLLATOR
|
||||||
|
try:
|
||||||
|
if ICU_COLLATOR is None:
|
||||||
|
import icu
|
||||||
|
language = LanguageManager.get_language()
|
||||||
|
icu_locale = icu.Locale(language)
|
||||||
|
ICU_COLLATOR = icu.Collator.createInstance(icu_locale)
|
||||||
|
return ICU_COLLATOR.getSortKey(string)
|
||||||
|
except:
|
||||||
|
return locale.strxfrm(string).encode()
|
||||||
|
|
||||||
|
|
||||||
|
def get_natural_key(string):
|
||||||
|
"""
|
||||||
|
Generate a key for locale aware natural string sorting.
|
||||||
|
|
||||||
|
:param string: string to be sorted by
|
||||||
|
Returns a list of string compare keys and integers.
|
||||||
|
"""
|
||||||
|
key = DIGITS_OR_NONDIGITS.findall(string)
|
||||||
|
key = [int(part) if part.isdigit() else get_locale_key(part) for part in key]
|
||||||
|
# Python 3 does not support comparison of different types anymore. So make sure, that we do not compare str
|
||||||
|
# and int.
|
||||||
|
if string and string[0].isdigit():
|
||||||
|
return [b''] + key
|
||||||
|
return key
|
||||||
|
@ -121,6 +121,7 @@ class Settings(QtCore.QSettings):
|
|||||||
'advanced/double click live': False,
|
'advanced/double click live': False,
|
||||||
'advanced/enable exit confirmation': True,
|
'advanced/enable exit confirmation': True,
|
||||||
'advanced/expand service item': False,
|
'advanced/expand service item': False,
|
||||||
|
'advanced/slide max height': 0,
|
||||||
'advanced/hide mouse': True,
|
'advanced/hide mouse': True,
|
||||||
'advanced/is portable': False,
|
'advanced/is portable': False,
|
||||||
'advanced/max recent files': 20,
|
'advanced/max recent files': 20,
|
||||||
|
170
openlp/core/common/versionchecker.py
Normal file
170
openlp/core/common/versionchecker.py
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import platform
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
import urllib.error
|
||||||
|
import urllib.parse
|
||||||
|
import urllib.request
|
||||||
|
from datetime import datetime
|
||||||
|
from distutils.version import LooseVersion
|
||||||
|
from subprocess import Popen, PIPE
|
||||||
|
|
||||||
|
from openlp.core.common import AppLocation, Settings
|
||||||
|
|
||||||
|
from PyQt5 import QtCore
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
APPLICATION_VERSION = {}
|
||||||
|
CONNECTION_TIMEOUT = 30
|
||||||
|
CONNECTION_RETRIES = 2
|
||||||
|
|
||||||
|
|
||||||
|
class VersionThread(QtCore.QThread):
|
||||||
|
"""
|
||||||
|
A special Qt thread class to fetch the version of OpenLP from the website.
|
||||||
|
This is threaded so that it doesn't affect the loading time of OpenLP.
|
||||||
|
"""
|
||||||
|
def __init__(self, main_window):
|
||||||
|
"""
|
||||||
|
Constructor for the thread class.
|
||||||
|
|
||||||
|
:param main_window: The main window Object.
|
||||||
|
"""
|
||||||
|
log.debug("VersionThread - Initialise")
|
||||||
|
super(VersionThread, self).__init__(None)
|
||||||
|
self.main_window = main_window
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
"""
|
||||||
|
Run the thread.
|
||||||
|
"""
|
||||||
|
self.sleep(1)
|
||||||
|
log.debug('Version thread - run')
|
||||||
|
app_version = get_application_version()
|
||||||
|
version = check_latest_version(app_version)
|
||||||
|
log.debug("Versions %s and %s " % (LooseVersion(str(version)), LooseVersion(str(app_version['full']))))
|
||||||
|
if LooseVersion(str(version)) > LooseVersion(str(app_version['full'])):
|
||||||
|
self.main_window.openlp_version_check.emit('%s' % version)
|
||||||
|
|
||||||
|
|
||||||
|
def get_application_version():
|
||||||
|
"""
|
||||||
|
Returns the application version of the running instance of OpenLP::
|
||||||
|
|
||||||
|
{'full': '1.9.4-bzr1249', 'version': '1.9.4', 'build': 'bzr1249'}
|
||||||
|
"""
|
||||||
|
global APPLICATION_VERSION
|
||||||
|
if APPLICATION_VERSION:
|
||||||
|
return APPLICATION_VERSION
|
||||||
|
if '--dev-version' in sys.argv or '-d' in sys.argv:
|
||||||
|
# NOTE: The following code is a duplicate of the code in setup.py. Any fix applied here should also be applied
|
||||||
|
# there.
|
||||||
|
|
||||||
|
# Get the revision of this tree.
|
||||||
|
bzr = Popen(('bzr', 'revno'), stdout=PIPE)
|
||||||
|
tree_revision, error = bzr.communicate()
|
||||||
|
tree_revision = tree_revision.decode()
|
||||||
|
code = bzr.wait()
|
||||||
|
if code != 0:
|
||||||
|
raise Exception('Error running bzr log')
|
||||||
|
|
||||||
|
# Get all tags.
|
||||||
|
bzr = Popen(('bzr', 'tags'), stdout=PIPE)
|
||||||
|
output, error = bzr.communicate()
|
||||||
|
code = bzr.wait()
|
||||||
|
if code != 0:
|
||||||
|
raise Exception('Error running bzr tags')
|
||||||
|
tags = list(map(bytes.decode, output.splitlines()))
|
||||||
|
if not tags:
|
||||||
|
tag_version = '0.0.0'
|
||||||
|
tag_revision = '0'
|
||||||
|
else:
|
||||||
|
# Remove any tag that has "?" as revision number. A "?" as revision number indicates, that this tag is from
|
||||||
|
# another series.
|
||||||
|
tags = [tag for tag in tags if tag.split()[-1].strip() != '?']
|
||||||
|
# Get the last tag and split it in a revision and tag name.
|
||||||
|
tag_version, tag_revision = tags[-1].split()
|
||||||
|
# If they are equal, then this tree is tarball with the source for the release. We do not want the revision
|
||||||
|
# number in the full version.
|
||||||
|
if tree_revision == tag_revision:
|
||||||
|
full_version = tag_version.strip()
|
||||||
|
else:
|
||||||
|
full_version = '%s-bzr%s' % (tag_version.strip(), tree_revision.strip())
|
||||||
|
else:
|
||||||
|
# We're not running the development version, let's use the file.
|
||||||
|
file_path = AppLocation.get_directory(AppLocation.VersionDir)
|
||||||
|
file_path = os.path.join(file_path, '.version')
|
||||||
|
version_file = None
|
||||||
|
try:
|
||||||
|
version_file = open(file_path, 'r')
|
||||||
|
full_version = str(version_file.read()).rstrip()
|
||||||
|
except IOError:
|
||||||
|
log.exception('Error in version file.')
|
||||||
|
full_version = '0.0.0-bzr000'
|
||||||
|
finally:
|
||||||
|
if version_file:
|
||||||
|
version_file.close()
|
||||||
|
bits = full_version.split('-')
|
||||||
|
APPLICATION_VERSION = {
|
||||||
|
'full': full_version,
|
||||||
|
'version': bits[0],
|
||||||
|
'build': bits[1] if len(bits) > 1 else None
|
||||||
|
}
|
||||||
|
if APPLICATION_VERSION['build']:
|
||||||
|
log.info('Openlp version %s build %s', APPLICATION_VERSION['version'], APPLICATION_VERSION['build'])
|
||||||
|
else:
|
||||||
|
log.info('Openlp version %s' % APPLICATION_VERSION['version'])
|
||||||
|
return APPLICATION_VERSION
|
||||||
|
|
||||||
|
|
||||||
|
def check_latest_version(current_version):
|
||||||
|
"""
|
||||||
|
Check the latest version of OpenLP against the version file on the OpenLP
|
||||||
|
site.
|
||||||
|
|
||||||
|
**Rules around versions and version files:**
|
||||||
|
|
||||||
|
* If a version number has a build (i.e. -bzr1234), then it is a nightly.
|
||||||
|
* If a version number's minor version is an odd number, it is a development release.
|
||||||
|
* If a version number's minor version is an even number, it is a stable release.
|
||||||
|
|
||||||
|
:param current_version: The current version of OpenLP.
|
||||||
|
"""
|
||||||
|
version_string = current_version['full']
|
||||||
|
# set to prod in the distribution config file.
|
||||||
|
settings = Settings()
|
||||||
|
settings.beginGroup('core')
|
||||||
|
last_test = settings.value('last version test')
|
||||||
|
this_test = str(datetime.now().date())
|
||||||
|
settings.setValue('last version test', this_test)
|
||||||
|
settings.endGroup()
|
||||||
|
if last_test != this_test:
|
||||||
|
if current_version['build']:
|
||||||
|
req = urllib.request.Request('http://www.openlp.org/files/nightly_version.txt')
|
||||||
|
else:
|
||||||
|
version_parts = current_version['version'].split('.')
|
||||||
|
if int(version_parts[1]) % 2 != 0:
|
||||||
|
req = urllib.request.Request('http://www.openlp.org/files/dev_version.txt')
|
||||||
|
else:
|
||||||
|
req = urllib.request.Request('http://www.openlp.org/files/version.txt')
|
||||||
|
req.add_header('User-Agent', 'OpenLP/%s %s/%s; ' % (current_version['full'], platform.system(),
|
||||||
|
platform.release()))
|
||||||
|
remote_version = None
|
||||||
|
retries = 0
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
remote_version = str(urllib.request.urlopen(req, None,
|
||||||
|
timeout=CONNECTION_TIMEOUT).read().decode()).strip()
|
||||||
|
except (urllib.error.URLError, ConnectionError):
|
||||||
|
if retries > CONNECTION_RETRIES:
|
||||||
|
log.exception('Failed to download the latest OpenLP version file')
|
||||||
|
else:
|
||||||
|
retries += 1
|
||||||
|
time.sleep(0.1)
|
||||||
|
continue
|
||||||
|
break
|
||||||
|
if remote_version:
|
||||||
|
version_string = remote_version
|
||||||
|
return version_string
|
@ -34,9 +34,8 @@ from sqlalchemy.pool import NullPool
|
|||||||
from alembic.migration import MigrationContext
|
from alembic.migration import MigrationContext
|
||||||
from alembic.operations import Operations
|
from alembic.operations import Operations
|
||||||
|
|
||||||
from openlp.core.common import AppLocation, Settings, translate
|
from openlp.core.common import AppLocation, Settings, translate, delete_file
|
||||||
from openlp.core.lib.ui import critical_error_message_box
|
from openlp.core.lib.ui import critical_error_message_box
|
||||||
from openlp.core.utils import delete_file
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -24,11 +24,10 @@ Provide the generic plugin functionality for OpenLP plugins.
|
|||||||
"""
|
"""
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
|
||||||
from PyQt5 import QtCore
|
from PyQt5 import QtCore
|
||||||
|
|
||||||
from openlp.core.common import Registry, RegistryProperties, Settings, UiStrings
|
from openlp.core.common import Registry, RegistryProperties, Settings, UiStrings
|
||||||
from openlp.core.utils import get_application_version
|
from openlp.core.common.versionchecker import get_application_version
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -513,17 +513,13 @@ class PJLink1(QTcpSocket):
|
|||||||
log.debug('(%s) _send_string(): Sending "%s"' % (self.ip, out.strip()))
|
log.debug('(%s) _send_string(): Sending "%s"' % (self.ip, out.strip()))
|
||||||
log.debug('(%s) _send_string(): Queue = %s' % (self.ip, self.send_queue))
|
log.debug('(%s) _send_string(): Queue = %s' % (self.ip, self.send_queue))
|
||||||
self.socket_timer.start()
|
self.socket_timer.start()
|
||||||
try:
|
self.projectorNetwork.emit(S_NETWORK_SENDING)
|
||||||
self.projectorNetwork.emit(S_NETWORK_SENDING)
|
sent = self.write(out.encode('ascii'))
|
||||||
sent = self.write(out.encode('ascii'))
|
self.waitForBytesWritten(2000) # 2 seconds should be enough
|
||||||
self.waitForBytesWritten(2000) # 2 seconds should be enough
|
if sent == -1:
|
||||||
if sent == -1:
|
# Network error?
|
||||||
# Network error?
|
self.change_status(E_NETWORK,
|
||||||
self.change_status(E_NETWORK,
|
translate('OpenLP.PJLink1', 'Error while sending data to projector'))
|
||||||
translate('OpenLP.PJLink1', 'Error while sending data to projector'))
|
|
||||||
except SocketError as e:
|
|
||||||
self.disconnect_from_host(abort=True)
|
|
||||||
self.changeStatus(E_NETWORK, '%s : %s' % (e.error(), e.errorString()))
|
|
||||||
|
|
||||||
def process_command(self, cmd, data):
|
def process_command(self, cmd, data):
|
||||||
"""
|
"""
|
||||||
|
183
openlp/core/lib/webpagereader.py
Normal file
183
openlp/core/lib/webpagereader.py
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# OpenLP - Open Source Lyrics Projection #
|
||||||
|
# --------------------------------------------------------------------------- #
|
||||||
|
# Copyright (c) 2008-2016 OpenLP Developers #
|
||||||
|
# --------------------------------------------------------------------------- #
|
||||||
|
# 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.utils` module provides the utility libraries for OpenLP.
|
||||||
|
"""
|
||||||
|
import logging
|
||||||
|
import socket
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
import urllib.error
|
||||||
|
import urllib.parse
|
||||||
|
import urllib.request
|
||||||
|
from http.client import HTTPException
|
||||||
|
from random import randint
|
||||||
|
|
||||||
|
from openlp.core.common import Registry
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__ + '.__init__')
|
||||||
|
|
||||||
|
USER_AGENTS = {
|
||||||
|
'win32': [
|
||||||
|
'Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.101 Safari/537.36',
|
||||||
|
'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.101 Safari/537.36',
|
||||||
|
'Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.71 Safari/537.36'
|
||||||
|
],
|
||||||
|
'darwin': [
|
||||||
|
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_3) AppleWebKit/537.31 (KHTML, like Gecko) '
|
||||||
|
'Chrome/26.0.1410.43 Safari/537.31',
|
||||||
|
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/536.11 (KHTML, like Gecko) '
|
||||||
|
'Chrome/20.0.1132.57 Safari/536.11',
|
||||||
|
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/536.11 (KHTML, like Gecko) '
|
||||||
|
'Chrome/20.0.1132.47 Safari/536.11',
|
||||||
|
],
|
||||||
|
'linux2': [
|
||||||
|
'Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.22 (KHTML, like Gecko) Ubuntu Chromium/25.0.1364.160 '
|
||||||
|
'Chrome/25.0.1364.160 Safari/537.22',
|
||||||
|
'Mozilla/5.0 (X11; CrOS armv7l 2913.260.0) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.99 '
|
||||||
|
'Safari/537.11',
|
||||||
|
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.27 (KHTML, like Gecko) Chrome/26.0.1389.0 Safari/537.27'
|
||||||
|
],
|
||||||
|
'default': [
|
||||||
|
'Mozilla/5.0 (X11; NetBSD amd64; rv:18.0) Gecko/20130120 Firefox/18.0'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
CONNECTION_TIMEOUT = 30
|
||||||
|
CONNECTION_RETRIES = 2
|
||||||
|
|
||||||
|
|
||||||
|
class HTTPRedirectHandlerFixed(urllib.request.HTTPRedirectHandler):
|
||||||
|
"""
|
||||||
|
Special HTTPRedirectHandler used to work around http://bugs.python.org/issue22248
|
||||||
|
(Redirecting to urls with special chars)
|
||||||
|
"""
|
||||||
|
def redirect_request(self, req, fp, code, msg, headers, new_url):
|
||||||
|
#
|
||||||
|
"""
|
||||||
|
Test if the new_url can be decoded to ascii
|
||||||
|
|
||||||
|
:param req:
|
||||||
|
:param fp:
|
||||||
|
:param code:
|
||||||
|
:param msg:
|
||||||
|
:param headers:
|
||||||
|
:param new_url:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
new_url.encode('latin1').decode('ascii')
|
||||||
|
fixed_url = new_url
|
||||||
|
except Exception:
|
||||||
|
# The url could not be decoded to ascii, so we do some url encoding
|
||||||
|
fixed_url = urllib.parse.quote(new_url.encode('latin1').decode('utf-8', 'replace'), safe='/:')
|
||||||
|
return super(HTTPRedirectHandlerFixed, self).redirect_request(req, fp, code, msg, headers, fixed_url)
|
||||||
|
|
||||||
|
|
||||||
|
def _get_user_agent():
|
||||||
|
"""
|
||||||
|
Return a user agent customised for the platform the user is on.
|
||||||
|
"""
|
||||||
|
browser_list = USER_AGENTS.get(sys.platform, None)
|
||||||
|
if not browser_list:
|
||||||
|
browser_list = USER_AGENTS['default']
|
||||||
|
random_index = randint(0, len(browser_list) - 1)
|
||||||
|
return browser_list[random_index]
|
||||||
|
|
||||||
|
|
||||||
|
def get_web_page(url, header=None, update_openlp=False):
|
||||||
|
"""
|
||||||
|
Attempts to download the webpage at url and returns that page or None.
|
||||||
|
|
||||||
|
:param url: The URL to be downloaded.
|
||||||
|
:param header: An optional HTTP header to pass in the request to the web server.
|
||||||
|
:param update_openlp: Tells OpenLP to update itself if the page is successfully downloaded.
|
||||||
|
Defaults to False.
|
||||||
|
"""
|
||||||
|
# TODO: Add proxy usage. Get proxy info from OpenLP settings, add to a
|
||||||
|
# proxy_handler, build into an opener and install the opener into urllib2.
|
||||||
|
# http://docs.python.org/library/urllib2.html
|
||||||
|
if not url:
|
||||||
|
return None
|
||||||
|
# This is needed to work around http://bugs.python.org/issue22248 and https://bugs.launchpad.net/openlp/+bug/1251437
|
||||||
|
opener = urllib.request.build_opener(HTTPRedirectHandlerFixed())
|
||||||
|
urllib.request.install_opener(opener)
|
||||||
|
req = urllib.request.Request(url)
|
||||||
|
if not header or header[0].lower() != 'user-agent':
|
||||||
|
user_agent = _get_user_agent()
|
||||||
|
req.add_header('User-Agent', user_agent)
|
||||||
|
if header:
|
||||||
|
req.add_header(header[0], header[1])
|
||||||
|
log.debug('Downloading URL = %s' % url)
|
||||||
|
retries = 0
|
||||||
|
while retries <= CONNECTION_RETRIES:
|
||||||
|
retries += 1
|
||||||
|
time.sleep(0.1)
|
||||||
|
try:
|
||||||
|
page = urllib.request.urlopen(req, timeout=CONNECTION_TIMEOUT)
|
||||||
|
log.debug('Downloaded page {}'.format(page.geturl()))
|
||||||
|
break
|
||||||
|
except urllib.error.URLError as err:
|
||||||
|
log.exception('URLError on {}'.format(url))
|
||||||
|
log.exception('URLError: {}'.format(err.reason))
|
||||||
|
page = None
|
||||||
|
if retries > CONNECTION_RETRIES:
|
||||||
|
raise
|
||||||
|
except socket.timeout:
|
||||||
|
log.exception('Socket timeout: {}'.format(url))
|
||||||
|
page = None
|
||||||
|
if retries > CONNECTION_RETRIES:
|
||||||
|
raise
|
||||||
|
except socket.gaierror:
|
||||||
|
log.exception('Socket gaierror: {}'.format(url))
|
||||||
|
page = None
|
||||||
|
if retries > CONNECTION_RETRIES:
|
||||||
|
raise
|
||||||
|
except ConnectionRefusedError:
|
||||||
|
log.exception('ConnectionRefused: {}'.format(url))
|
||||||
|
page = None
|
||||||
|
if retries > CONNECTION_RETRIES:
|
||||||
|
raise
|
||||||
|
break
|
||||||
|
except ConnectionError:
|
||||||
|
log.exception('Connection error: {}'.format(url))
|
||||||
|
page = None
|
||||||
|
if retries > CONNECTION_RETRIES:
|
||||||
|
raise
|
||||||
|
except HTTPException:
|
||||||
|
log.exception('HTTPException error: {}'.format(url))
|
||||||
|
page = None
|
||||||
|
if retries > CONNECTION_RETRIES:
|
||||||
|
raise
|
||||||
|
except:
|
||||||
|
# Don't know what's happening, so reraise the original
|
||||||
|
raise
|
||||||
|
if update_openlp:
|
||||||
|
Registry().get('application').process_events()
|
||||||
|
if not page:
|
||||||
|
log.exception('{} could not be downloaded'.format(url))
|
||||||
|
return None
|
||||||
|
log.debug(page)
|
||||||
|
return page
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = ['get_application_version', 'check_latest_version',
|
||||||
|
'get_web_page']
|
@ -26,8 +26,8 @@ import webbrowser
|
|||||||
|
|
||||||
from PyQt5 import QtCore, QtWidgets
|
from PyQt5 import QtCore, QtWidgets
|
||||||
|
|
||||||
|
from openlp.core.common.versionchecker import get_application_version
|
||||||
from openlp.core.lib import translate
|
from openlp.core.lib import translate
|
||||||
from openlp.core.utils import get_application_version
|
|
||||||
from .aboutdialog import UiAboutDialog
|
from .aboutdialog import UiAboutDialog
|
||||||
|
|
||||||
|
|
||||||
|
@ -29,9 +29,9 @@ import sys
|
|||||||
|
|
||||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
from openlp.core.common import AppLocation, Settings, SlideLimits, UiStrings, translate
|
from openlp.core.common import AppLocation, Settings, SlideLimits, UiStrings, translate, get_images_filter
|
||||||
from openlp.core.lib import ColorButton, SettingsTab, build_icon
|
from openlp.core.lib import ColorButton, SettingsTab, build_icon
|
||||||
from openlp.core.utils import format_time, get_images_filter
|
from openlp.core.common.languagemanager import format_time
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -83,6 +83,13 @@ class AdvancedTab(SettingsTab):
|
|||||||
self.expand_service_item_check_box = QtWidgets.QCheckBox(self.ui_group_box)
|
self.expand_service_item_check_box = QtWidgets.QCheckBox(self.ui_group_box)
|
||||||
self.expand_service_item_check_box.setObjectName('expand_service_item_check_box')
|
self.expand_service_item_check_box.setObjectName('expand_service_item_check_box')
|
||||||
self.ui_layout.addRow(self.expand_service_item_check_box)
|
self.ui_layout.addRow(self.expand_service_item_check_box)
|
||||||
|
self.slide_max_height_label = QtWidgets.QLabel(self.ui_group_box)
|
||||||
|
self.slide_max_height_label.setObjectName('slide_max_height_label')
|
||||||
|
self.slide_max_height_spin_box = QtWidgets.QSpinBox(self.ui_group_box)
|
||||||
|
self.slide_max_height_spin_box.setObjectName('slide_max_height_spin_box')
|
||||||
|
self.slide_max_height_spin_box.setRange(0, 1000)
|
||||||
|
self.slide_max_height_spin_box.setSingleStep(20)
|
||||||
|
self.ui_layout.addRow(self.slide_max_height_label, self.slide_max_height_spin_box)
|
||||||
self.search_as_type_check_box = QtWidgets.QCheckBox(self.ui_group_box)
|
self.search_as_type_check_box = QtWidgets.QCheckBox(self.ui_group_box)
|
||||||
self.search_as_type_check_box.setObjectName('SearchAsType_check_box')
|
self.search_as_type_check_box.setObjectName('SearchAsType_check_box')
|
||||||
self.ui_layout.addRow(self.search_as_type_check_box)
|
self.ui_layout.addRow(self.search_as_type_check_box)
|
||||||
@ -277,6 +284,9 @@ class AdvancedTab(SettingsTab):
|
|||||||
'Preview items when clicked in Service Manager'))
|
'Preview items when clicked in Service Manager'))
|
||||||
self.expand_service_item_check_box.setText(translate('OpenLP.AdvancedTab',
|
self.expand_service_item_check_box.setText(translate('OpenLP.AdvancedTab',
|
||||||
'Expand new service items on creation'))
|
'Expand new service items on creation'))
|
||||||
|
self.slide_max_height_label.setText(translate('OpenLP.AdvancedTab',
|
||||||
|
'Max height for non-text slides\nin slide controller:'))
|
||||||
|
self.slide_max_height_spin_box.setSpecialValueText(translate('OpenLP.AdvancedTab', 'Disabled'))
|
||||||
self.enable_auto_close_check_box.setText(translate('OpenLP.AdvancedTab',
|
self.enable_auto_close_check_box.setText(translate('OpenLP.AdvancedTab',
|
||||||
'Enable application exit confirmation'))
|
'Enable application exit confirmation'))
|
||||||
self.service_name_group_box.setTitle(translate('OpenLP.AdvancedTab', 'Default Service Name'))
|
self.service_name_group_box.setTitle(translate('OpenLP.AdvancedTab', 'Default Service Name'))
|
||||||
@ -346,6 +356,7 @@ class AdvancedTab(SettingsTab):
|
|||||||
self.single_click_preview_check_box.setChecked(settings.value('single click preview'))
|
self.single_click_preview_check_box.setChecked(settings.value('single click preview'))
|
||||||
self.single_click_service_preview_check_box.setChecked(settings.value('single click service preview'))
|
self.single_click_service_preview_check_box.setChecked(settings.value('single click service preview'))
|
||||||
self.expand_service_item_check_box.setChecked(settings.value('expand service item'))
|
self.expand_service_item_check_box.setChecked(settings.value('expand service item'))
|
||||||
|
self.slide_max_height_spin_box.setValue(settings.value('slide max height'))
|
||||||
self.enable_auto_close_check_box.setChecked(settings.value('enable exit confirmation'))
|
self.enable_auto_close_check_box.setChecked(settings.value('enable exit confirmation'))
|
||||||
self.hide_mouse_check_box.setChecked(settings.value('hide mouse'))
|
self.hide_mouse_check_box.setChecked(settings.value('hide mouse'))
|
||||||
self.service_name_day.setCurrentIndex(settings.value('default service day'))
|
self.service_name_day.setCurrentIndex(settings.value('default service day'))
|
||||||
@ -428,6 +439,7 @@ class AdvancedTab(SettingsTab):
|
|||||||
settings.setValue('single click preview', self.single_click_preview_check_box.isChecked())
|
settings.setValue('single click preview', self.single_click_preview_check_box.isChecked())
|
||||||
settings.setValue('single click service preview', self.single_click_service_preview_check_box.isChecked())
|
settings.setValue('single click service preview', self.single_click_service_preview_check_box.isChecked())
|
||||||
settings.setValue('expand service item', self.expand_service_item_check_box.isChecked())
|
settings.setValue('expand service item', self.expand_service_item_check_box.isChecked())
|
||||||
|
settings.setValue('slide max height', self.slide_max_height_spin_box.value())
|
||||||
settings.setValue('enable exit confirmation', self.enable_auto_close_check_box.isChecked())
|
settings.setValue('enable exit confirmation', self.enable_auto_close_check_box.isChecked())
|
||||||
settings.setValue('hide mouse', self.hide_mouse_check_box.isChecked())
|
settings.setValue('hide mouse', self.hide_mouse_check_box.isChecked())
|
||||||
settings.setValue('alternate rows', self.alternate_rows_check_box.isChecked())
|
settings.setValue('alternate rows', self.alternate_rows_check_box.isChecked())
|
||||||
|
@ -23,18 +23,17 @@
|
|||||||
The actual exception dialog form.
|
The actual exception dialog form.
|
||||||
"""
|
"""
|
||||||
import logging
|
import logging
|
||||||
import re
|
|
||||||
import os
|
import os
|
||||||
import platform
|
import platform
|
||||||
|
import re
|
||||||
|
|
||||||
import bs4
|
import bs4
|
||||||
import sqlalchemy
|
import sqlalchemy
|
||||||
|
from PyQt5 import Qt, QtCore, QtGui, QtWebKit, QtWidgets
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
|
|
||||||
from openlp.core.common import RegistryProperties, is_linux
|
from openlp.core.common import RegistryProperties, is_linux
|
||||||
|
|
||||||
from PyQt5 import Qt, QtCore, QtGui, QtWebKit, QtWidgets
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import migrate
|
import migrate
|
||||||
MIGRATE_VERSION = getattr(migrate, '__version__', '< 0.7')
|
MIGRATE_VERSION = getattr(migrate, '__version__', '< 0.7')
|
||||||
@ -74,7 +73,7 @@ except ImportError:
|
|||||||
VLC_VERSION = '-'
|
VLC_VERSION = '-'
|
||||||
|
|
||||||
from openlp.core.common import Settings, UiStrings, translate
|
from openlp.core.common import Settings, UiStrings, translate
|
||||||
from openlp.core.utils import get_application_version
|
from openlp.core.common.versionchecker import get_application_version
|
||||||
|
|
||||||
from .exceptiondialog import Ui_ExceptionDialog
|
from .exceptiondialog import Ui_ExceptionDialog
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ from openlp.core.common import Registry, RegistryProperties, AppLocation, Settin
|
|||||||
translate, clean_button_text, trace_error_handler
|
translate, clean_button_text, trace_error_handler
|
||||||
from openlp.core.lib import PluginStatus, build_icon
|
from openlp.core.lib import PluginStatus, build_icon
|
||||||
from openlp.core.lib.ui import critical_error_message_box
|
from openlp.core.lib.ui import critical_error_message_box
|
||||||
from openlp.core.utils import get_web_page, CONNECTION_RETRIES, CONNECTION_TIMEOUT
|
from openlp.core.lib.webpagereader import get_web_page, CONNECTION_RETRIES, CONNECTION_TIMEOUT
|
||||||
from .firsttimewizard import UiFirstTimeWizard, FirstTimePage
|
from .firsttimewizard import UiFirstTimeWizard, FirstTimePage
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||||
###############################################################################
|
###############################################################################
|
||||||
"""
|
"""
|
||||||
The :mod:`~openlp.core.common.historycombobox` module contains the HistoryComboBox widget
|
The :mod:`~openlp.core.ui.lib.historycombobox` module contains the HistoryComboBox widget
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from PyQt5 import QtCore, QtWidgets
|
from PyQt5 import QtCore, QtWidgets
|
@ -26,7 +26,7 @@ It is based on a QTableWidget but represents its contents in list form.
|
|||||||
|
|
||||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
from openlp.core.common import RegistryProperties
|
from openlp.core.common import RegistryProperties, Settings
|
||||||
from openlp.core.lib import ImageSource, ServiceItem
|
from openlp.core.lib import ImageSource, ServiceItem
|
||||||
|
|
||||||
|
|
||||||
@ -63,6 +63,8 @@ class ListPreviewWidget(QtWidgets.QTableWidget, RegistryProperties):
|
|||||||
# Initialize variables.
|
# Initialize variables.
|
||||||
self.service_item = ServiceItem()
|
self.service_item = ServiceItem()
|
||||||
self.screen_ratio = screen_ratio
|
self.screen_ratio = screen_ratio
|
||||||
|
# Connect signals
|
||||||
|
self.verticalHeader().sectionResized.connect(self.row_resized)
|
||||||
|
|
||||||
def resizeEvent(self, event):
|
def resizeEvent(self, event):
|
||||||
"""
|
"""
|
||||||
@ -80,12 +82,30 @@ class ListPreviewWidget(QtWidgets.QTableWidget, RegistryProperties):
|
|||||||
# Sort out songs, bibles, etc.
|
# Sort out songs, bibles, etc.
|
||||||
if self.service_item.is_text():
|
if self.service_item.is_text():
|
||||||
self.resizeRowsToContents()
|
self.resizeRowsToContents()
|
||||||
|
# Sort out image heights.
|
||||||
else:
|
else:
|
||||||
# Sort out image heights.
|
height = self.viewport().width() // self.screen_ratio
|
||||||
|
max_img_row_height = Settings().value('advanced/slide max height')
|
||||||
|
# Adjust for row height cap if in use.
|
||||||
|
if max_img_row_height > 0 and height > max_img_row_height:
|
||||||
|
height = max_img_row_height
|
||||||
|
# Apply new height to slides
|
||||||
for frame_number in range(len(self.service_item.get_frames())):
|
for frame_number in range(len(self.service_item.get_frames())):
|
||||||
height = self.viewport().width() // self.screen_ratio
|
|
||||||
self.setRowHeight(frame_number, height)
|
self.setRowHeight(frame_number, height)
|
||||||
|
|
||||||
|
def row_resized(self, row, old_height, new_height):
|
||||||
|
"""
|
||||||
|
Will scale non-image slides.
|
||||||
|
"""
|
||||||
|
# Only for non-text slides when row height cap in use
|
||||||
|
if self.service_item.is_text() or Settings().value('advanced/slide max height') <= 0:
|
||||||
|
return
|
||||||
|
# Get and validate label widget containing slide & adjust max width
|
||||||
|
try:
|
||||||
|
self.cellWidget(row, 0).children()[1].setMaximumWidth(new_height * self.screen_ratio)
|
||||||
|
except:
|
||||||
|
return
|
||||||
|
|
||||||
def screen_size_changed(self, screen_ratio):
|
def screen_size_changed(self, screen_ratio):
|
||||||
"""
|
"""
|
||||||
This method is called whenever the live screen size changes, which then makes a layout recalculation necessary
|
This method is called whenever the live screen size changes, which then makes a layout recalculation necessary
|
||||||
@ -139,8 +159,26 @@ class ListPreviewWidget(QtWidgets.QTableWidget, RegistryProperties):
|
|||||||
pixmap = QtGui.QPixmap.fromImage(image)
|
pixmap = QtGui.QPixmap.fromImage(image)
|
||||||
pixmap.setDevicePixelRatio(label.devicePixelRatio())
|
pixmap.setDevicePixelRatio(label.devicePixelRatio())
|
||||||
label.setPixmap(pixmap)
|
label.setPixmap(pixmap)
|
||||||
self.setCellWidget(frame_number, 0, label)
|
|
||||||
slide_height = width // self.screen_ratio
|
slide_height = width // self.screen_ratio
|
||||||
|
# Setup row height cap if in use.
|
||||||
|
max_img_row_height = Settings().value('advanced/slide max height')
|
||||||
|
if max_img_row_height > 0:
|
||||||
|
if slide_height > max_img_row_height:
|
||||||
|
slide_height = max_img_row_height
|
||||||
|
label.setMaximumWidth(max_img_row_height * self.screen_ratio)
|
||||||
|
label.resize(max_img_row_height * self.screen_ratio, max_img_row_height)
|
||||||
|
# Build widget with stretch padding
|
||||||
|
container = QtWidgets.QWidget()
|
||||||
|
hbox = QtWidgets.QHBoxLayout()
|
||||||
|
hbox.setContentsMargins(0, 0, 0, 0)
|
||||||
|
hbox.addWidget(label, stretch=1)
|
||||||
|
hbox.addStretch(0)
|
||||||
|
container.setLayout(hbox)
|
||||||
|
# Add to table
|
||||||
|
self.setCellWidget(frame_number, 0, container)
|
||||||
|
else:
|
||||||
|
# Add to table
|
||||||
|
self.setCellWidget(frame_number, 0, label)
|
||||||
row += 1
|
row += 1
|
||||||
text.append(str(row))
|
text.append(str(row))
|
||||||
self.setItem(frame_number, 0, item)
|
self.setItem(frame_number, 0, item)
|
||||||
|
@ -35,8 +35,9 @@ from tempfile import gettempdir
|
|||||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
from openlp.core.common import Registry, RegistryProperties, AppLocation, LanguageManager, Settings, \
|
from openlp.core.common import Registry, RegistryProperties, AppLocation, LanguageManager, Settings, \
|
||||||
check_directory_exists, translate, is_win, is_macosx
|
check_directory_exists, translate, is_win, is_macosx, add_actions
|
||||||
from openlp.core.common.actions import ActionList, CategoryOrder
|
from openlp.core.common.actions import ActionList, CategoryOrder
|
||||||
|
from openlp.core.common.versionchecker import get_application_version
|
||||||
from openlp.core.lib import Renderer, OpenLPDockWidget, PluginManager, ImageManager, PluginStatus, ScreenList, \
|
from openlp.core.lib import Renderer, OpenLPDockWidget, PluginManager, ImageManager, PluginStatus, ScreenList, \
|
||||||
build_icon
|
build_icon
|
||||||
from openlp.core.lib.ui import UiStrings, create_action
|
from openlp.core.lib.ui import UiStrings, create_action
|
||||||
@ -46,7 +47,6 @@ from openlp.core.ui.firsttimeform import FirstTimeForm
|
|||||||
from openlp.core.ui.media import MediaController
|
from openlp.core.ui.media import MediaController
|
||||||
from openlp.core.ui.printserviceform import PrintServiceForm
|
from openlp.core.ui.printserviceform import PrintServiceForm
|
||||||
from openlp.core.ui.projector.manager import ProjectorManager
|
from openlp.core.ui.projector.manager import ProjectorManager
|
||||||
from openlp.core.utils import get_application_version, add_actions
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -33,12 +33,12 @@ from tempfile import mkstemp
|
|||||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
from openlp.core.common import Registry, RegistryProperties, AppLocation, Settings, ThemeLevel, OpenLPMixin, \
|
from openlp.core.common import Registry, RegistryProperties, AppLocation, Settings, ThemeLevel, OpenLPMixin, \
|
||||||
RegistryMixin, check_directory_exists, UiStrings, translate
|
RegistryMixin, check_directory_exists, UiStrings, translate, split_filename, delete_file
|
||||||
from openlp.core.common.actions import ActionList, CategoryOrder
|
from openlp.core.common.actions import ActionList, CategoryOrder
|
||||||
from openlp.core.lib import OpenLPToolbar, ServiceItem, ItemCapabilities, PluginStatus, build_icon
|
from openlp.core.lib import OpenLPToolbar, ServiceItem, ItemCapabilities, PluginStatus, build_icon
|
||||||
from openlp.core.lib.ui import critical_error_message_box, create_widget_action, find_and_set_in_combo_box
|
from openlp.core.lib.ui import critical_error_message_box, create_widget_action, find_and_set_in_combo_box
|
||||||
from openlp.core.ui import ServiceNoteForm, ServiceItemEditForm, StartTimeForm
|
from openlp.core.ui import ServiceNoteForm, ServiceItemEditForm, StartTimeForm
|
||||||
from openlp.core.utils import delete_file, split_filename, format_time
|
from openlp.core.common.languagemanager import format_time
|
||||||
|
|
||||||
|
|
||||||
class ServiceManagerList(QtWidgets.QTreeWidget):
|
class ServiceManagerList(QtWidgets.QTreeWidget):
|
||||||
|
@ -27,11 +27,10 @@ import os
|
|||||||
|
|
||||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
from openlp.core.common import Registry, RegistryProperties, UiStrings, translate
|
from openlp.core.common import Registry, RegistryProperties, UiStrings, translate, get_images_filter, is_not_image_file
|
||||||
from openlp.core.lib.theme import BackgroundType, BackgroundGradientType
|
from openlp.core.lib.theme import BackgroundType, BackgroundGradientType
|
||||||
from openlp.core.lib.ui import critical_error_message_box
|
from openlp.core.lib.ui import critical_error_message_box
|
||||||
from openlp.core.ui import ThemeLayoutForm
|
from openlp.core.ui import ThemeLayoutForm
|
||||||
from openlp.core.utils import get_images_filter, is_not_image_file
|
|
||||||
from .themewizard import Ui_ThemeWizard
|
from .themewizard import Ui_ThemeWizard
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
@ -30,13 +30,13 @@ from xml.etree.ElementTree import ElementTree, XML
|
|||||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
from openlp.core.common import Registry, RegistryProperties, AppLocation, Settings, OpenLPMixin, RegistryMixin, \
|
from openlp.core.common import Registry, RegistryProperties, AppLocation, Settings, OpenLPMixin, RegistryMixin, \
|
||||||
check_directory_exists, UiStrings, translate, is_win
|
check_directory_exists, UiStrings, translate, is_win, get_filesystem_encoding, delete_file
|
||||||
from openlp.core.lib import FileDialog, ImageSource, OpenLPToolbar, ValidationError, get_text_file_string, build_icon, \
|
from openlp.core.lib import FileDialog, ImageSource, OpenLPToolbar, ValidationError, get_text_file_string, build_icon, \
|
||||||
check_item_selected, create_thumb, validate_thumb
|
check_item_selected, create_thumb, validate_thumb
|
||||||
from openlp.core.lib.theme import ThemeXML, BackgroundType
|
from openlp.core.lib.theme import ThemeXML, BackgroundType
|
||||||
from openlp.core.lib.ui import critical_error_message_box, create_widget_action
|
from openlp.core.lib.ui import critical_error_message_box, create_widget_action
|
||||||
from openlp.core.ui import FileRenameForm, ThemeForm
|
from openlp.core.ui import FileRenameForm, ThemeForm
|
||||||
from openlp.core.utils import delete_file, get_locale_key, get_filesystem_encoding
|
from openlp.core.common.languagemanager import get_locale_key
|
||||||
|
|
||||||
|
|
||||||
class Ui_ThemeManager(object):
|
class Ui_ThemeManager(object):
|
||||||
|
@ -1,539 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
# OpenLP - Open Source Lyrics Projection #
|
|
||||||
# --------------------------------------------------------------------------- #
|
|
||||||
# Copyright (c) 2008-2016 OpenLP Developers #
|
|
||||||
# --------------------------------------------------------------------------- #
|
|
||||||
# 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.utils` module provides the utility libraries for OpenLP.
|
|
||||||
"""
|
|
||||||
import locale
|
|
||||||
import logging
|
|
||||||
import os
|
|
||||||
import platform
|
|
||||||
import re
|
|
||||||
import socket
|
|
||||||
import sys
|
|
||||||
import time
|
|
||||||
import urllib.error
|
|
||||||
import urllib.parse
|
|
||||||
import urllib.request
|
|
||||||
from datetime import datetime
|
|
||||||
from distutils.version import LooseVersion
|
|
||||||
from http.client import HTTPException
|
|
||||||
from random import randint
|
|
||||||
from shutil import which
|
|
||||||
from subprocess import Popen, PIPE
|
|
||||||
|
|
||||||
from PyQt5 import QtGui, QtCore
|
|
||||||
|
|
||||||
from openlp.core.common import Registry, AppLocation, Settings, is_win, is_macosx
|
|
||||||
|
|
||||||
if not is_win() and not is_macosx():
|
|
||||||
try:
|
|
||||||
from xdg import BaseDirectory
|
|
||||||
XDG_BASE_AVAILABLE = True
|
|
||||||
except ImportError:
|
|
||||||
BaseDirectory = None
|
|
||||||
XDG_BASE_AVAILABLE = False
|
|
||||||
|
|
||||||
from openlp.core.common import translate
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__ + '.__init__')
|
|
||||||
|
|
||||||
APPLICATION_VERSION = {}
|
|
||||||
IMAGES_FILTER = None
|
|
||||||
ICU_COLLATOR = None
|
|
||||||
CONTROL_CHARS = re.compile(r'[\x00-\x1F\x7F-\x9F]', re.UNICODE)
|
|
||||||
INVALID_FILE_CHARS = re.compile(r'[\\/:\*\?"<>\|\+\[\]%]', re.UNICODE)
|
|
||||||
DIGITS_OR_NONDIGITS = re.compile(r'\d+|\D+', re.UNICODE)
|
|
||||||
USER_AGENTS = {
|
|
||||||
'win32': [
|
|
||||||
'Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.101 Safari/537.36',
|
|
||||||
'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.101 Safari/537.36',
|
|
||||||
'Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.71 Safari/537.36'
|
|
||||||
],
|
|
||||||
'darwin': [
|
|
||||||
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_3) AppleWebKit/537.31 (KHTML, like Gecko) '
|
|
||||||
'Chrome/26.0.1410.43 Safari/537.31',
|
|
||||||
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/536.11 (KHTML, like Gecko) '
|
|
||||||
'Chrome/20.0.1132.57 Safari/536.11',
|
|
||||||
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/536.11 (KHTML, like Gecko) '
|
|
||||||
'Chrome/20.0.1132.47 Safari/536.11',
|
|
||||||
],
|
|
||||||
'linux2': [
|
|
||||||
'Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.22 (KHTML, like Gecko) Ubuntu Chromium/25.0.1364.160 '
|
|
||||||
'Chrome/25.0.1364.160 Safari/537.22',
|
|
||||||
'Mozilla/5.0 (X11; CrOS armv7l 2913.260.0) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.99 '
|
|
||||||
'Safari/537.11',
|
|
||||||
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.27 (KHTML, like Gecko) Chrome/26.0.1389.0 Safari/537.27'
|
|
||||||
],
|
|
||||||
'default': [
|
|
||||||
'Mozilla/5.0 (X11; NetBSD amd64; rv:18.0) Gecko/20130120 Firefox/18.0'
|
|
||||||
]
|
|
||||||
}
|
|
||||||
CONNECTION_TIMEOUT = 30
|
|
||||||
CONNECTION_RETRIES = 2
|
|
||||||
|
|
||||||
|
|
||||||
class VersionThread(QtCore.QThread):
|
|
||||||
"""
|
|
||||||
A special Qt thread class to fetch the version of OpenLP from the website.
|
|
||||||
This is threaded so that it doesn't affect the loading time of OpenLP.
|
|
||||||
"""
|
|
||||||
def __init__(self, main_window):
|
|
||||||
"""
|
|
||||||
Constructor for the thread class.
|
|
||||||
|
|
||||||
:param main_window: The main window Object.
|
|
||||||
"""
|
|
||||||
log.debug("VersionThread - Initialise")
|
|
||||||
super(VersionThread, self).__init__(None)
|
|
||||||
self.main_window = main_window
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
"""
|
|
||||||
Run the thread.
|
|
||||||
"""
|
|
||||||
self.sleep(1)
|
|
||||||
log.debug('Version thread - run')
|
|
||||||
app_version = get_application_version()
|
|
||||||
version = check_latest_version(app_version)
|
|
||||||
log.debug("Versions %s and %s " % (LooseVersion(str(version)), LooseVersion(str(app_version['full']))))
|
|
||||||
if LooseVersion(str(version)) > LooseVersion(str(app_version['full'])):
|
|
||||||
self.main_window.openlp_version_check.emit('%s' % version)
|
|
||||||
|
|
||||||
|
|
||||||
class HTTPRedirectHandlerFixed(urllib.request.HTTPRedirectHandler):
|
|
||||||
"""
|
|
||||||
Special HTTPRedirectHandler used to work around http://bugs.python.org/issue22248
|
|
||||||
(Redirecting to urls with special chars)
|
|
||||||
"""
|
|
||||||
def redirect_request(self, req, fp, code, msg, headers, new_url):
|
|
||||||
#
|
|
||||||
"""
|
|
||||||
Test if the new_url can be decoded to ascii
|
|
||||||
|
|
||||||
:param req:
|
|
||||||
:param fp:
|
|
||||||
:param code:
|
|
||||||
:param msg:
|
|
||||||
:param headers:
|
|
||||||
:param new_url:
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
new_url.encode('latin1').decode('ascii')
|
|
||||||
fixed_url = new_url
|
|
||||||
except Exception:
|
|
||||||
# The url could not be decoded to ascii, so we do some url encoding
|
|
||||||
fixed_url = urllib.parse.quote(new_url.encode('latin1').decode('utf-8', 'replace'), safe='/:')
|
|
||||||
return super(HTTPRedirectHandlerFixed, self).redirect_request(req, fp, code, msg, headers, fixed_url)
|
|
||||||
|
|
||||||
|
|
||||||
def get_application_version():
|
|
||||||
"""
|
|
||||||
Returns the application version of the running instance of OpenLP::
|
|
||||||
|
|
||||||
{'full': '1.9.4-bzr1249', 'version': '1.9.4', 'build': 'bzr1249'}
|
|
||||||
"""
|
|
||||||
global APPLICATION_VERSION
|
|
||||||
if APPLICATION_VERSION:
|
|
||||||
return APPLICATION_VERSION
|
|
||||||
if '--dev-version' in sys.argv or '-d' in sys.argv:
|
|
||||||
# NOTE: The following code is a duplicate of the code in setup.py. Any fix applied here should also be applied
|
|
||||||
# there.
|
|
||||||
|
|
||||||
# Get the revision of this tree.
|
|
||||||
bzr = Popen(('bzr', 'revno'), stdout=PIPE)
|
|
||||||
tree_revision, error = bzr.communicate()
|
|
||||||
tree_revision = tree_revision.decode()
|
|
||||||
code = bzr.wait()
|
|
||||||
if code != 0:
|
|
||||||
raise Exception('Error running bzr log')
|
|
||||||
|
|
||||||
# Get all tags.
|
|
||||||
bzr = Popen(('bzr', 'tags'), stdout=PIPE)
|
|
||||||
output, error = bzr.communicate()
|
|
||||||
code = bzr.wait()
|
|
||||||
if code != 0:
|
|
||||||
raise Exception('Error running bzr tags')
|
|
||||||
tags = list(map(bytes.decode, output.splitlines()))
|
|
||||||
if not tags:
|
|
||||||
tag_version = '0.0.0'
|
|
||||||
tag_revision = '0'
|
|
||||||
else:
|
|
||||||
# Remove any tag that has "?" as revision number. A "?" as revision number indicates, that this tag is from
|
|
||||||
# another series.
|
|
||||||
tags = [tag for tag in tags if tag.split()[-1].strip() != '?']
|
|
||||||
# Get the last tag and split it in a revision and tag name.
|
|
||||||
tag_version, tag_revision = tags[-1].split()
|
|
||||||
# If they are equal, then this tree is tarball with the source for the release. We do not want the revision
|
|
||||||
# number in the full version.
|
|
||||||
if tree_revision == tag_revision:
|
|
||||||
full_version = tag_version.decode('utf-8')
|
|
||||||
else:
|
|
||||||
full_version = '%s-bzr%s' % (tag_version.decode('utf-8'), tree_revision.decode('utf-8'))
|
|
||||||
else:
|
|
||||||
# We're not running the development version, let's use the file.
|
|
||||||
file_path = AppLocation.get_directory(AppLocation.VersionDir)
|
|
||||||
file_path = os.path.join(file_path, '.version')
|
|
||||||
version_file = None
|
|
||||||
try:
|
|
||||||
version_file = open(file_path, 'r')
|
|
||||||
full_version = str(version_file.read()).rstrip()
|
|
||||||
except IOError:
|
|
||||||
log.exception('Error in version file.')
|
|
||||||
full_version = '0.0.0-bzr000'
|
|
||||||
finally:
|
|
||||||
if version_file:
|
|
||||||
version_file.close()
|
|
||||||
bits = full_version.split('-')
|
|
||||||
APPLICATION_VERSION = {
|
|
||||||
'full': full_version,
|
|
||||||
'version': bits[0],
|
|
||||||
'build': bits[1] if len(bits) > 1 else None
|
|
||||||
}
|
|
||||||
if APPLICATION_VERSION['build']:
|
|
||||||
log.info('Openlp version %s build %s', APPLICATION_VERSION['version'], APPLICATION_VERSION['build'])
|
|
||||||
else:
|
|
||||||
log.info('Openlp version %s' % APPLICATION_VERSION['version'])
|
|
||||||
return APPLICATION_VERSION
|
|
||||||
|
|
||||||
|
|
||||||
def check_latest_version(current_version):
|
|
||||||
"""
|
|
||||||
Check the latest version of OpenLP against the version file on the OpenLP
|
|
||||||
site.
|
|
||||||
|
|
||||||
**Rules around versions and version files:**
|
|
||||||
|
|
||||||
* If a version number has a build (i.e. -bzr1234), then it is a nightly.
|
|
||||||
* If a version number's minor version is an odd number, it is a development release.
|
|
||||||
* If a version number's minor version is an even number, it is a stable release.
|
|
||||||
|
|
||||||
:param current_version: The current version of OpenLP.
|
|
||||||
"""
|
|
||||||
version_string = current_version['full']
|
|
||||||
# set to prod in the distribution config file.
|
|
||||||
settings = Settings()
|
|
||||||
settings.beginGroup('core')
|
|
||||||
last_test = settings.value('last version test')
|
|
||||||
this_test = str(datetime.now().date())
|
|
||||||
settings.setValue('last version test', this_test)
|
|
||||||
settings.endGroup()
|
|
||||||
if last_test != this_test:
|
|
||||||
if current_version['build']:
|
|
||||||
req = urllib.request.Request('http://www.openlp.org/files/nightly_version.txt')
|
|
||||||
else:
|
|
||||||
version_parts = current_version['version'].split('.')
|
|
||||||
if int(version_parts[1]) % 2 != 0:
|
|
||||||
req = urllib.request.Request('http://www.openlp.org/files/dev_version.txt')
|
|
||||||
else:
|
|
||||||
req = urllib.request.Request('http://www.openlp.org/files/version.txt')
|
|
||||||
req.add_header('User-Agent', 'OpenLP/%s %s/%s; ' % (current_version['full'], platform.system(),
|
|
||||||
platform.release()))
|
|
||||||
remote_version = None
|
|
||||||
retries = 0
|
|
||||||
while True:
|
|
||||||
try:
|
|
||||||
remote_version = str(urllib.request.urlopen(req, None,
|
|
||||||
timeout=CONNECTION_TIMEOUT).read().decode()).strip()
|
|
||||||
except (urllib.error.URLError, ConnectionError):
|
|
||||||
if retries > CONNECTION_RETRIES:
|
|
||||||
log.exception('Failed to download the latest OpenLP version file')
|
|
||||||
else:
|
|
||||||
retries += 1
|
|
||||||
time.sleep(0.1)
|
|
||||||
continue
|
|
||||||
break
|
|
||||||
if remote_version:
|
|
||||||
version_string = remote_version
|
|
||||||
return version_string
|
|
||||||
|
|
||||||
|
|
||||||
def add_actions(target, actions):
|
|
||||||
"""
|
|
||||||
Adds multiple actions to a menu or toolbar in one command.
|
|
||||||
|
|
||||||
:param target: The menu or toolbar to add actions to
|
|
||||||
:param actions: The actions to be added. An action consisting of the keyword ``None``
|
|
||||||
will result in a separator being inserted into the target.
|
|
||||||
"""
|
|
||||||
for action in actions:
|
|
||||||
if action is None:
|
|
||||||
target.addSeparator()
|
|
||||||
else:
|
|
||||||
target.addAction(action)
|
|
||||||
|
|
||||||
|
|
||||||
def get_filesystem_encoding():
|
|
||||||
"""
|
|
||||||
Returns the name of the encoding used to convert Unicode filenames into system file names.
|
|
||||||
"""
|
|
||||||
encoding = sys.getfilesystemencoding()
|
|
||||||
if encoding is None:
|
|
||||||
encoding = sys.getdefaultencoding()
|
|
||||||
return encoding
|
|
||||||
|
|
||||||
|
|
||||||
def get_images_filter():
|
|
||||||
"""
|
|
||||||
Returns a filter string for a file dialog containing all the supported image formats.
|
|
||||||
"""
|
|
||||||
global IMAGES_FILTER
|
|
||||||
if not IMAGES_FILTER:
|
|
||||||
log.debug('Generating images filter.')
|
|
||||||
formats = list(map(bytes.decode, list(map(bytes, QtGui.QImageReader.supportedImageFormats()))))
|
|
||||||
visible_formats = '(*.%s)' % '; *.'.join(formats)
|
|
||||||
actual_formats = '(*.%s)' % ' *.'.join(formats)
|
|
||||||
IMAGES_FILTER = '%s %s %s' % (translate('OpenLP', 'Image Files'), visible_formats, actual_formats)
|
|
||||||
return IMAGES_FILTER
|
|
||||||
|
|
||||||
|
|
||||||
def is_not_image_file(file_name):
|
|
||||||
"""
|
|
||||||
Validate that the file is not an image file.
|
|
||||||
|
|
||||||
:param file_name: File name to be checked.
|
|
||||||
"""
|
|
||||||
if not file_name:
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
formats = [bytes(fmt).decode().lower() for fmt in QtGui.QImageReader.supportedImageFormats()]
|
|
||||||
file_part, file_extension = os.path.splitext(str(file_name))
|
|
||||||
if file_extension[1:].lower() in formats and os.path.exists(file_name):
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def split_filename(path):
|
|
||||||
"""
|
|
||||||
Return a list of the parts in a given path.
|
|
||||||
"""
|
|
||||||
path = os.path.abspath(path)
|
|
||||||
if not os.path.isfile(path):
|
|
||||||
return path, ''
|
|
||||||
else:
|
|
||||||
return os.path.split(path)
|
|
||||||
|
|
||||||
|
|
||||||
def clean_filename(filename):
|
|
||||||
"""
|
|
||||||
Removes invalid characters from the given ``filename``.
|
|
||||||
|
|
||||||
:param filename: The "dirty" file name to clean.
|
|
||||||
"""
|
|
||||||
if not isinstance(filename, str):
|
|
||||||
filename = str(filename, 'utf-8')
|
|
||||||
return INVALID_FILE_CHARS.sub('_', CONTROL_CHARS.sub('', filename))
|
|
||||||
|
|
||||||
|
|
||||||
def delete_file(file_path_name):
|
|
||||||
"""
|
|
||||||
Deletes a file from the system.
|
|
||||||
|
|
||||||
:param file_path_name: The file, including path, to delete.
|
|
||||||
"""
|
|
||||||
if not file_path_name:
|
|
||||||
return False
|
|
||||||
try:
|
|
||||||
if os.path.exists(file_path_name):
|
|
||||||
os.remove(file_path_name)
|
|
||||||
return True
|
|
||||||
except (IOError, OSError):
|
|
||||||
log.exception("Unable to delete file %s" % file_path_name)
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def _get_user_agent():
|
|
||||||
"""
|
|
||||||
Return a user agent customised for the platform the user is on.
|
|
||||||
"""
|
|
||||||
browser_list = USER_AGENTS.get(sys.platform, None)
|
|
||||||
if not browser_list:
|
|
||||||
browser_list = USER_AGENTS['default']
|
|
||||||
random_index = randint(0, len(browser_list) - 1)
|
|
||||||
return browser_list[random_index]
|
|
||||||
|
|
||||||
|
|
||||||
def get_web_page(url, header=None, update_openlp=False):
|
|
||||||
"""
|
|
||||||
Attempts to download the webpage at url and returns that page or None.
|
|
||||||
|
|
||||||
:param url: The URL to be downloaded.
|
|
||||||
:param header: An optional HTTP header to pass in the request to the web server.
|
|
||||||
:param update_openlp: Tells OpenLP to update itself if the page is successfully downloaded.
|
|
||||||
Defaults to False.
|
|
||||||
"""
|
|
||||||
# TODO: Add proxy usage. Get proxy info from OpenLP settings, add to a
|
|
||||||
# proxy_handler, build into an opener and install the opener into urllib2.
|
|
||||||
# http://docs.python.org/library/urllib2.html
|
|
||||||
if not url:
|
|
||||||
return None
|
|
||||||
# This is needed to work around http://bugs.python.org/issue22248 and https://bugs.launchpad.net/openlp/+bug/1251437
|
|
||||||
opener = urllib.request.build_opener(HTTPRedirectHandlerFixed())
|
|
||||||
urllib.request.install_opener(opener)
|
|
||||||
req = urllib.request.Request(url)
|
|
||||||
if not header or header[0].lower() != 'user-agent':
|
|
||||||
user_agent = _get_user_agent()
|
|
||||||
req.add_header('User-Agent', user_agent)
|
|
||||||
if header:
|
|
||||||
req.add_header(header[0], header[1])
|
|
||||||
log.debug('Downloading URL = %s' % url)
|
|
||||||
retries = 0
|
|
||||||
while retries <= CONNECTION_RETRIES:
|
|
||||||
retries += 1
|
|
||||||
time.sleep(0.1)
|
|
||||||
try:
|
|
||||||
page = urllib.request.urlopen(req, timeout=CONNECTION_TIMEOUT)
|
|
||||||
log.debug('Downloaded page {}'.format(page.geturl()))
|
|
||||||
break
|
|
||||||
except urllib.error.URLError as err:
|
|
||||||
log.exception('URLError on {}'.format(url))
|
|
||||||
log.exception('URLError: {}'.format(err.reason))
|
|
||||||
page = None
|
|
||||||
if retries > CONNECTION_RETRIES:
|
|
||||||
raise
|
|
||||||
except socket.timeout:
|
|
||||||
log.exception('Socket timeout: {}'.format(url))
|
|
||||||
page = None
|
|
||||||
if retries > CONNECTION_RETRIES:
|
|
||||||
raise
|
|
||||||
except socket.gaierror:
|
|
||||||
log.exception('Socket gaierror: {}'.format(url))
|
|
||||||
page = None
|
|
||||||
if retries > CONNECTION_RETRIES:
|
|
||||||
raise
|
|
||||||
except ConnectionRefusedError:
|
|
||||||
log.exception('ConnectionRefused: {}'.format(url))
|
|
||||||
page = None
|
|
||||||
if retries > CONNECTION_RETRIES:
|
|
||||||
raise
|
|
||||||
break
|
|
||||||
except ConnectionError:
|
|
||||||
log.exception('Connection error: {}'.format(url))
|
|
||||||
page = None
|
|
||||||
if retries > CONNECTION_RETRIES:
|
|
||||||
raise
|
|
||||||
except HTTPException:
|
|
||||||
log.exception('HTTPException error: {}'.format(url))
|
|
||||||
page = None
|
|
||||||
if retries > CONNECTION_RETRIES:
|
|
||||||
raise
|
|
||||||
except:
|
|
||||||
# Don't know what's happening, so reraise the original
|
|
||||||
raise
|
|
||||||
if update_openlp:
|
|
||||||
Registry().get('application').process_events()
|
|
||||||
if not page:
|
|
||||||
log.exception('{} could not be downloaded'.format(url))
|
|
||||||
return None
|
|
||||||
log.debug(page)
|
|
||||||
return page
|
|
||||||
|
|
||||||
|
|
||||||
def get_uno_command(connection_type='pipe'):
|
|
||||||
"""
|
|
||||||
Returns the UNO command to launch an openoffice.org instance.
|
|
||||||
"""
|
|
||||||
for command in ['libreoffice', 'soffice']:
|
|
||||||
if which(command):
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
raise FileNotFoundError('Command not found')
|
|
||||||
|
|
||||||
OPTIONS = '--nologo --norestore --minimized --nodefault --nofirststartwizard'
|
|
||||||
if connection_type == 'pipe':
|
|
||||||
CONNECTION = '"--accept=pipe,name=openlp_pipe;urp;"'
|
|
||||||
else:
|
|
||||||
CONNECTION = '"--accept=socket,host=localhost,port=2002;urp;"'
|
|
||||||
return '%s %s %s' % (command, OPTIONS, CONNECTION)
|
|
||||||
|
|
||||||
|
|
||||||
def get_uno_instance(resolver, connection_type='pipe'):
|
|
||||||
"""
|
|
||||||
Returns a running openoffice.org instance.
|
|
||||||
|
|
||||||
:param resolver: The UNO resolver to use to find a running instance.
|
|
||||||
"""
|
|
||||||
log.debug('get UNO Desktop Openoffice - resolve')
|
|
||||||
if connection_type == 'pipe':
|
|
||||||
return resolver.resolve('uno:pipe,name=openlp_pipe;urp;StarOffice.ComponentContext')
|
|
||||||
else:
|
|
||||||
return resolver.resolve('uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext')
|
|
||||||
|
|
||||||
|
|
||||||
def format_time(text, local_time):
|
|
||||||
"""
|
|
||||||
Workaround for Python built-in time formatting function time.strftime().
|
|
||||||
|
|
||||||
time.strftime() accepts only ascii characters. This function accepts
|
|
||||||
unicode string and passes individual % placeholders to time.strftime().
|
|
||||||
This ensures only ascii characters are passed to time.strftime().
|
|
||||||
|
|
||||||
:param text: The text to be processed.
|
|
||||||
:param local_time: The time to be used to add to the string. This is a time object
|
|
||||||
"""
|
|
||||||
def match_formatting(match):
|
|
||||||
"""
|
|
||||||
Format the match
|
|
||||||
"""
|
|
||||||
return local_time.strftime(match.group())
|
|
||||||
return re.sub('\%[a-zA-Z]', match_formatting, text)
|
|
||||||
|
|
||||||
|
|
||||||
def get_locale_key(string):
|
|
||||||
"""
|
|
||||||
Creates a key for case insensitive, locale aware string sorting.
|
|
||||||
|
|
||||||
:param string: The corresponding string.
|
|
||||||
"""
|
|
||||||
string = string.lower()
|
|
||||||
# ICU is the prefered way to handle locale sort key, we fallback to locale.strxfrm which will work in most cases.
|
|
||||||
global ICU_COLLATOR
|
|
||||||
try:
|
|
||||||
if ICU_COLLATOR is None:
|
|
||||||
import icu
|
|
||||||
from openlp.core.common.languagemanager import LanguageManager
|
|
||||||
language = LanguageManager.get_language()
|
|
||||||
icu_locale = icu.Locale(language)
|
|
||||||
ICU_COLLATOR = icu.Collator.createInstance(icu_locale)
|
|
||||||
return ICU_COLLATOR.getSortKey(string)
|
|
||||||
except:
|
|
||||||
return locale.strxfrm(string).encode()
|
|
||||||
|
|
||||||
|
|
||||||
def get_natural_key(string):
|
|
||||||
"""
|
|
||||||
Generate a key for locale aware natural string sorting.
|
|
||||||
|
|
||||||
:param string: string to be sorted by
|
|
||||||
Returns a list of string compare keys and integers.
|
|
||||||
"""
|
|
||||||
key = DIGITS_OR_NONDIGITS.findall(string)
|
|
||||||
key = [int(part) if part.isdigit() else get_locale_key(part) for part in key]
|
|
||||||
# Python 3 does not support comparison of different types anymore. So make sure, that we do not compare str
|
|
||||||
# and int.
|
|
||||||
if string and string[0].isdigit():
|
|
||||||
return [b''] + key
|
|
||||||
return key
|
|
||||||
|
|
||||||
__all__ = ['get_application_version', 'check_latest_version',
|
|
||||||
'add_actions', 'get_filesystem_encoding', 'get_web_page', 'get_uno_command', 'get_uno_instance',
|
|
||||||
'delete_file', 'clean_filename', 'format_time', 'get_locale_key', 'get_natural_key']
|
|
@ -28,11 +28,11 @@ import urllib.error
|
|||||||
|
|
||||||
from PyQt5 import QtWidgets
|
from PyQt5 import QtWidgets
|
||||||
|
|
||||||
from openlp.core.common import AppLocation, Settings, UiStrings, translate
|
from openlp.core.common import AppLocation, Settings, UiStrings, translate, clean_filename
|
||||||
from openlp.core.lib.db import delete_database
|
from openlp.core.lib.db import delete_database
|
||||||
from openlp.core.lib.ui import critical_error_message_box
|
from openlp.core.lib.ui import critical_error_message_box
|
||||||
from openlp.core.ui.wizard import OpenLPWizard, WizardStrings
|
from openlp.core.ui.wizard import OpenLPWizard, WizardStrings
|
||||||
from openlp.core.utils import get_locale_key
|
from openlp.core.common.languagemanager import get_locale_key
|
||||||
from openlp.plugins.bibles.lib.manager import BibleFormat
|
from openlp.plugins.bibles.lib.manager import BibleFormat
|
||||||
from openlp.plugins.bibles.lib.db import BiblesResourcesDB, clean_filename
|
from openlp.plugins.bibles.lib.db import BiblesResourcesDB, clean_filename
|
||||||
from openlp.plugins.bibles.lib.http import CWExtract, BGExtract, BSExtract
|
from openlp.plugins.bibles.lib.http import CWExtract, BGExtract, BSExtract
|
||||||
|
@ -29,10 +29,10 @@ from tempfile import gettempdir
|
|||||||
|
|
||||||
from PyQt5 import QtCore, QtWidgets
|
from PyQt5 import QtCore, QtWidgets
|
||||||
|
|
||||||
from openlp.core.common import Registry, AppLocation, UiStrings, Settings, check_directory_exists, translate
|
from openlp.core.common import Registry, AppLocation, UiStrings, Settings, check_directory_exists, translate, \
|
||||||
|
delete_file
|
||||||
from openlp.core.lib.ui import critical_error_message_box
|
from openlp.core.lib.ui import critical_error_message_box
|
||||||
from openlp.core.ui.wizard import OpenLPWizard, WizardStrings
|
from openlp.core.ui.wizard import OpenLPWizard, WizardStrings
|
||||||
from openlp.core.utils import delete_file
|
|
||||||
from openlp.plugins.bibles.lib.db import BibleDB, BibleMeta, OldBibleDB, BiblesResourcesDB
|
from openlp.plugins.bibles.lib.db import BibleDB, BibleMeta, OldBibleDB, BiblesResourcesDB
|
||||||
from openlp.plugins.bibles.lib.http import BSExtract, BGExtract, CWExtract
|
from openlp.plugins.bibles.lib.http import BSExtract, BGExtract, CWExtract
|
||||||
|
|
||||||
|
@ -33,10 +33,9 @@ from sqlalchemy.exc import OperationalError
|
|||||||
from sqlalchemy.orm import class_mapper, mapper, relation
|
from sqlalchemy.orm import class_mapper, mapper, relation
|
||||||
from sqlalchemy.orm.exc import UnmappedClassError
|
from sqlalchemy.orm.exc import UnmappedClassError
|
||||||
|
|
||||||
from openlp.core.common import Registry, RegistryProperties, AppLocation, translate
|
from openlp.core.common import Registry, RegistryProperties, AppLocation, translate, clean_filename
|
||||||
from openlp.core.lib.db import BaseModel, init_db, Manager
|
from openlp.core.lib.db import BaseModel, init_db, Manager
|
||||||
from openlp.core.lib.ui import critical_error_message_box
|
from openlp.core.lib.ui import critical_error_message_box
|
||||||
from openlp.core.utils import clean_filename
|
|
||||||
from openlp.plugins.bibles.lib import upgrade
|
from openlp.plugins.bibles.lib import upgrade
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
@ -32,7 +32,7 @@ from bs4 import BeautifulSoup, NavigableString, Tag
|
|||||||
|
|
||||||
from openlp.core.common import Registry, RegistryProperties, translate
|
from openlp.core.common import Registry, RegistryProperties, translate
|
||||||
from openlp.core.lib.ui import critical_error_message_box
|
from openlp.core.lib.ui import critical_error_message_box
|
||||||
from openlp.core.utils import get_web_page
|
from openlp.core.lib.webpagereader import get_web_page
|
||||||
from openlp.plugins.bibles.lib import SearchResults
|
from openlp.plugins.bibles.lib import SearchResults
|
||||||
from openlp.plugins.bibles.lib.db import BibleDB, BiblesResourcesDB, Book
|
from openlp.plugins.bibles.lib.db import BibleDB, BiblesResourcesDB, Book
|
||||||
|
|
||||||
|
@ -23,8 +23,7 @@
|
|||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from openlp.core.common import RegistryProperties, AppLocation, Settings, translate
|
from openlp.core.common import RegistryProperties, AppLocation, Settings, translate, delete_file
|
||||||
from openlp.core.utils import delete_file
|
|
||||||
from openlp.plugins.bibles.lib import parse_reference, get_reference_separator, LanguageSelection
|
from openlp.plugins.bibles.lib import parse_reference, get_reference_separator, LanguageSelection
|
||||||
from openlp.plugins.bibles.lib.db import BibleDB, BibleMeta
|
from openlp.plugins.bibles.lib.db import BibleDB, BibleMeta
|
||||||
from .csvbible import CSVBible
|
from .csvbible import CSVBible
|
||||||
|
@ -29,7 +29,7 @@ from openlp.core.lib import MediaManagerItem, ItemCapabilities, ServiceItemConte
|
|||||||
from openlp.core.lib.searchedit import SearchEdit
|
from openlp.core.lib.searchedit import SearchEdit
|
||||||
from openlp.core.lib.ui import set_case_insensitive_completer, create_horizontal_adjusting_combo_box, \
|
from openlp.core.lib.ui import set_case_insensitive_completer, create_horizontal_adjusting_combo_box, \
|
||||||
critical_error_message_box, find_and_set_in_combo_box, build_icon
|
critical_error_message_box, find_and_set_in_combo_box, build_icon
|
||||||
from openlp.core.utils import get_locale_key
|
from openlp.core.common.languagemanager import get_locale_key
|
||||||
from openlp.plugins.bibles.forms.bibleimportform import BibleImportForm
|
from openlp.plugins.bibles.forms.bibleimportform import BibleImportForm
|
||||||
from openlp.plugins.bibles.forms.editbibleform import EditBibleForm
|
from openlp.plugins.bibles.forms.editbibleform import EditBibleForm
|
||||||
from openlp.plugins.bibles.lib import LayoutStyle, DisplayStyle, VerseReferenceList, get_reference_separator, \
|
from openlp.plugins.bibles.lib import LayoutStyle, DisplayStyle, VerseReferenceList, get_reference_separator, \
|
||||||
|
@ -28,7 +28,7 @@ from sqlalchemy import Column, Table, types
|
|||||||
from sqlalchemy.orm import mapper
|
from sqlalchemy.orm import mapper
|
||||||
|
|
||||||
from openlp.core.lib.db import BaseModel, init_db
|
from openlp.core.lib.db import BaseModel, init_db
|
||||||
from openlp.core.utils import get_locale_key
|
from openlp.core.common.languagemanager import get_locale_key
|
||||||
|
|
||||||
|
|
||||||
class CustomSlide(BaseModel):
|
class CustomSlide(BaseModel):
|
||||||
|
@ -25,11 +25,12 @@ import os
|
|||||||
|
|
||||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
from openlp.core.common import Registry, AppLocation, Settings, UiStrings, check_directory_exists, translate
|
from openlp.core.common import Registry, AppLocation, Settings, UiStrings, check_directory_exists, translate, \
|
||||||
|
delete_file, get_images_filter
|
||||||
from openlp.core.lib import ItemCapabilities, MediaManagerItem, ServiceItemContext, StringContent, TreeWidgetWithDnD,\
|
from openlp.core.lib import ItemCapabilities, MediaManagerItem, ServiceItemContext, StringContent, TreeWidgetWithDnD,\
|
||||||
build_icon, check_item_selected, create_thumb, validate_thumb
|
build_icon, check_item_selected, create_thumb, validate_thumb
|
||||||
from openlp.core.lib.ui import create_widget_action, critical_error_message_box
|
from openlp.core.lib.ui import create_widget_action, critical_error_message_box
|
||||||
from openlp.core.utils import delete_file, get_locale_key, get_images_filter
|
from openlp.core.common.languagemanager import get_locale_key
|
||||||
from openlp.plugins.images.forms import AddGroupForm, ChooseGroupForm
|
from openlp.plugins.images.forms import AddGroupForm, ChooseGroupForm
|
||||||
from openlp.plugins.images.lib.db import ImageFilenames, ImageGroups
|
from openlp.plugins.images.lib.db import ImageFilenames, ImageGroups
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ from openlp.core.lib import ItemCapabilities, MediaManagerItem, MediaType, Servi
|
|||||||
from openlp.core.lib.ui import critical_error_message_box, create_horizontal_adjusting_combo_box
|
from openlp.core.lib.ui import critical_error_message_box, create_horizontal_adjusting_combo_box
|
||||||
from openlp.core.ui import DisplayController, Display, DisplayControllerType
|
from openlp.core.ui import DisplayController, Display, DisplayControllerType
|
||||||
from openlp.core.ui.media import get_media_players, set_media_players, parse_optical_path, format_milliseconds
|
from openlp.core.ui.media import get_media_players, set_media_players, parse_optical_path, format_milliseconds
|
||||||
from openlp.core.utils import get_locale_key
|
from openlp.core.common.languagemanager import get_locale_key
|
||||||
from openlp.core.ui.media.vlcplayer import get_vlc
|
from openlp.core.ui.media.vlcplayer import get_vlc
|
||||||
|
|
||||||
if get_vlc() is not None:
|
if get_vlc() is not None:
|
||||||
|
@ -35,7 +35,7 @@ import logging
|
|||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from openlp.core.common import is_win, Registry
|
from openlp.core.common import is_win, Registry, get_uno_command, get_uno_instance, delete_file
|
||||||
|
|
||||||
if is_win():
|
if is_win():
|
||||||
from win32com.client import Dispatch
|
from win32com.client import Dispatch
|
||||||
@ -57,7 +57,7 @@ else:
|
|||||||
from PyQt5 import QtCore
|
from PyQt5 import QtCore
|
||||||
|
|
||||||
from openlp.core.lib import ScreenList
|
from openlp.core.lib import ScreenList
|
||||||
from openlp.core.utils import delete_file, get_uno_command, get_uno_instance
|
from openlp.core.common import get_uno_command, get_uno_instance
|
||||||
from .presentationcontroller import PresentationController, PresentationDocument, TextType
|
from .presentationcontroller import PresentationController, PresentationDocument, TextType
|
||||||
|
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ from openlp.core.common import Registry, Settings, UiStrings, translate
|
|||||||
from openlp.core.lib import MediaManagerItem, ItemCapabilities, ServiceItemContext,\
|
from openlp.core.lib import MediaManagerItem, ItemCapabilities, ServiceItemContext,\
|
||||||
build_icon, check_item_selected, create_thumb, validate_thumb
|
build_icon, check_item_selected, create_thumb, validate_thumb
|
||||||
from openlp.core.lib.ui import critical_error_message_box, create_horizontal_adjusting_combo_box
|
from openlp.core.lib.ui import critical_error_message_box, create_horizontal_adjusting_combo_box
|
||||||
from openlp.core.utils import get_locale_key
|
from openlp.core.common.languagemanager import get_locale_key
|
||||||
from openlp.plugins.presentations.lib import MessageListener
|
from openlp.plugins.presentations.lib import MessageListener
|
||||||
from openlp.plugins.presentations.lib.pdfcontroller import PDF_CONTROLLER_FILETYPES
|
from openlp.plugins.presentations.lib.pdfcontroller import PDF_CONTROLLER_FILETYPES
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ import re
|
|||||||
from shutil import which
|
from shutil import which
|
||||||
from subprocess import check_output, CalledProcessError, STDOUT
|
from subprocess import check_output, CalledProcessError, STDOUT
|
||||||
|
|
||||||
from openlp.core.utils import AppLocation
|
from openlp.core.common import AppLocation
|
||||||
from openlp.core.common import Settings, is_win, trace_error_handler
|
from openlp.core.common import Settings, is_win, trace_error_handler
|
||||||
from openlp.core.lib import ScreenList
|
from openlp.core.lib import ScreenList
|
||||||
from .presentationcontroller import PresentationController, PresentationDocument
|
from .presentationcontroller import PresentationController, PresentationDocument
|
||||||
|
@ -20,7 +20,6 @@
|
|||||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
import logging
|
|
||||||
import os
|
import os
|
||||||
import logging
|
import logging
|
||||||
import zipfile
|
import zipfile
|
||||||
@ -34,7 +33,7 @@ if is_win():
|
|||||||
from ctypes import cdll
|
from ctypes import cdll
|
||||||
from ctypes.wintypes import RECT
|
from ctypes.wintypes import RECT
|
||||||
|
|
||||||
from openlp.core.utils import AppLocation
|
from openlp.core.common import AppLocation
|
||||||
from openlp.core.lib import ScreenList
|
from openlp.core.lib import ScreenList
|
||||||
from .presentationcontroller import PresentationController, PresentationDocument
|
from .presentationcontroller import PresentationController, PresentationDocument
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ The :mod:`~openlp.plugins.songs.forms.songselectdialog` module contains the user
|
|||||||
|
|
||||||
from PyQt5 import QtCore, QtWidgets
|
from PyQt5 import QtCore, QtWidgets
|
||||||
|
|
||||||
from openlp.core.common import HistoryComboBox
|
from openlp.core.ui.lib.historycombobox import HistoryComboBox
|
||||||
from openlp.core.lib import translate, build_icon
|
from openlp.core.lib import translate, build_icon
|
||||||
from openlp.core.ui import SingleColumnTableWidget
|
from openlp.core.ui import SingleColumnTableWidget
|
||||||
|
|
||||||
|
@ -29,9 +29,8 @@ import re
|
|||||||
|
|
||||||
from PyQt5 import QtWidgets
|
from PyQt5 import QtWidgets
|
||||||
|
|
||||||
from openlp.core.common import AppLocation
|
from openlp.core.common import AppLocation, CONTROL_CHARS
|
||||||
from openlp.core.lib import translate
|
from openlp.core.lib import translate
|
||||||
from openlp.core.utils import CONTROL_CHARS
|
|
||||||
from openlp.plugins.songs.lib.db import MediaFile, Song
|
from openlp.plugins.songs.lib.db import MediaFile, Song
|
||||||
from .db import Author
|
from .db import Author
|
||||||
from .ui import SongStrings
|
from .ui import SongStrings
|
||||||
|
@ -29,7 +29,7 @@ from sqlalchemy.orm import mapper, relation, reconstructor
|
|||||||
from sqlalchemy.sql.expression import func, text
|
from sqlalchemy.sql.expression import func, text
|
||||||
|
|
||||||
from openlp.core.lib.db import BaseModel, init_db
|
from openlp.core.lib.db import BaseModel, init_db
|
||||||
from openlp.core.utils import get_natural_key
|
from openlp.core.common.languagemanager import get_natural_key
|
||||||
from openlp.core.lib import translate
|
from openlp.core.lib import translate
|
||||||
|
|
||||||
|
|
||||||
|
@ -313,9 +313,9 @@ class SongFormat(object):
|
|||||||
},
|
},
|
||||||
ProPresenter: {
|
ProPresenter: {
|
||||||
'class': ProPresenterImport,
|
'class': ProPresenterImport,
|
||||||
'name': 'ProPresenter 4',
|
'name': 'ProPresenter 4, 5 and 6',
|
||||||
'prefix': 'proPresenter',
|
'prefix': 'proPresenter',
|
||||||
'filter': '%s (*.pro4)' % translate('SongsPlugin.ImportWizardForm', 'ProPresenter 4 Song Files')
|
'filter': '%s (*.pro4 *.pro5 *.pro6)' % translate('SongsPlugin.ImportWizardForm', 'ProPresenter Song Files')
|
||||||
},
|
},
|
||||||
SongBeamer: {
|
SongBeamer: {
|
||||||
'class': SongBeamerImport,
|
'class': SongBeamerImport,
|
||||||
|
@ -25,8 +25,7 @@ import time
|
|||||||
|
|
||||||
from PyQt5 import QtCore
|
from PyQt5 import QtCore
|
||||||
|
|
||||||
from openlp.core.common import is_win
|
from openlp.core.common import is_win, get_uno_command, get_uno_instance
|
||||||
from openlp.core.utils import get_uno_command, get_uno_instance
|
|
||||||
from openlp.core.lib import translate
|
from openlp.core.lib import translate
|
||||||
from .songimport import SongImport
|
from .songimport import SongImport
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ log = logging.getLogger(__name__)
|
|||||||
class ProPresenterImport(SongImport):
|
class ProPresenterImport(SongImport):
|
||||||
"""
|
"""
|
||||||
The :class:`ProPresenterImport` class provides OpenLP with the
|
The :class:`ProPresenterImport` class provides OpenLP with the
|
||||||
ability to import ProPresenter 4 song files.
|
ability to import ProPresenter 4-6 song files.
|
||||||
"""
|
"""
|
||||||
def do_import(self):
|
def do_import(self):
|
||||||
self.import_wizard.progress_bar.setMaximum(len(self.import_source))
|
self.import_wizard.progress_bar.setMaximum(len(self.import_source))
|
||||||
@ -52,23 +52,82 @@ class ProPresenterImport(SongImport):
|
|||||||
|
|
||||||
def process_song(self, root, filename):
|
def process_song(self, root, filename):
|
||||||
self.set_defaults()
|
self.set_defaults()
|
||||||
self.title = os.path.basename(filename).rstrip('.pro4')
|
|
||||||
self.copyright = root.get('CCLICopyrightInfo')
|
# Extract ProPresenter versionNumber
|
||||||
|
try:
|
||||||
|
self.version = int(root.get('versionNumber'))
|
||||||
|
except ValueError:
|
||||||
|
log.debug('ProPresenter versionNumber invalid or missing')
|
||||||
|
return
|
||||||
|
|
||||||
|
# Title
|
||||||
|
self.title = root.get('CCLISongTitle')
|
||||||
|
if not self.title or self.title == '':
|
||||||
|
self.title = os.path.basename(filename)
|
||||||
|
if self.title[-5:-1] == '.pro':
|
||||||
|
self.title = self.title[:-5]
|
||||||
|
# Notes
|
||||||
self.comments = root.get('notes')
|
self.comments = root.get('notes')
|
||||||
self.ccli_number = root.get('CCLILicenseNumber')
|
# Author
|
||||||
for author_key in ['author', 'artist', 'CCLIArtistCredits']:
|
for author_key in ['author', 'CCLIAuthor', 'artist', 'CCLIArtistCredits']:
|
||||||
author = root.get(author_key)
|
author = root.get(author_key)
|
||||||
if len(author) > 0:
|
if author and len(author) > 0:
|
||||||
self.parse_author(author)
|
self.parse_author(author)
|
||||||
count = 0
|
|
||||||
for slide in root.slides.RVDisplaySlide:
|
# ProPresenter 4
|
||||||
count += 1
|
if(self.version >= 400 and self.version < 500):
|
||||||
if not hasattr(slide.displayElements, 'RVTextElement'):
|
self.copyright = root.get('CCLICopyrightInfo')
|
||||||
log.debug('No text found, may be an image slide')
|
self.ccli_number = root.get('CCLILicenseNumber')
|
||||||
continue
|
count = 0
|
||||||
RTFData = slide.displayElements.RVTextElement.get('RTFData')
|
for slide in root.slides.RVDisplaySlide:
|
||||||
rtf = base64.standard_b64decode(RTFData)
|
count += 1
|
||||||
words, encoding = strip_rtf(rtf.decode())
|
if not hasattr(slide.displayElements, 'RVTextElement'):
|
||||||
self.add_verse(words, "v%d" % count)
|
log.debug('No text found, may be an image slide')
|
||||||
|
continue
|
||||||
|
RTFData = slide.displayElements.RVTextElement.get('RTFData')
|
||||||
|
rtf = base64.standard_b64decode(RTFData)
|
||||||
|
words, encoding = strip_rtf(rtf.decode())
|
||||||
|
self.add_verse(words, "v%d" % count)
|
||||||
|
|
||||||
|
# ProPresenter 5
|
||||||
|
elif(self.version >= 500 and self.version < 600):
|
||||||
|
self.copyright = root.get('CCLICopyrightInfo')
|
||||||
|
self.ccli_number = root.get('CCLILicenseNumber')
|
||||||
|
count = 0
|
||||||
|
for group in root.groups.RVSlideGrouping:
|
||||||
|
for slide in group.slides.RVDisplaySlide:
|
||||||
|
count += 1
|
||||||
|
if not hasattr(slide.displayElements, 'RVTextElement'):
|
||||||
|
log.debug('No text found, may be an image slide')
|
||||||
|
continue
|
||||||
|
RTFData = slide.displayElements.RVTextElement.get('RTFData')
|
||||||
|
rtf = base64.standard_b64decode(RTFData)
|
||||||
|
words, encoding = strip_rtf(rtf.decode())
|
||||||
|
self.add_verse(words, "v%d" % count)
|
||||||
|
|
||||||
|
# ProPresenter 6
|
||||||
|
elif(self.version >= 600 and self.version < 700):
|
||||||
|
self.copyright = root.get('CCLICopyrightYear')
|
||||||
|
self.ccli_number = root.get('CCLISongNumber')
|
||||||
|
count = 0
|
||||||
|
for group in root.array.RVSlideGrouping:
|
||||||
|
for slide in group.array.RVDisplaySlide:
|
||||||
|
count += 1
|
||||||
|
for item in slide.array:
|
||||||
|
if not (item.get('rvXMLIvarName') == "displayElements"):
|
||||||
|
continue
|
||||||
|
if not hasattr(item, 'RVTextElement'):
|
||||||
|
log.debug('No text found, may be an image slide')
|
||||||
|
continue
|
||||||
|
for contents in item.RVTextElement.NSString:
|
||||||
|
b64Data = contents.text
|
||||||
|
data = base64.standard_b64decode(b64Data)
|
||||||
|
words = None
|
||||||
|
if(contents.get('rvXMLIvarName') == "RTFData"):
|
||||||
|
words, encoding = strip_rtf(data.decode())
|
||||||
|
break
|
||||||
|
if words:
|
||||||
|
self.add_verse(words, "v%d" % count)
|
||||||
|
|
||||||
if not self.finish():
|
if not self.finish():
|
||||||
self.log_error(self.import_source)
|
self.log_error(self.import_source)
|
||||||
|
@ -32,6 +32,7 @@ from openlp.core.common import Registry, AppLocation, Settings, check_directory_
|
|||||||
from openlp.core.lib import MediaManagerItem, ItemCapabilities, PluginStatus, ServiceItemContext, \
|
from openlp.core.lib import MediaManagerItem, ItemCapabilities, PluginStatus, ServiceItemContext, \
|
||||||
check_item_selected, create_separated_list
|
check_item_selected, create_separated_list
|
||||||
from openlp.core.lib.ui import create_widget_action
|
from openlp.core.lib.ui import create_widget_action
|
||||||
|
from openlp.core.common.languagemanager import get_natural_key
|
||||||
from openlp.plugins.songs.forms.editsongform import EditSongForm
|
from openlp.plugins.songs.forms.editsongform import EditSongForm
|
||||||
from openlp.plugins.songs.forms.songmaintenanceform import SongMaintenanceForm
|
from openlp.plugins.songs.forms.songmaintenanceform import SongMaintenanceForm
|
||||||
from openlp.plugins.songs.forms.songimportform import SongImportForm
|
from openlp.plugins.songs.forms.songimportform import SongImportForm
|
||||||
@ -203,7 +204,13 @@ class SongMediaItem(MediaManagerItem):
|
|||||||
self.display_results_topic(search_results)
|
self.display_results_topic(search_results)
|
||||||
elif search_type == SongSearch.Books:
|
elif search_type == SongSearch.Books:
|
||||||
log.debug('Songbook Search')
|
log.debug('Songbook Search')
|
||||||
self.display_results_book(search_keywords)
|
search_keywords = search_keywords.rpartition(' ')
|
||||||
|
search_book = search_keywords[0] + '%'
|
||||||
|
search_entry = search_keywords[2] + '%'
|
||||||
|
search_results = (self.plugin.manager.session.query(SongBookEntry)
|
||||||
|
.join(Book)
|
||||||
|
.filter(Book.name.like(search_book), SongBookEntry.entry.like(search_entry)).all())
|
||||||
|
self.display_results_book(search_results)
|
||||||
elif search_type == SongSearch.Themes:
|
elif search_type == SongSearch.Themes:
|
||||||
log.debug('Theme Search')
|
log.debug('Theme Search')
|
||||||
search_string = '%' + search_keywords + '%'
|
search_string = '%' + search_keywords + '%'
|
||||||
@ -278,8 +285,10 @@ class SongMediaItem(MediaManagerItem):
|
|||||||
"""
|
"""
|
||||||
log.debug('display results Author')
|
log.debug('display results Author')
|
||||||
self.list_view.clear()
|
self.list_view.clear()
|
||||||
|
search_results = sorted(search_results, key=lambda author: get_natural_key(author.display_name))
|
||||||
for author in search_results:
|
for author in search_results:
|
||||||
for song in author.songs:
|
songs = sorted(author.songs, key=lambda song: song.sort_key)
|
||||||
|
for song in songs:
|
||||||
# Do not display temporary songs
|
# Do not display temporary songs
|
||||||
if song.temporary:
|
if song.temporary:
|
||||||
continue
|
continue
|
||||||
@ -288,32 +297,20 @@ class SongMediaItem(MediaManagerItem):
|
|||||||
song_name.setData(QtCore.Qt.UserRole, song.id)
|
song_name.setData(QtCore.Qt.UserRole, song.id)
|
||||||
self.list_view.addItem(song_name)
|
self.list_view.addItem(song_name)
|
||||||
|
|
||||||
def display_results_book(self, search_keywords):
|
def display_results_book(self, search_results):
|
||||||
"""
|
"""
|
||||||
Display the song search results in the media manager list, grouped by book
|
Display the song search results in the media manager list, grouped by book and entry
|
||||||
|
|
||||||
:param search_keywords: A list of search keywords - book first, then number
|
:param search_results: A list of db SongBookEntry objects
|
||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
|
|
||||||
log.debug('display results Book')
|
log.debug('display results Book')
|
||||||
self.list_view.clear()
|
self.list_view.clear()
|
||||||
|
search_results = sorted(search_results, key=lambda songbook_entry:
|
||||||
search_keywords = search_keywords.rpartition(' ')
|
(get_natural_key(songbook_entry.songbook.name), get_natural_key(songbook_entry.entry)))
|
||||||
search_book = search_keywords[0]
|
for songbook_entry in search_results:
|
||||||
search_entry = re.sub(r'[^0-9]', '', search_keywords[2])
|
|
||||||
|
|
||||||
songbook_entries = (self.plugin.manager.session.query(SongBookEntry)
|
|
||||||
.join(Book)
|
|
||||||
.order_by(Book.name)
|
|
||||||
.order_by(SongBookEntry.entry))
|
|
||||||
for songbook_entry in songbook_entries:
|
|
||||||
if songbook_entry.song.temporary:
|
if songbook_entry.song.temporary:
|
||||||
continue
|
continue
|
||||||
if search_book.lower() not in songbook_entry.songbook.name.lower():
|
|
||||||
continue
|
|
||||||
if search_entry not in songbook_entry.entry:
|
|
||||||
continue
|
|
||||||
song_detail = '%s #%s: %s' % (songbook_entry.songbook.name, songbook_entry.entry, songbook_entry.song.title)
|
song_detail = '%s #%s: %s' % (songbook_entry.songbook.name, songbook_entry.entry, songbook_entry.song.title)
|
||||||
song_name = QtWidgets.QListWidgetItem(song_detail)
|
song_name = QtWidgets.QListWidgetItem(song_detail)
|
||||||
song_name.setData(QtCore.Qt.UserRole, songbook_entry.song.id)
|
song_name.setData(QtCore.Qt.UserRole, songbook_entry.song.id)
|
||||||
@ -328,7 +325,7 @@ class SongMediaItem(MediaManagerItem):
|
|||||||
"""
|
"""
|
||||||
log.debug('display results Topic')
|
log.debug('display results Topic')
|
||||||
self.list_view.clear()
|
self.list_view.clear()
|
||||||
search_results = sorted(search_results, key=lambda topic: self._natural_sort_key(topic.name))
|
search_results = sorted(search_results, key=lambda topic: get_natural_key(topic.name))
|
||||||
for topic in search_results:
|
for topic in search_results:
|
||||||
songs = sorted(topic.songs, key=lambda song: song.sort_key)
|
songs = sorted(topic.songs, key=lambda song: song.sort_key)
|
||||||
for song in songs:
|
for song in songs:
|
||||||
@ -349,6 +346,8 @@ class SongMediaItem(MediaManagerItem):
|
|||||||
"""
|
"""
|
||||||
log.debug('display results Themes')
|
log.debug('display results Themes')
|
||||||
self.list_view.clear()
|
self.list_view.clear()
|
||||||
|
search_results = sorted(search_results, key=lambda song: (get_natural_key(song.theme_name),
|
||||||
|
song.sort_key))
|
||||||
for song in search_results:
|
for song in search_results:
|
||||||
# Do not display temporary songs
|
# Do not display temporary songs
|
||||||
if song.temporary:
|
if song.temporary:
|
||||||
@ -367,7 +366,8 @@ class SongMediaItem(MediaManagerItem):
|
|||||||
"""
|
"""
|
||||||
log.debug('display results CCLI number')
|
log.debug('display results CCLI number')
|
||||||
self.list_view.clear()
|
self.list_view.clear()
|
||||||
songs = sorted(search_results, key=lambda song: self._natural_sort_key(song.ccli_number))
|
songs = sorted(search_results, key=lambda song: (get_natural_key(song.ccli_number),
|
||||||
|
song.sort_key))
|
||||||
for song in songs:
|
for song in songs:
|
||||||
# Do not display temporary songs
|
# Do not display temporary songs
|
||||||
if song.temporary:
|
if song.temporary:
|
||||||
@ -694,14 +694,6 @@ class SongMediaItem(MediaManagerItem):
|
|||||||
# List must be empty at the end
|
# List must be empty at the end
|
||||||
return not author_list
|
return not author_list
|
||||||
|
|
||||||
def _natural_sort_key(self, s):
|
|
||||||
"""
|
|
||||||
Return a tuple by which s is sorted.
|
|
||||||
:param s: A string value from the list we want to sort.
|
|
||||||
"""
|
|
||||||
return [int(text) if text.isdecimal() else text.lower()
|
|
||||||
for text in re.split('(\d+)', s)]
|
|
||||||
|
|
||||||
def search(self, string, show_error):
|
def search(self, string, show_error):
|
||||||
"""
|
"""
|
||||||
Search for some songs
|
Search for some songs
|
||||||
|
@ -28,8 +28,7 @@ import os
|
|||||||
|
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
|
|
||||||
from openlp.core.common import RegistryProperties, check_directory_exists, translate
|
from openlp.core.common import RegistryProperties, check_directory_exists, translate, clean_filename
|
||||||
from openlp.core.utils import clean_filename
|
|
||||||
from openlp.plugins.songs.lib.openlyricsxml import OpenLyrics
|
from openlp.plugins.songs.lib.openlyricsxml import OpenLyrics
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
@ -62,10 +62,10 @@ import re
|
|||||||
from lxml import etree, objectify
|
from lxml import etree, objectify
|
||||||
|
|
||||||
from openlp.core.common import translate
|
from openlp.core.common import translate
|
||||||
|
from openlp.core.common.versionchecker import get_application_version
|
||||||
from openlp.core.lib import FormattingTags
|
from openlp.core.lib import FormattingTags
|
||||||
from openlp.plugins.songs.lib import VerseType, clean_song
|
from openlp.plugins.songs.lib import VerseType, clean_song
|
||||||
from openlp.plugins.songs.lib.db import Author, AuthorType, Book, Song, Topic
|
from openlp.plugins.songs.lib.db import Author, AuthorType, Book, Song, Topic
|
||||||
from openlp.core.utils import get_application_version
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
4
setup.py
4
setup.py
@ -65,8 +65,8 @@ def natural_sort(seq):
|
|||||||
return temp
|
return temp
|
||||||
|
|
||||||
|
|
||||||
# NOTE: The following code is a duplicate of the code in openlp/core/utils/__init__.py. Any fix applied here should also
|
# NOTE: The following code is a duplicate of the code in openlp/core/common/checkversion.py.
|
||||||
# be applied there.
|
# Any fix applied here should also be applied there.
|
||||||
ver_file = None
|
ver_file = None
|
||||||
try:
|
try:
|
||||||
# Get the revision of this tree.
|
# Get the revision of this tree.
|
||||||
|
@ -171,7 +171,7 @@ class TestAppLocation(TestCase):
|
|||||||
"""
|
"""
|
||||||
Test the _get_frozen_path() function when the application is not frozen (compiled by PyInstaller)
|
Test the _get_frozen_path() function when the application is not frozen (compiled by PyInstaller)
|
||||||
"""
|
"""
|
||||||
with patch('openlp.core.utils.sys') as mocked_sys:
|
with patch('openlp.core.common.sys') as mocked_sys:
|
||||||
# GIVEN: The sys module "without" a "frozen" attribute
|
# GIVEN: The sys module "without" a "frozen" attribute
|
||||||
mocked_sys.frozen = None
|
mocked_sys.frozen = None
|
||||||
|
|
||||||
|
342
tests/functional/openlp_core_common/test_init.py
Normal file
342
tests/functional/openlp_core_common/test_init.py
Normal file
@ -0,0 +1,342 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# OpenLP - Open Source Lyrics Projection #
|
||||||
|
# --------------------------------------------------------------------------- #
|
||||||
|
# Copyright (c) 2008-2016 OpenLP Developers #
|
||||||
|
# --------------------------------------------------------------------------- #
|
||||||
|
# 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 #
|
||||||
|
###############################################################################
|
||||||
|
"""
|
||||||
|
Functional tests to test the AppLocation class and related methods.
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
from unittest import TestCase
|
||||||
|
|
||||||
|
from openlp.core.common import add_actions, get_uno_instance, get_uno_command, delete_file, get_filesystem_encoding, \
|
||||||
|
split_filename, clean_filename
|
||||||
|
from tests.functional import MagicMock, patch
|
||||||
|
from tests.helpers.testmixin import TestMixin
|
||||||
|
|
||||||
|
|
||||||
|
class TestInit(TestCase, TestMixin):
|
||||||
|
"""
|
||||||
|
A test suite to test out various methods around the common __init__ class.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
"""
|
||||||
|
Create an instance and a few example actions.
|
||||||
|
"""
|
||||||
|
self.build_settings()
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
"""
|
||||||
|
Clean up
|
||||||
|
"""
|
||||||
|
self.destroy_settings()
|
||||||
|
|
||||||
|
def add_actions_empty_list_test(self):
|
||||||
|
"""
|
||||||
|
Test that no actions are added when the list is empty
|
||||||
|
"""
|
||||||
|
# GIVEN: a mocked action list, and an empty list
|
||||||
|
mocked_target = MagicMock()
|
||||||
|
empty_list = []
|
||||||
|
|
||||||
|
# WHEN: The empty list is added to the mocked target
|
||||||
|
add_actions(mocked_target, empty_list)
|
||||||
|
|
||||||
|
# THEN: The add method on the mocked target is never called
|
||||||
|
self.assertEqual(0, mocked_target.addSeparator.call_count, 'addSeparator method should not have been called')
|
||||||
|
self.assertEqual(0, mocked_target.addAction.call_count, 'addAction method should not have been called')
|
||||||
|
|
||||||
|
def add_actions_none_action_test(self):
|
||||||
|
"""
|
||||||
|
Test that a separator is added when a None action is in the list
|
||||||
|
"""
|
||||||
|
# GIVEN: a mocked action list, and a list with None in it
|
||||||
|
mocked_target = MagicMock()
|
||||||
|
separator_list = [None]
|
||||||
|
|
||||||
|
# WHEN: The list is added to the mocked target
|
||||||
|
add_actions(mocked_target, separator_list)
|
||||||
|
|
||||||
|
# THEN: The addSeparator method is called, but the addAction method is never called
|
||||||
|
mocked_target.addSeparator.assert_called_with()
|
||||||
|
self.assertEqual(0, mocked_target.addAction.call_count, 'addAction method should not have been called')
|
||||||
|
|
||||||
|
def add_actions_add_action_test(self):
|
||||||
|
"""
|
||||||
|
Test that an action is added when a valid action is in the list
|
||||||
|
"""
|
||||||
|
# GIVEN: a mocked action list, and a list with an action in it
|
||||||
|
mocked_target = MagicMock()
|
||||||
|
action_list = ['action']
|
||||||
|
|
||||||
|
# WHEN: The list is added to the mocked target
|
||||||
|
add_actions(mocked_target, action_list)
|
||||||
|
|
||||||
|
# THEN: The addSeparator method is not called, and the addAction method is called
|
||||||
|
self.assertEqual(0, mocked_target.addSeparator.call_count, 'addSeparator method should not have been called')
|
||||||
|
mocked_target.addAction.assert_called_with('action')
|
||||||
|
|
||||||
|
def add_actions_action_and_none_test(self):
|
||||||
|
"""
|
||||||
|
Test that an action and a separator are added when a valid action and None are in the list
|
||||||
|
"""
|
||||||
|
# GIVEN: a mocked action list, and a list with an action and None in it
|
||||||
|
mocked_target = MagicMock()
|
||||||
|
action_list = ['action', None]
|
||||||
|
|
||||||
|
# WHEN: The list is added to the mocked target
|
||||||
|
add_actions(mocked_target, action_list)
|
||||||
|
|
||||||
|
# THEN: The addSeparator method is called, and the addAction method is called
|
||||||
|
mocked_target.addSeparator.assert_called_with()
|
||||||
|
mocked_target.addAction.assert_called_with('action')
|
||||||
|
|
||||||
|
def get_uno_instance_pipe_test(self):
|
||||||
|
"""
|
||||||
|
Test that when the UNO connection type is "pipe" the resolver is given the "pipe" URI
|
||||||
|
"""
|
||||||
|
# GIVEN: A mock resolver object and UNO_CONNECTION_TYPE is "pipe"
|
||||||
|
mock_resolver = MagicMock()
|
||||||
|
|
||||||
|
# WHEN: get_uno_instance() is called
|
||||||
|
get_uno_instance(mock_resolver)
|
||||||
|
|
||||||
|
# THEN: the resolve method is called with the correct argument
|
||||||
|
mock_resolver.resolve.assert_called_with('uno:pipe,name=openlp_pipe;urp;StarOffice.ComponentContext')
|
||||||
|
|
||||||
|
def get_uno_instance_socket_test(self):
|
||||||
|
"""
|
||||||
|
Test that when the UNO connection type is other than "pipe" the resolver is given the "socket" URI
|
||||||
|
"""
|
||||||
|
# GIVEN: A mock resolver object and UNO_CONNECTION_TYPE is "socket"
|
||||||
|
mock_resolver = MagicMock()
|
||||||
|
|
||||||
|
# WHEN: get_uno_instance() is called
|
||||||
|
get_uno_instance(mock_resolver, 'socket')
|
||||||
|
|
||||||
|
# THEN: the resolve method is called with the correct argument
|
||||||
|
mock_resolver.resolve.assert_called_with('uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext')
|
||||||
|
|
||||||
|
def get_uno_command_libreoffice_command_exists_test(self):
|
||||||
|
"""
|
||||||
|
Test the ``get_uno_command`` function uses the libreoffice command when available.
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
|
||||||
|
# GIVEN: A patched 'which' method which returns a path when called with 'libreoffice'
|
||||||
|
with patch('openlp.core.common.which',
|
||||||
|
**{'side_effect': lambda command: {'libreoffice': '/usr/bin/libreoffice'}[command]}):
|
||||||
|
# WHEN: Calling get_uno_command
|
||||||
|
result = get_uno_command()
|
||||||
|
|
||||||
|
# THEN: The command 'libreoffice' should be called with the appropriate parameters
|
||||||
|
self.assertEquals(result,
|
||||||
|
'libreoffice --nologo --norestore --minimized --nodefault --nofirststartwizard'
|
||||||
|
' "--accept=pipe,name=openlp_pipe;urp;"')
|
||||||
|
|
||||||
|
def get_uno_command_only_soffice_command_exists_test(self):
|
||||||
|
"""
|
||||||
|
Test the ``get_uno_command`` function uses the soffice command when the libreoffice command is not available.
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
|
||||||
|
# GIVEN: A patched 'which' method which returns None when called with 'libreoffice' and a path when called with
|
||||||
|
# 'soffice'
|
||||||
|
with patch('openlp.core.common.which',
|
||||||
|
**{'side_effect': lambda command: {'libreoffice': None, 'soffice': '/usr/bin/soffice'}[
|
||||||
|
command]}):
|
||||||
|
# WHEN: Calling get_uno_command
|
||||||
|
result = get_uno_command()
|
||||||
|
|
||||||
|
# THEN: The command 'soffice' should be called with the appropriate parameters
|
||||||
|
self.assertEquals(result, 'soffice --nologo --norestore --minimized --nodefault --nofirststartwizard'
|
||||||
|
' "--accept=pipe,name=openlp_pipe;urp;"')
|
||||||
|
|
||||||
|
def get_uno_command_when_no_command_exists_test(self):
|
||||||
|
"""
|
||||||
|
Test the ``get_uno_command`` function raises an FileNotFoundError when neither the libreoffice or soffice
|
||||||
|
commands are available.
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
|
||||||
|
# GIVEN: A patched 'which' method which returns None
|
||||||
|
with patch('openlp.core.common.which', **{'return_value': None}):
|
||||||
|
# WHEN: Calling get_uno_command
|
||||||
|
|
||||||
|
# THEN: a FileNotFoundError exception should be raised
|
||||||
|
self.assertRaises(FileNotFoundError, get_uno_command)
|
||||||
|
|
||||||
|
def get_uno_command_connection_type_test(self):
|
||||||
|
"""
|
||||||
|
Test the ``get_uno_command`` function when the connection type is anything other than pipe.
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
|
||||||
|
# GIVEN: A patched 'which' method which returns 'libreoffice'
|
||||||
|
with patch('openlp.core.common.which', **{'return_value': 'libreoffice'}):
|
||||||
|
# WHEN: Calling get_uno_command with a connection type other than pipe
|
||||||
|
result = get_uno_command('socket')
|
||||||
|
|
||||||
|
# THEN: The connection parameters should be set for socket
|
||||||
|
self.assertEqual(result, 'libreoffice --nologo --norestore --minimized --nodefault --nofirststartwizard'
|
||||||
|
' "--accept=socket,host=localhost,port=2002;urp;"')
|
||||||
|
|
||||||
|
def get_filesystem_encoding_sys_function_not_called_test(self):
|
||||||
|
"""
|
||||||
|
Test the get_filesystem_encoding() function does not call the sys.getdefaultencoding() function
|
||||||
|
"""
|
||||||
|
# GIVEN: sys.getfilesystemencoding returns "cp1252"
|
||||||
|
with patch('openlp.core.common.sys.getfilesystemencoding') as mocked_getfilesystemencoding, \
|
||||||
|
patch('openlp.core.common.sys.getdefaultencoding') as mocked_getdefaultencoding:
|
||||||
|
mocked_getfilesystemencoding.return_value = 'cp1252'
|
||||||
|
|
||||||
|
# WHEN: get_filesystem_encoding() is called
|
||||||
|
result = get_filesystem_encoding()
|
||||||
|
|
||||||
|
# THEN: getdefaultencoding should have been called
|
||||||
|
mocked_getfilesystemencoding.assert_called_with()
|
||||||
|
self.assertEqual(0, mocked_getdefaultencoding.called, 'getdefaultencoding should not have been called')
|
||||||
|
self.assertEqual('cp1252', result, 'The result should be "cp1252"')
|
||||||
|
|
||||||
|
def get_filesystem_encoding_sys_function_is_called_test(self):
|
||||||
|
"""
|
||||||
|
Test the get_filesystem_encoding() function calls the sys.getdefaultencoding() function
|
||||||
|
"""
|
||||||
|
# GIVEN: sys.getfilesystemencoding returns None and sys.getdefaultencoding returns "utf-8"
|
||||||
|
with patch('openlp.core.common.sys.getfilesystemencoding') as mocked_getfilesystemencoding, \
|
||||||
|
patch('openlp.core.common.sys.getdefaultencoding') as mocked_getdefaultencoding:
|
||||||
|
mocked_getfilesystemencoding.return_value = None
|
||||||
|
mocked_getdefaultencoding.return_value = 'utf-8'
|
||||||
|
|
||||||
|
# WHEN: get_filesystem_encoding() is called
|
||||||
|
result = get_filesystem_encoding()
|
||||||
|
|
||||||
|
# THEN: getdefaultencoding should have been called
|
||||||
|
mocked_getfilesystemencoding.assert_called_with()
|
||||||
|
mocked_getdefaultencoding.assert_called_with()
|
||||||
|
self.assertEqual('utf-8', result, 'The result should be "utf-8"')
|
||||||
|
|
||||||
|
def split_filename_with_file_path_test(self):
|
||||||
|
"""
|
||||||
|
Test the split_filename() function with a path to a file
|
||||||
|
"""
|
||||||
|
# GIVEN: A path to a file.
|
||||||
|
if os.name == 'nt':
|
||||||
|
file_path = 'C:\\home\\user\\myfile.txt'
|
||||||
|
wanted_result = ('C:\\home\\user', 'myfile.txt')
|
||||||
|
else:
|
||||||
|
file_path = '/home/user/myfile.txt'
|
||||||
|
wanted_result = ('/home/user', 'myfile.txt')
|
||||||
|
with patch('openlp.core.common.os.path.isfile') as mocked_is_file:
|
||||||
|
mocked_is_file.return_value = True
|
||||||
|
|
||||||
|
# WHEN: Split the file name.
|
||||||
|
result = split_filename(file_path)
|
||||||
|
|
||||||
|
# THEN: A tuple should be returned.
|
||||||
|
self.assertEqual(wanted_result, result, 'A tuple with the dir and file name should have been returned')
|
||||||
|
|
||||||
|
def split_filename_with_dir_path_test(self):
|
||||||
|
"""
|
||||||
|
Test the split_filename() function with a path to a directory
|
||||||
|
"""
|
||||||
|
# GIVEN: A path to a dir.
|
||||||
|
if os.name == 'nt':
|
||||||
|
file_path = 'C:\\home\\user\\mydir'
|
||||||
|
wanted_result = ('C:\\home\\user\\mydir', '')
|
||||||
|
else:
|
||||||
|
file_path = '/home/user/mydir'
|
||||||
|
wanted_result = ('/home/user/mydir', '')
|
||||||
|
with patch('openlp.core.common.os.path.isfile') as mocked_is_file:
|
||||||
|
mocked_is_file.return_value = False
|
||||||
|
|
||||||
|
# WHEN: Split the file name.
|
||||||
|
result = split_filename(file_path)
|
||||||
|
|
||||||
|
# THEN: A tuple should be returned.
|
||||||
|
self.assertEqual(wanted_result, result,
|
||||||
|
'A two-entry tuple with the directory and file name (empty) should have been returned.')
|
||||||
|
|
||||||
|
def clean_filename_test(self):
|
||||||
|
"""
|
||||||
|
Test the clean_filename() function
|
||||||
|
"""
|
||||||
|
# GIVEN: A invalid file name and the valid file name.
|
||||||
|
invalid_name = 'A_file_with_invalid_characters_[\\/:\*\?"<>\|\+\[\]%].py'
|
||||||
|
wanted_name = 'A_file_with_invalid_characters______________________.py'
|
||||||
|
|
||||||
|
# WHEN: Clean the name.
|
||||||
|
result = clean_filename(invalid_name)
|
||||||
|
|
||||||
|
# THEN: The file name should be cleaned.
|
||||||
|
self.assertEqual(wanted_name, result, 'The file name should not contain any special characters.')
|
||||||
|
|
||||||
|
def delete_file_no_path_test(self):
|
||||||
|
"""
|
||||||
|
Test the delete_file function when called with out a valid path
|
||||||
|
"""
|
||||||
|
# GIVEN: A blank path
|
||||||
|
# WEHN: Calling delete_file
|
||||||
|
result = delete_file('')
|
||||||
|
|
||||||
|
# THEN: delete_file should return False
|
||||||
|
self.assertFalse(result, "delete_file should return False when called with ''")
|
||||||
|
|
||||||
|
def delete_file_path_success_test(self):
|
||||||
|
"""
|
||||||
|
Test the delete_file function when it successfully deletes a file
|
||||||
|
"""
|
||||||
|
# GIVEN: A mocked os which returns True when os.path.exists is called
|
||||||
|
with patch('openlp.core.common.os', **{'path.exists.return_value': False}):
|
||||||
|
|
||||||
|
# WHEN: Calling delete_file with a file path
|
||||||
|
result = delete_file('path/file.ext')
|
||||||
|
|
||||||
|
# THEN: delete_file should return True
|
||||||
|
self.assertTrue(result, 'delete_file should return True when it successfully deletes a file')
|
||||||
|
|
||||||
|
def delete_file_path_no_file_exists_test(self):
|
||||||
|
"""
|
||||||
|
Test the delete_file function when the file to remove does not exist
|
||||||
|
"""
|
||||||
|
# GIVEN: A mocked os which returns False when os.path.exists is called
|
||||||
|
with patch('openlp.core.common.os', **{'path.exists.return_value': False}):
|
||||||
|
|
||||||
|
# WHEN: Calling delete_file with a file path
|
||||||
|
result = delete_file('path/file.ext')
|
||||||
|
|
||||||
|
# THEN: delete_file should return True
|
||||||
|
self.assertTrue(result, 'delete_file should return True when the file doesnt exist')
|
||||||
|
|
||||||
|
def delete_file_path_exception_test(self):
|
||||||
|
"""
|
||||||
|
Test the delete_file function when os.remove raises an exception
|
||||||
|
"""
|
||||||
|
# GIVEN: A mocked os which returns True when os.path.exists is called and raises an OSError when os.remove is
|
||||||
|
# called.
|
||||||
|
with patch('openlp.core.common.os', **{'path.exists.return_value': True, 'path.exists.side_effect': OSError}), \
|
||||||
|
patch('openlp.core.common.log') as mocked_log:
|
||||||
|
|
||||||
|
# WHEN: Calling delete_file with a file path
|
||||||
|
result = delete_file('path/file.ext')
|
||||||
|
|
||||||
|
# THEN: delete_file should log and exception and return False
|
||||||
|
self.assertEqual(mocked_log.exception.call_count, 1)
|
||||||
|
self.assertFalse(result, 'delete_file should return False when os.remove raises an OSError')
|
66
tests/functional/openlp_core_common/test_languagemanager.py
Normal file
66
tests/functional/openlp_core_common/test_languagemanager.py
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# OpenLP - Open Source Lyrics Projection #
|
||||||
|
# --------------------------------------------------------------------------- #
|
||||||
|
# Copyright (c) 2008-2016 OpenLP Developers #
|
||||||
|
# --------------------------------------------------------------------------- #
|
||||||
|
# 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 #
|
||||||
|
###############################################################################
|
||||||
|
"""
|
||||||
|
Functional tests to test the AppLocation class and related methods.
|
||||||
|
"""
|
||||||
|
from unittest import TestCase
|
||||||
|
|
||||||
|
from tests.functional import patch
|
||||||
|
from openlp.core.common.languagemanager import get_locale_key, get_natural_key
|
||||||
|
|
||||||
|
|
||||||
|
class TestLanguageManager(TestCase):
|
||||||
|
"""
|
||||||
|
A test suite to test out various methods around the common __init__ class.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def get_locale_key_test(self):
|
||||||
|
"""
|
||||||
|
Test the get_locale_key(string) function
|
||||||
|
"""
|
||||||
|
with patch('openlp.core.common.languagemanager.LanguageManager.get_language') as mocked_get_language:
|
||||||
|
# GIVEN: The language is German
|
||||||
|
# 0x00C3 (A with diaresis) should be sorted as "A". 0x00DF (sharp s) should be sorted as "ss".
|
||||||
|
mocked_get_language.return_value = 'de'
|
||||||
|
unsorted_list = ['Auszug', 'Aushang', '\u00C4u\u00DFerung']
|
||||||
|
|
||||||
|
# WHEN: We sort the list and use get_locale_key() to generate the sorting keys
|
||||||
|
sorted_list = sorted(unsorted_list, key=get_locale_key)
|
||||||
|
|
||||||
|
# THEN: We get a properly sorted list
|
||||||
|
self.assertEqual(['Aushang', '\u00C4u\u00DFerung', 'Auszug'], sorted_list,
|
||||||
|
'Strings should be sorted properly')
|
||||||
|
|
||||||
|
def get_natural_key_test(self):
|
||||||
|
"""
|
||||||
|
Test the get_natural_key(string) function
|
||||||
|
"""
|
||||||
|
with patch('openlp.core.common.languagemanager.LanguageManager.get_language') as mocked_get_language:
|
||||||
|
# GIVEN: The language is English (a language, which sorts digits before letters)
|
||||||
|
mocked_get_language.return_value = 'en'
|
||||||
|
unsorted_list = ['item 10a', 'item 3b', '1st item']
|
||||||
|
|
||||||
|
# WHEN: We sort the list and use get_natural_key() to generate the sorting keys
|
||||||
|
sorted_list = sorted(unsorted_list, key=get_natural_key)
|
||||||
|
|
||||||
|
# THEN: We get a properly sorted list
|
||||||
|
self.assertEqual(['1st item', 'item 3b', 'item 10a'], sorted_list, 'Numbers should be sorted naturally')
|
63
tests/functional/openlp_core_common/test_versionchecker.py
Normal file
63
tests/functional/openlp_core_common/test_versionchecker.py
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# OpenLP - Open Source Lyrics Projection #
|
||||||
|
# --------------------------------------------------------------------------- #
|
||||||
|
# Copyright (c) 2008-2016 OpenLP Developers #
|
||||||
|
# --------------------------------------------------------------------------- #
|
||||||
|
# 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 #
|
||||||
|
###############################################################################
|
||||||
|
"""
|
||||||
|
Package to test the openlp.core.common.versionchecker package.
|
||||||
|
"""
|
||||||
|
from unittest import TestCase
|
||||||
|
|
||||||
|
from openlp.core.common.settings import Settings
|
||||||
|
from openlp.core.common.versionchecker import VersionThread
|
||||||
|
from tests.functional import MagicMock, patch
|
||||||
|
from tests.helpers.testmixin import TestMixin
|
||||||
|
|
||||||
|
|
||||||
|
class TestVersionchecker(TestMixin, TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
"""
|
||||||
|
Create an instance and a few example actions.
|
||||||
|
"""
|
||||||
|
self.build_settings()
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
"""
|
||||||
|
Clean up
|
||||||
|
"""
|
||||||
|
self.destroy_settings()
|
||||||
|
|
||||||
|
def version_thread_triggered_test(self):
|
||||||
|
"""
|
||||||
|
Test the version thread call does not trigger UI
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
# GIVEN: a equal version setup and the data is not today.
|
||||||
|
mocked_main_window = MagicMock()
|
||||||
|
Settings().setValue('core/last version test', '1950-04-01')
|
||||||
|
# WHEN: We check to see if the version is different .
|
||||||
|
with patch('PyQt5.QtCore.QThread'),\
|
||||||
|
patch('openlp.core.common.versionchecker.get_application_version') as mocked_get_application_version:
|
||||||
|
mocked_get_application_version.return_value = {'version': '1.0.0', 'build': '', 'full': '2.0.4'}
|
||||||
|
version_thread = VersionThread(mocked_main_window)
|
||||||
|
version_thread.run()
|
||||||
|
# THEN: If the version has changed the main window is notified
|
||||||
|
self.assertTrue(mocked_main_window.openlp_version_check.emit.called,
|
||||||
|
'The main windows should have been notified')
|
@ -92,3 +92,18 @@ class TestPJLink(TestCase):
|
|||||||
mock_change_status.called_with(E_PARAMETER,
|
mock_change_status.called_with(E_PARAMETER,
|
||||||
'change_status should have been called with "{}"'.format(
|
'change_status should have been called with "{}"'.format(
|
||||||
ERROR_STRING[E_PARAMETER]))
|
ERROR_STRING[E_PARAMETER]))
|
||||||
|
|
||||||
|
@patch.object(pjlink_test, 'process_inpt')
|
||||||
|
def projector_return_ok_test(self, mock_process_inpt):
|
||||||
|
"""
|
||||||
|
Test projector calls process_inpt command when process_command is called with INPT option
|
||||||
|
"""
|
||||||
|
# GIVEN: Test object
|
||||||
|
pjlink = pjlink_test
|
||||||
|
|
||||||
|
# WHEN: process_command is called with INST command and 31 input:
|
||||||
|
pjlink.process_command('INPT', '31')
|
||||||
|
|
||||||
|
# THEN: process_inpt method should have been called with 31
|
||||||
|
mock_process_inpt.called_with('31',
|
||||||
|
"process_inpt should have been called with 31")
|
||||||
|
229
tests/functional/openlp_core_lib/test_webpagereader.py
Normal file
229
tests/functional/openlp_core_lib/test_webpagereader.py
Normal file
@ -0,0 +1,229 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# OpenLP - Open Source Lyrics Projection #
|
||||||
|
# --------------------------------------------------------------------------- #
|
||||||
|
# Copyright (c) 2008-2016 OpenLP Developers #
|
||||||
|
# --------------------------------------------------------------------------- #
|
||||||
|
# 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 #
|
||||||
|
###############################################################################
|
||||||
|
"""
|
||||||
|
Functional tests to test the AppLocation class and related methods.
|
||||||
|
"""
|
||||||
|
from unittest import TestCase
|
||||||
|
|
||||||
|
from openlp.core.lib.webpagereader import _get_user_agent, get_web_page
|
||||||
|
|
||||||
|
from tests.functional import MagicMock, patch
|
||||||
|
|
||||||
|
|
||||||
|
class TestUtils(TestCase):
|
||||||
|
"""
|
||||||
|
A test suite to test out various methods around the AppLocation class.
|
||||||
|
"""
|
||||||
|
def get_user_agent_linux_test(self):
|
||||||
|
"""
|
||||||
|
Test that getting a user agent on Linux returns a user agent suitable for Linux
|
||||||
|
"""
|
||||||
|
with patch('openlp.core.lib.webpagereader.sys') as mocked_sys:
|
||||||
|
|
||||||
|
# GIVEN: The system is Linux
|
||||||
|
mocked_sys.platform = 'linux2'
|
||||||
|
|
||||||
|
# WHEN: We call _get_user_agent()
|
||||||
|
user_agent = _get_user_agent()
|
||||||
|
|
||||||
|
# THEN: The user agent is a Linux (or ChromeOS) user agent
|
||||||
|
result = 'Linux' in user_agent or 'CrOS' in user_agent
|
||||||
|
self.assertTrue(result, 'The user agent should be a valid Linux user agent')
|
||||||
|
|
||||||
|
def get_user_agent_windows_test(self):
|
||||||
|
"""
|
||||||
|
Test that getting a user agent on Windows returns a user agent suitable for Windows
|
||||||
|
"""
|
||||||
|
with patch('openlp.core.lib.webpagereader.sys') as mocked_sys:
|
||||||
|
|
||||||
|
# GIVEN: The system is Linux
|
||||||
|
mocked_sys.platform = 'win32'
|
||||||
|
|
||||||
|
# WHEN: We call _get_user_agent()
|
||||||
|
user_agent = _get_user_agent()
|
||||||
|
|
||||||
|
# THEN: The user agent is a Linux (or ChromeOS) user agent
|
||||||
|
self.assertIn('Windows', user_agent, 'The user agent should be a valid Windows user agent')
|
||||||
|
|
||||||
|
def get_user_agent_macos_test(self):
|
||||||
|
"""
|
||||||
|
Test that getting a user agent on OS X returns a user agent suitable for OS X
|
||||||
|
"""
|
||||||
|
with patch('openlp.core.lib.webpagereader.sys') as mocked_sys:
|
||||||
|
|
||||||
|
# GIVEN: The system is Linux
|
||||||
|
mocked_sys.platform = 'darwin'
|
||||||
|
|
||||||
|
# WHEN: We call _get_user_agent()
|
||||||
|
user_agent = _get_user_agent()
|
||||||
|
|
||||||
|
# THEN: The user agent is a Linux (or ChromeOS) user agent
|
||||||
|
self.assertIn('Mac OS X', user_agent, 'The user agent should be a valid OS X user agent')
|
||||||
|
|
||||||
|
def get_user_agent_default_test(self):
|
||||||
|
"""
|
||||||
|
Test that getting a user agent on a non-Linux/Windows/OS X platform returns the default user agent
|
||||||
|
"""
|
||||||
|
with patch('openlp.core.lib.webpagereader.sys') as mocked_sys:
|
||||||
|
|
||||||
|
# GIVEN: The system is Linux
|
||||||
|
mocked_sys.platform = 'freebsd'
|
||||||
|
|
||||||
|
# WHEN: We call _get_user_agent()
|
||||||
|
user_agent = _get_user_agent()
|
||||||
|
|
||||||
|
# THEN: The user agent is a Linux (or ChromeOS) user agent
|
||||||
|
self.assertIn('NetBSD', user_agent, 'The user agent should be the default user agent')
|
||||||
|
|
||||||
|
def get_web_page_no_url_test(self):
|
||||||
|
"""
|
||||||
|
Test that sending a URL of None to the get_web_page method returns None
|
||||||
|
"""
|
||||||
|
# GIVEN: A None url
|
||||||
|
test_url = None
|
||||||
|
|
||||||
|
# WHEN: We try to get the test URL
|
||||||
|
result = get_web_page(test_url)
|
||||||
|
|
||||||
|
# THEN: None should be returned
|
||||||
|
self.assertIsNone(result, 'The return value of get_web_page should be None')
|
||||||
|
|
||||||
|
def get_web_page_test(self):
|
||||||
|
"""
|
||||||
|
Test that the get_web_page method works correctly
|
||||||
|
"""
|
||||||
|
with patch('openlp.core.lib.webpagereader.urllib.request.Request') as MockRequest, \
|
||||||
|
patch('openlp.core.lib.webpagereader.urllib.request.urlopen') as mock_urlopen, \
|
||||||
|
patch('openlp.core.lib.webpagereader._get_user_agent') as mock_get_user_agent, \
|
||||||
|
patch('openlp.core.common.Registry') as MockRegistry:
|
||||||
|
# GIVEN: Mocked out objects and a fake URL
|
||||||
|
mocked_request_object = MagicMock()
|
||||||
|
MockRequest.return_value = mocked_request_object
|
||||||
|
mocked_page_object = MagicMock()
|
||||||
|
mock_urlopen.return_value = mocked_page_object
|
||||||
|
mock_get_user_agent.return_value = 'user_agent'
|
||||||
|
fake_url = 'this://is.a.fake/url'
|
||||||
|
|
||||||
|
# WHEN: The get_web_page() method is called
|
||||||
|
returned_page = get_web_page(fake_url)
|
||||||
|
|
||||||
|
# THEN: The correct methods are called with the correct arguments and a web page is returned
|
||||||
|
MockRequest.assert_called_with(fake_url)
|
||||||
|
mocked_request_object.add_header.assert_called_with('User-Agent', 'user_agent')
|
||||||
|
self.assertEqual(1, mocked_request_object.add_header.call_count,
|
||||||
|
'There should only be 1 call to add_header')
|
||||||
|
mock_get_user_agent.assert_called_with()
|
||||||
|
mock_urlopen.assert_called_with(mocked_request_object, timeout=30)
|
||||||
|
mocked_page_object.geturl.assert_called_with()
|
||||||
|
self.assertEqual(0, MockRegistry.call_count, 'The Registry() object should have never been called')
|
||||||
|
self.assertEqual(mocked_page_object, returned_page, 'The returned page should be the mock object')
|
||||||
|
|
||||||
|
def get_web_page_with_header_test(self):
|
||||||
|
"""
|
||||||
|
Test that adding a header to the call to get_web_page() adds the header to the request
|
||||||
|
"""
|
||||||
|
with patch('openlp.core.lib.webpagereader.urllib.request.Request') as MockRequest, \
|
||||||
|
patch('openlp.core.lib.webpagereader.urllib.request.urlopen') as mock_urlopen, \
|
||||||
|
patch('openlp.core.lib.webpagereader._get_user_agent') as mock_get_user_agent:
|
||||||
|
# GIVEN: Mocked out objects, a fake URL and a fake header
|
||||||
|
mocked_request_object = MagicMock()
|
||||||
|
MockRequest.return_value = mocked_request_object
|
||||||
|
mocked_page_object = MagicMock()
|
||||||
|
mock_urlopen.return_value = mocked_page_object
|
||||||
|
mock_get_user_agent.return_value = 'user_agent'
|
||||||
|
fake_url = 'this://is.a.fake/url'
|
||||||
|
fake_header = ('Fake-Header', 'fake value')
|
||||||
|
|
||||||
|
# WHEN: The get_web_page() method is called
|
||||||
|
returned_page = get_web_page(fake_url, header=fake_header)
|
||||||
|
|
||||||
|
# THEN: The correct methods are called with the correct arguments and a web page is returned
|
||||||
|
MockRequest.assert_called_with(fake_url)
|
||||||
|
mocked_request_object.add_header.assert_called_with(fake_header[0], fake_header[1])
|
||||||
|
self.assertEqual(2, mocked_request_object.add_header.call_count,
|
||||||
|
'There should only be 2 calls to add_header')
|
||||||
|
mock_get_user_agent.assert_called_with()
|
||||||
|
mock_urlopen.assert_called_with(mocked_request_object, timeout=30)
|
||||||
|
mocked_page_object.geturl.assert_called_with()
|
||||||
|
self.assertEqual(mocked_page_object, returned_page, 'The returned page should be the mock object')
|
||||||
|
|
||||||
|
def get_web_page_with_user_agent_in_headers_test(self):
|
||||||
|
"""
|
||||||
|
Test that adding a user agent in the header when calling get_web_page() adds that user agent to the request
|
||||||
|
"""
|
||||||
|
with patch('openlp.core.lib.webpagereader.urllib.request.Request') as MockRequest, \
|
||||||
|
patch('openlp.core.lib.webpagereader.urllib.request.urlopen') as mock_urlopen, \
|
||||||
|
patch('openlp.core.lib.webpagereader._get_user_agent') as mock_get_user_agent:
|
||||||
|
# GIVEN: Mocked out objects, a fake URL and a fake header
|
||||||
|
mocked_request_object = MagicMock()
|
||||||
|
MockRequest.return_value = mocked_request_object
|
||||||
|
mocked_page_object = MagicMock()
|
||||||
|
mock_urlopen.return_value = mocked_page_object
|
||||||
|
fake_url = 'this://is.a.fake/url'
|
||||||
|
user_agent_header = ('User-Agent', 'OpenLP/2.2.0')
|
||||||
|
|
||||||
|
# WHEN: The get_web_page() method is called
|
||||||
|
returned_page = get_web_page(fake_url, header=user_agent_header)
|
||||||
|
|
||||||
|
# THEN: The correct methods are called with the correct arguments and a web page is returned
|
||||||
|
MockRequest.assert_called_with(fake_url)
|
||||||
|
mocked_request_object.add_header.assert_called_with(user_agent_header[0], user_agent_header[1])
|
||||||
|
self.assertEqual(1, mocked_request_object.add_header.call_count,
|
||||||
|
'There should only be 1 call to add_header')
|
||||||
|
self.assertEqual(0, mock_get_user_agent.call_count, '_get_user_agent should not have been called')
|
||||||
|
mock_urlopen.assert_called_with(mocked_request_object, timeout=30)
|
||||||
|
mocked_page_object.geturl.assert_called_with()
|
||||||
|
self.assertEqual(mocked_page_object, returned_page, 'The returned page should be the mock object')
|
||||||
|
|
||||||
|
def get_web_page_update_openlp_test(self):
|
||||||
|
"""
|
||||||
|
Test that passing "update_openlp" as true to get_web_page calls Registry().get('app').process_events()
|
||||||
|
"""
|
||||||
|
with patch('openlp.core.lib.webpagereader.urllib.request.Request') as MockRequest, \
|
||||||
|
patch('openlp.core.lib.webpagereader.urllib.request.urlopen') as mock_urlopen, \
|
||||||
|
patch('openlp.core.lib.webpagereader._get_user_agent') as mock_get_user_agent, \
|
||||||
|
patch('openlp.core.lib.webpagereader.Registry') as MockRegistry:
|
||||||
|
# GIVEN: Mocked out objects, a fake URL
|
||||||
|
mocked_request_object = MagicMock()
|
||||||
|
MockRequest.return_value = mocked_request_object
|
||||||
|
mocked_page_object = MagicMock()
|
||||||
|
mock_urlopen.return_value = mocked_page_object
|
||||||
|
mock_get_user_agent.return_value = 'user_agent'
|
||||||
|
mocked_registry_object = MagicMock()
|
||||||
|
mocked_application_object = MagicMock()
|
||||||
|
mocked_registry_object.get.return_value = mocked_application_object
|
||||||
|
MockRegistry.return_value = mocked_registry_object
|
||||||
|
fake_url = 'this://is.a.fake/url'
|
||||||
|
|
||||||
|
# WHEN: The get_web_page() method is called
|
||||||
|
returned_page = get_web_page(fake_url, update_openlp=True)
|
||||||
|
|
||||||
|
# THEN: The correct methods are called with the correct arguments and a web page is returned
|
||||||
|
MockRequest.assert_called_with(fake_url)
|
||||||
|
mocked_request_object.add_header.assert_called_with('User-Agent', 'user_agent')
|
||||||
|
self.assertEqual(1, mocked_request_object.add_header.call_count,
|
||||||
|
'There should only be 1 call to add_header')
|
||||||
|
mock_urlopen.assert_called_with(mocked_request_object, timeout=30)
|
||||||
|
mocked_page_object.geturl.assert_called_with()
|
||||||
|
mocked_registry_object.get.assert_called_with('application')
|
||||||
|
mocked_application_object.process_events.assert_called_with()
|
||||||
|
self.assertEqual(mocked_page_object, returned_page, 'The returned page should be the mock object')
|
@ -28,10 +28,10 @@ import urllib.request
|
|||||||
import urllib.error
|
import urllib.error
|
||||||
import urllib.parse
|
import urllib.parse
|
||||||
|
|
||||||
from tests.functional import MagicMock, patch
|
from tests.functional import patch
|
||||||
from tests.helpers.testmixin import TestMixin
|
from tests.helpers.testmixin import TestMixin
|
||||||
|
|
||||||
from openlp.core.utils import CONNECTION_TIMEOUT, CONNECTION_RETRIES, get_web_page
|
from openlp.core.lib.webpagereader import CONNECTION_RETRIES, get_web_page
|
||||||
|
|
||||||
|
|
||||||
class TestFirstTimeWizard(TestMixin, TestCase):
|
class TestFirstTimeWizard(TestMixin, TestCase):
|
@ -23,9 +23,12 @@
|
|||||||
Package to test the openlp.core.ui.listpreviewwidget package.
|
Package to test the openlp.core.ui.listpreviewwidget package.
|
||||||
"""
|
"""
|
||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
from openlp.core.ui.listpreviewwidget import ListPreviewWidget
|
|
||||||
|
|
||||||
from tests.functional import patch
|
from openlp.core.common import Settings
|
||||||
|
from openlp.core.ui.listpreviewwidget import ListPreviewWidget
|
||||||
|
from openlp.core.lib import ServiceItem
|
||||||
|
|
||||||
|
from tests.functional import MagicMock, patch, call
|
||||||
|
|
||||||
|
|
||||||
class TestListPreviewWidget(TestCase):
|
class TestListPreviewWidget(TestCase):
|
||||||
@ -34,9 +37,27 @@ class TestListPreviewWidget(TestCase):
|
|||||||
"""
|
"""
|
||||||
Mock out stuff for all the tests
|
Mock out stuff for all the tests
|
||||||
"""
|
"""
|
||||||
self.setup_patcher = patch('openlp.core.ui.listpreviewwidget.ListPreviewWidget._setup')
|
# Mock self.parent().width()
|
||||||
self.mocked_setup = self.setup_patcher.start()
|
self.parent_patcher = patch('openlp.core.ui.listpreviewwidget.ListPreviewWidget.parent')
|
||||||
self.addCleanup(self.setup_patcher.stop)
|
self.mocked_parent = self.parent_patcher.start()
|
||||||
|
self.mocked_parent.width.return_value = 100
|
||||||
|
self.addCleanup(self.parent_patcher.stop)
|
||||||
|
|
||||||
|
# Mock Settings().value()
|
||||||
|
self.Settings_patcher = patch('openlp.core.ui.listpreviewwidget.Settings')
|
||||||
|
self.mocked_Settings = self.Settings_patcher.start()
|
||||||
|
self.mocked_Settings_obj = MagicMock()
|
||||||
|
self.mocked_Settings_obj.value.return_value = None
|
||||||
|
self.mocked_Settings.return_value = self.mocked_Settings_obj
|
||||||
|
self.addCleanup(self.Settings_patcher.stop)
|
||||||
|
|
||||||
|
# Mock self.viewport().width()
|
||||||
|
self.viewport_patcher = patch('openlp.core.ui.listpreviewwidget.ListPreviewWidget.viewport')
|
||||||
|
self.mocked_viewport = self.viewport_patcher.start()
|
||||||
|
self.mocked_viewport_obj = MagicMock()
|
||||||
|
self.mocked_viewport_obj.width.return_value = 200
|
||||||
|
self.mocked_viewport.return_value = self.mocked_viewport_obj
|
||||||
|
self.addCleanup(self.viewport_patcher.stop)
|
||||||
|
|
||||||
def new_list_preview_widget_test(self):
|
def new_list_preview_widget_test(self):
|
||||||
"""
|
"""
|
||||||
@ -49,4 +70,206 @@ class TestListPreviewWidget(TestCase):
|
|||||||
|
|
||||||
# THEN: The object is not None, and the _setup() method was called.
|
# THEN: The object is not None, and the _setup() method was called.
|
||||||
self.assertIsNotNone(list_preview_widget, 'The ListPreviewWidget object should not be None')
|
self.assertIsNotNone(list_preview_widget, 'The ListPreviewWidget object should not be None')
|
||||||
self.mocked_setup.assert_called_with(1)
|
self.assertEquals(list_preview_widget.screen_ratio, 1, 'Should not be called')
|
||||||
|
|
||||||
|
@patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.resizeRowsToContents')
|
||||||
|
@patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.setRowHeight')
|
||||||
|
def replace_recalculate_layout_test_text(self, mocked_setRowHeight, mocked_resizeRowsToContents):
|
||||||
|
"""
|
||||||
|
Test if "Max height for non-text slides..." enabled, txt slides unchanged in replace_service_item & __recalc...
|
||||||
|
"""
|
||||||
|
# GIVEN: A setting to adjust "Max height for non-text slides in slide controller",
|
||||||
|
# a text ServiceItem and a ListPreviewWidget.
|
||||||
|
|
||||||
|
# Mock Settings().value('advanced/slide max height')
|
||||||
|
self.mocked_Settings_obj.value.return_value = 100
|
||||||
|
# Mock self.viewport().width()
|
||||||
|
self.mocked_viewport_obj.width.return_value = 200
|
||||||
|
# Mock text service item
|
||||||
|
service_item = MagicMock()
|
||||||
|
service_item.is_text.return_value = True
|
||||||
|
service_item.get_frames.return_value = [{'title': None, 'text': None, 'verseTag': None},
|
||||||
|
{'title': None, 'text': None, 'verseTag': None}]
|
||||||
|
# init ListPreviewWidget and load service item
|
||||||
|
list_preview_widget = ListPreviewWidget(None, 1)
|
||||||
|
list_preview_widget.replace_service_item(service_item, 200, 0)
|
||||||
|
# Change viewport width before forcing a resize
|
||||||
|
self.mocked_viewport_obj.width.return_value = 400
|
||||||
|
|
||||||
|
# WHEN: __recalculate_layout() is called (via resizeEvent)
|
||||||
|
list_preview_widget.resizeEvent(None)
|
||||||
|
|
||||||
|
# THEN: setRowHeight() should not be called, while resizeRowsToContents() should be called twice
|
||||||
|
# (once each in __recalculate_layout and replace_service_item)
|
||||||
|
self.assertEquals(mocked_resizeRowsToContents.call_count, 2, 'Should be called')
|
||||||
|
self.assertEquals(mocked_setRowHeight.call_count, 0, 'Should not be called')
|
||||||
|
|
||||||
|
@patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.resizeRowsToContents')
|
||||||
|
@patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.setRowHeight')
|
||||||
|
def replace_recalculate_layout_test_img(self, mocked_setRowHeight, mocked_resizeRowsToContents):
|
||||||
|
"""
|
||||||
|
Test if "Max height for non-text slides..." disabled, img slides unchanged in replace_service_item & __recalc...
|
||||||
|
"""
|
||||||
|
# GIVEN: A setting to adjust "Max height for non-text slides in slide controller",
|
||||||
|
# an image ServiceItem and a ListPreviewWidget.
|
||||||
|
|
||||||
|
# Mock Settings().value('advanced/slide max height')
|
||||||
|
self.mocked_Settings_obj.value.return_value = 0
|
||||||
|
# Mock self.viewport().width()
|
||||||
|
self.mocked_viewport_obj.width.return_value = 200
|
||||||
|
# Mock image service item
|
||||||
|
service_item = MagicMock()
|
||||||
|
service_item.is_text.return_value = False
|
||||||
|
service_item.get_frames.return_value = [{'title': None, 'path': None, 'image': None},
|
||||||
|
{'title': None, 'path': None, 'image': None}]
|
||||||
|
# init ListPreviewWidget and load service item
|
||||||
|
list_preview_widget = ListPreviewWidget(None, 1)
|
||||||
|
list_preview_widget.replace_service_item(service_item, 200, 0)
|
||||||
|
# Change viewport width before forcing a resize
|
||||||
|
self.mocked_viewport_obj.width.return_value = 400
|
||||||
|
|
||||||
|
# WHEN: __recalculate_layout() is called (via resizeEvent)
|
||||||
|
list_preview_widget.resizeEvent(None)
|
||||||
|
|
||||||
|
# THEN: resizeRowsToContents() should not be called, while setRowHeight() should be called
|
||||||
|
# twice for each slide.
|
||||||
|
self.assertEquals(mocked_resizeRowsToContents.call_count, 0, 'Should not be called')
|
||||||
|
self.assertEquals(mocked_setRowHeight.call_count, 4, 'Should be called twice for each slide')
|
||||||
|
calls = [call(0, 200), call(1, 200), call(0, 400), call(1, 400)]
|
||||||
|
mocked_setRowHeight.assert_has_calls(calls)
|
||||||
|
|
||||||
|
@patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.resizeRowsToContents')
|
||||||
|
@patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.setRowHeight')
|
||||||
|
def replace_recalculate_layout_test_img_max(self, mocked_setRowHeight, mocked_resizeRowsToContents):
|
||||||
|
"""
|
||||||
|
Test if "Max height for non-text slides..." enabled, img slides resized in replace_service_item & __recalc...
|
||||||
|
"""
|
||||||
|
# GIVEN: A setting to adjust "Max height for non-text slides in slide controller",
|
||||||
|
# an image ServiceItem and a ListPreviewWidget.
|
||||||
|
|
||||||
|
# Mock Settings().value('advanced/slide max height')
|
||||||
|
self.mocked_Settings_obj.value.return_value = 100
|
||||||
|
# Mock self.viewport().width()
|
||||||
|
self.mocked_viewport_obj.width.return_value = 200
|
||||||
|
# Mock image service item
|
||||||
|
service_item = MagicMock()
|
||||||
|
service_item.is_text.return_value = False
|
||||||
|
service_item.get_frames.return_value = [{'title': None, 'path': None, 'image': None},
|
||||||
|
{'title': None, 'path': None, 'image': None}]
|
||||||
|
# init ListPreviewWidget and load service item
|
||||||
|
list_preview_widget = ListPreviewWidget(None, 1)
|
||||||
|
list_preview_widget.replace_service_item(service_item, 200, 0)
|
||||||
|
# Change viewport width before forcing a resize
|
||||||
|
self.mocked_viewport_obj.width.return_value = 400
|
||||||
|
|
||||||
|
# WHEN: __recalculate_layout() is called (via resizeEvent)
|
||||||
|
list_preview_widget.resizeEvent(None)
|
||||||
|
|
||||||
|
# THEN: resizeRowsToContents() should not be called, while setRowHeight() should be called
|
||||||
|
# twice for each slide.
|
||||||
|
self.assertEquals(mocked_resizeRowsToContents.call_count, 0, 'Should not be called')
|
||||||
|
self.assertEquals(mocked_setRowHeight.call_count, 4, 'Should be called twice for each slide')
|
||||||
|
calls = [call(0, 100), call(1, 100), call(0, 100), call(1, 100)]
|
||||||
|
mocked_setRowHeight.assert_has_calls(calls)
|
||||||
|
|
||||||
|
@patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.resizeRowsToContents')
|
||||||
|
@patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.setRowHeight')
|
||||||
|
@patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.cellWidget')
|
||||||
|
def row_resized_test_text(self, mocked_cellWidget, mocked_setRowHeight, mocked_resizeRowsToContents):
|
||||||
|
"""
|
||||||
|
Test if "Max height for non-text slides..." enabled, text-based slides not affected in row_resized.
|
||||||
|
"""
|
||||||
|
# GIVEN: A setting to adjust "Max height for non-text slides in slide controller",
|
||||||
|
# a text ServiceItem and a ListPreviewWidget.
|
||||||
|
|
||||||
|
# Mock Settings().value('advanced/slide max height')
|
||||||
|
self.mocked_Settings_obj.value.return_value = 100
|
||||||
|
# Mock self.viewport().width()
|
||||||
|
self.mocked_viewport_obj.width.return_value = 200
|
||||||
|
# Mock text service item
|
||||||
|
service_item = MagicMock()
|
||||||
|
service_item.is_text.return_value = True
|
||||||
|
service_item.get_frames.return_value = [{'title': None, 'text': None, 'verseTag': None},
|
||||||
|
{'title': None, 'text': None, 'verseTag': None}]
|
||||||
|
# Mock self.cellWidget().children().setMaximumWidth()
|
||||||
|
mocked_cellWidget_child = MagicMock()
|
||||||
|
mocked_cellWidget_obj = MagicMock()
|
||||||
|
mocked_cellWidget_obj.children.return_value = [None, mocked_cellWidget_child]
|
||||||
|
mocked_cellWidget.return_value = mocked_cellWidget_obj
|
||||||
|
# init ListPreviewWidget and load service item
|
||||||
|
list_preview_widget = ListPreviewWidget(None, 1)
|
||||||
|
list_preview_widget.replace_service_item(service_item, 200, 0)
|
||||||
|
|
||||||
|
# WHEN: row_resized() is called
|
||||||
|
list_preview_widget.row_resized(0, 100, 150)
|
||||||
|
|
||||||
|
# THEN: self.cellWidget(row, 0).children()[1].setMaximumWidth() should not be called
|
||||||
|
self.assertEquals(mocked_cellWidget_child.setMaximumWidth.call_count, 0, 'Should not be called')
|
||||||
|
|
||||||
|
@patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.resizeRowsToContents')
|
||||||
|
@patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.setRowHeight')
|
||||||
|
@patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.cellWidget')
|
||||||
|
def row_resized_test_img(self, mocked_cellWidget, mocked_setRowHeight, mocked_resizeRowsToContents):
|
||||||
|
"""
|
||||||
|
Test if "Max height for non-text slides..." disabled, image-based slides not affected in row_resized.
|
||||||
|
"""
|
||||||
|
# GIVEN: A setting to adjust "Max height for non-text slides in slide controller",
|
||||||
|
# an image ServiceItem and a ListPreviewWidget.
|
||||||
|
|
||||||
|
# Mock Settings().value('advanced/slide max height')
|
||||||
|
self.mocked_Settings_obj.value.return_value = 0
|
||||||
|
# Mock self.viewport().width()
|
||||||
|
self.mocked_viewport_obj.width.return_value = 200
|
||||||
|
# Mock image service item
|
||||||
|
service_item = MagicMock()
|
||||||
|
service_item.is_text.return_value = False
|
||||||
|
service_item.get_frames.return_value = [{'title': None, 'path': None, 'image': None},
|
||||||
|
{'title': None, 'path': None, 'image': None}]
|
||||||
|
# Mock self.cellWidget().children().setMaximumWidth()
|
||||||
|
mocked_cellWidget_child = MagicMock()
|
||||||
|
mocked_cellWidget_obj = MagicMock()
|
||||||
|
mocked_cellWidget_obj.children.return_value = [None, mocked_cellWidget_child]
|
||||||
|
mocked_cellWidget.return_value = mocked_cellWidget_obj
|
||||||
|
# init ListPreviewWidget and load service item
|
||||||
|
list_preview_widget = ListPreviewWidget(None, 1)
|
||||||
|
list_preview_widget.replace_service_item(service_item, 200, 0)
|
||||||
|
|
||||||
|
# WHEN: row_resized() is called
|
||||||
|
list_preview_widget.row_resized(0, 100, 150)
|
||||||
|
|
||||||
|
# THEN: self.cellWidget(row, 0).children()[1].setMaximumWidth() should not be called
|
||||||
|
self.assertEquals(mocked_cellWidget_child.setMaximumWidth.call_count, 0, 'Should not be called')
|
||||||
|
|
||||||
|
@patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.resizeRowsToContents')
|
||||||
|
@patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.setRowHeight')
|
||||||
|
@patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.cellWidget')
|
||||||
|
def row_resized_test_img_max(self, mocked_cellWidget, mocked_setRowHeight, mocked_resizeRowsToContents):
|
||||||
|
"""
|
||||||
|
Test if "Max height for non-text slides..." enabled, image-based slides are scaled in row_resized.
|
||||||
|
"""
|
||||||
|
# GIVEN: A setting to adjust "Max height for non-text slides in slide controller",
|
||||||
|
# an image ServiceItem and a ListPreviewWidget.
|
||||||
|
|
||||||
|
# Mock Settings().value('advanced/slide max height')
|
||||||
|
self.mocked_Settings_obj.value.return_value = 100
|
||||||
|
# Mock self.viewport().width()
|
||||||
|
self.mocked_viewport_obj.width.return_value = 200
|
||||||
|
# Mock image service item
|
||||||
|
service_item = MagicMock()
|
||||||
|
service_item.is_text.return_value = False
|
||||||
|
service_item.get_frames.return_value = [{'title': None, 'path': None, 'image': None},
|
||||||
|
{'title': None, 'path': None, 'image': None}]
|
||||||
|
# Mock self.cellWidget().children().setMaximumWidth()
|
||||||
|
mocked_cellWidget_child = MagicMock()
|
||||||
|
mocked_cellWidget_obj = MagicMock()
|
||||||
|
mocked_cellWidget_obj.children.return_value = [None, mocked_cellWidget_child]
|
||||||
|
mocked_cellWidget.return_value = mocked_cellWidget_obj
|
||||||
|
# init ListPreviewWidget and load service item
|
||||||
|
list_preview_widget = ListPreviewWidget(None, 1)
|
||||||
|
list_preview_widget.replace_service_item(service_item, 200, 0)
|
||||||
|
|
||||||
|
# WHEN: row_resized() is called
|
||||||
|
list_preview_widget.row_resized(0, 100, 150)
|
||||||
|
|
||||||
|
# THEN: self.cellWidget(row, 0).children()[1].setMaximumWidth() should be called
|
||||||
|
mocked_cellWidget_child.setMaximumWidth.assert_called_once_with(150)
|
||||||
|
@ -1,129 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
# OpenLP - Open Source Lyrics Projection #
|
|
||||||
# --------------------------------------------------------------------------- #
|
|
||||||
# Copyright (c) 2008-2016 OpenLP Developers #
|
|
||||||
# --------------------------------------------------------------------------- #
|
|
||||||
# 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 #
|
|
||||||
###############################################################################
|
|
||||||
"""
|
|
||||||
Package to test the openlp.core.utils.actions package.
|
|
||||||
"""
|
|
||||||
from unittest import TestCase
|
|
||||||
|
|
||||||
from openlp.core.common.settings import Settings
|
|
||||||
from openlp.core.utils import VersionThread, get_uno_command
|
|
||||||
from tests.functional import MagicMock, patch
|
|
||||||
from tests.helpers.testmixin import TestMixin
|
|
||||||
|
|
||||||
|
|
||||||
class TestInitFunctions(TestMixin, TestCase):
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
"""
|
|
||||||
Create an instance and a few example actions.
|
|
||||||
"""
|
|
||||||
self.build_settings()
|
|
||||||
|
|
||||||
def tearDown(self):
|
|
||||||
"""
|
|
||||||
Clean up
|
|
||||||
"""
|
|
||||||
self.destroy_settings()
|
|
||||||
|
|
||||||
def version_thread_triggered_test(self):
|
|
||||||
"""
|
|
||||||
Test the version thread call does not trigger UI
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
# GIVEN: a equal version setup and the data is not today.
|
|
||||||
mocked_main_window = MagicMock()
|
|
||||||
Settings().setValue('core/last version test', '1950-04-01')
|
|
||||||
# WHEN: We check to see if the version is different .
|
|
||||||
with patch('PyQt5.QtCore.QThread'),\
|
|
||||||
patch('openlp.core.utils.get_application_version') as mocked_get_application_version:
|
|
||||||
mocked_get_application_version.return_value = {'version': '1.0.0', 'build': '', 'full': '2.0.4'}
|
|
||||||
version_thread = VersionThread(mocked_main_window)
|
|
||||||
version_thread.run()
|
|
||||||
# THEN: If the version has changed the main window is notified
|
|
||||||
self.assertTrue(mocked_main_window.openlp_version_check.emit.called,
|
|
||||||
'The main windows should have been notified')
|
|
||||||
|
|
||||||
def get_uno_command_libreoffice_command_exists_test(self):
|
|
||||||
"""
|
|
||||||
Test the ``get_uno_command`` function uses the libreoffice command when available.
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
|
|
||||||
# GIVEN: A patched 'which' method which returns a path when called with 'libreoffice'
|
|
||||||
with patch('openlp.core.utils.which',
|
|
||||||
**{'side_effect': lambda command: {'libreoffice': '/usr/bin/libreoffice'}[command]}):
|
|
||||||
|
|
||||||
# WHEN: Calling get_uno_command
|
|
||||||
result = get_uno_command()
|
|
||||||
|
|
||||||
# THEN: The command 'libreoffice' should be called with the appropriate parameters
|
|
||||||
self.assertEquals(result, 'libreoffice --nologo --norestore --minimized --nodefault --nofirststartwizard'
|
|
||||||
' "--accept=pipe,name=openlp_pipe;urp;"')
|
|
||||||
|
|
||||||
def get_uno_command_only_soffice_command_exists_test(self):
|
|
||||||
"""
|
|
||||||
Test the ``get_uno_command`` function uses the soffice command when the libreoffice command is not available.
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
|
|
||||||
# GIVEN: A patched 'which' method which returns None when called with 'libreoffice' and a path when called with
|
|
||||||
# 'soffice'
|
|
||||||
with patch('openlp.core.utils.which',
|
|
||||||
**{'side_effect': lambda command: {'libreoffice': None, 'soffice': '/usr/bin/soffice'}[command]}):
|
|
||||||
|
|
||||||
# WHEN: Calling get_uno_command
|
|
||||||
result = get_uno_command()
|
|
||||||
|
|
||||||
# THEN: The command 'soffice' should be called with the appropriate parameters
|
|
||||||
self.assertEquals(result, 'soffice --nologo --norestore --minimized --nodefault --nofirststartwizard'
|
|
||||||
' "--accept=pipe,name=openlp_pipe;urp;"')
|
|
||||||
|
|
||||||
def get_uno_command_when_no_command_exists_test(self):
|
|
||||||
"""
|
|
||||||
Test the ``get_uno_command`` function raises an FileNotFoundError when neither the libreoffice or soffice
|
|
||||||
commands are available.
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
|
|
||||||
# GIVEN: A patched 'which' method which returns None
|
|
||||||
with patch('openlp.core.utils.which', **{'return_value': None}):
|
|
||||||
|
|
||||||
# WHEN: Calling get_uno_command
|
|
||||||
|
|
||||||
# THEN: a FileNotFoundError exception should be raised
|
|
||||||
self.assertRaises(FileNotFoundError, get_uno_command)
|
|
||||||
|
|
||||||
def get_uno_command_connection_type_test(self):
|
|
||||||
"""
|
|
||||||
Test the ``get_uno_command`` function when the connection type is anything other than pipe.
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
|
|
||||||
# GIVEN: A patched 'which' method which returns 'libreoffice'
|
|
||||||
with patch('openlp.core.utils.which', **{'return_value': 'libreoffice'}):
|
|
||||||
|
|
||||||
# WHEN: Calling get_uno_command with a connection type other than pipe
|
|
||||||
result = get_uno_command('socket')
|
|
||||||
|
|
||||||
# THEN: The connection parameters should be set for socket
|
|
||||||
self.assertEqual(result, 'libreoffice --nologo --norestore --minimized --nodefault --nofirststartwizard'
|
|
||||||
' "--accept=socket,host=localhost,port=2002;urp;"')
|
|
@ -1,491 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
# OpenLP - Open Source Lyrics Projection #
|
|
||||||
# --------------------------------------------------------------------------- #
|
|
||||||
# Copyright (c) 2008-2016 OpenLP Developers #
|
|
||||||
# --------------------------------------------------------------------------- #
|
|
||||||
# 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 #
|
|
||||||
###############################################################################
|
|
||||||
"""
|
|
||||||
Functional tests to test the AppLocation class and related methods.
|
|
||||||
"""
|
|
||||||
import os
|
|
||||||
from unittest import TestCase
|
|
||||||
|
|
||||||
from openlp.core.utils import clean_filename, delete_file, get_filesystem_encoding, get_locale_key, \
|
|
||||||
get_natural_key, split_filename, _get_user_agent, get_web_page, get_uno_instance, add_actions
|
|
||||||
from tests.functional import MagicMock, patch
|
|
||||||
|
|
||||||
|
|
||||||
class TestUtils(TestCase):
|
|
||||||
"""
|
|
||||||
A test suite to test out various methods around the AppLocation class.
|
|
||||||
"""
|
|
||||||
def add_actions_empty_list_test(self):
|
|
||||||
"""
|
|
||||||
Test that no actions are added when the list is empty
|
|
||||||
"""
|
|
||||||
# GIVEN: a mocked action list, and an empty list
|
|
||||||
mocked_target = MagicMock()
|
|
||||||
empty_list = []
|
|
||||||
|
|
||||||
# WHEN: The empty list is added to the mocked target
|
|
||||||
add_actions(mocked_target, empty_list)
|
|
||||||
|
|
||||||
# THEN: The add method on the mocked target is never called
|
|
||||||
self.assertEqual(0, mocked_target.addSeparator.call_count, 'addSeparator method should not have been called')
|
|
||||||
self.assertEqual(0, mocked_target.addAction.call_count, 'addAction method should not have been called')
|
|
||||||
|
|
||||||
def add_actions_none_action_test(self):
|
|
||||||
"""
|
|
||||||
Test that a separator is added when a None action is in the list
|
|
||||||
"""
|
|
||||||
# GIVEN: a mocked action list, and a list with None in it
|
|
||||||
mocked_target = MagicMock()
|
|
||||||
separator_list = [None]
|
|
||||||
|
|
||||||
# WHEN: The list is added to the mocked target
|
|
||||||
add_actions(mocked_target, separator_list)
|
|
||||||
|
|
||||||
# THEN: The addSeparator method is called, but the addAction method is never called
|
|
||||||
mocked_target.addSeparator.assert_called_with()
|
|
||||||
self.assertEqual(0, mocked_target.addAction.call_count, 'addAction method should not have been called')
|
|
||||||
|
|
||||||
def add_actions_add_action_test(self):
|
|
||||||
"""
|
|
||||||
Test that an action is added when a valid action is in the list
|
|
||||||
"""
|
|
||||||
# GIVEN: a mocked action list, and a list with an action in it
|
|
||||||
mocked_target = MagicMock()
|
|
||||||
action_list = ['action']
|
|
||||||
|
|
||||||
# WHEN: The list is added to the mocked target
|
|
||||||
add_actions(mocked_target, action_list)
|
|
||||||
|
|
||||||
# THEN: The addSeparator method is not called, and the addAction method is called
|
|
||||||
self.assertEqual(0, mocked_target.addSeparator.call_count, 'addSeparator method should not have been called')
|
|
||||||
mocked_target.addAction.assert_called_with('action')
|
|
||||||
|
|
||||||
def add_actions_action_and_none_test(self):
|
|
||||||
"""
|
|
||||||
Test that an action and a separator are added when a valid action and None are in the list
|
|
||||||
"""
|
|
||||||
# GIVEN: a mocked action list, and a list with an action and None in it
|
|
||||||
mocked_target = MagicMock()
|
|
||||||
action_list = ['action', None]
|
|
||||||
|
|
||||||
# WHEN: The list is added to the mocked target
|
|
||||||
add_actions(mocked_target, action_list)
|
|
||||||
|
|
||||||
# THEN: The addSeparator method is called, and the addAction method is called
|
|
||||||
mocked_target.addSeparator.assert_called_with()
|
|
||||||
mocked_target.addAction.assert_called_with('action')
|
|
||||||
|
|
||||||
def get_filesystem_encoding_sys_function_not_called_test(self):
|
|
||||||
"""
|
|
||||||
Test the get_filesystem_encoding() function does not call the sys.getdefaultencoding() function
|
|
||||||
"""
|
|
||||||
# GIVEN: sys.getfilesystemencoding returns "cp1252"
|
|
||||||
with patch('openlp.core.utils.sys.getfilesystemencoding') as mocked_getfilesystemencoding, \
|
|
||||||
patch('openlp.core.utils.sys.getdefaultencoding') as mocked_getdefaultencoding:
|
|
||||||
mocked_getfilesystemencoding.return_value = 'cp1252'
|
|
||||||
|
|
||||||
# WHEN: get_filesystem_encoding() is called
|
|
||||||
result = get_filesystem_encoding()
|
|
||||||
|
|
||||||
# THEN: getdefaultencoding should have been called
|
|
||||||
mocked_getfilesystemencoding.assert_called_with()
|
|
||||||
self.assertEqual(0, mocked_getdefaultencoding.called, 'getdefaultencoding should not have been called')
|
|
||||||
self.assertEqual('cp1252', result, 'The result should be "cp1252"')
|
|
||||||
|
|
||||||
def get_filesystem_encoding_sys_function_is_called_test(self):
|
|
||||||
"""
|
|
||||||
Test the get_filesystem_encoding() function calls the sys.getdefaultencoding() function
|
|
||||||
"""
|
|
||||||
# GIVEN: sys.getfilesystemencoding returns None and sys.getdefaultencoding returns "utf-8"
|
|
||||||
with patch('openlp.core.utils.sys.getfilesystemencoding') as mocked_getfilesystemencoding, \
|
|
||||||
patch('openlp.core.utils.sys.getdefaultencoding') as mocked_getdefaultencoding:
|
|
||||||
mocked_getfilesystemencoding.return_value = None
|
|
||||||
mocked_getdefaultencoding.return_value = 'utf-8'
|
|
||||||
|
|
||||||
# WHEN: get_filesystem_encoding() is called
|
|
||||||
result = get_filesystem_encoding()
|
|
||||||
|
|
||||||
# THEN: getdefaultencoding should have been called
|
|
||||||
mocked_getfilesystemencoding.assert_called_with()
|
|
||||||
mocked_getdefaultencoding.assert_called_with()
|
|
||||||
self.assertEqual('utf-8', result, 'The result should be "utf-8"')
|
|
||||||
|
|
||||||
def split_filename_with_file_path_test(self):
|
|
||||||
"""
|
|
||||||
Test the split_filename() function with a path to a file
|
|
||||||
"""
|
|
||||||
# GIVEN: A path to a file.
|
|
||||||
if os.name == 'nt':
|
|
||||||
file_path = 'C:\\home\\user\\myfile.txt'
|
|
||||||
wanted_result = ('C:\\home\\user', 'myfile.txt')
|
|
||||||
else:
|
|
||||||
file_path = '/home/user/myfile.txt'
|
|
||||||
wanted_result = ('/home/user', 'myfile.txt')
|
|
||||||
with patch('openlp.core.utils.os.path.isfile') as mocked_is_file:
|
|
||||||
mocked_is_file.return_value = True
|
|
||||||
|
|
||||||
# WHEN: Split the file name.
|
|
||||||
result = split_filename(file_path)
|
|
||||||
|
|
||||||
# THEN: A tuple should be returned.
|
|
||||||
self.assertEqual(wanted_result, result, 'A tuple with the dir and file name should have been returned')
|
|
||||||
|
|
||||||
def split_filename_with_dir_path_test(self):
|
|
||||||
"""
|
|
||||||
Test the split_filename() function with a path to a directory
|
|
||||||
"""
|
|
||||||
# GIVEN: A path to a dir.
|
|
||||||
if os.name == 'nt':
|
|
||||||
file_path = 'C:\\home\\user\\mydir'
|
|
||||||
wanted_result = ('C:\\home\\user\\mydir', '')
|
|
||||||
else:
|
|
||||||
file_path = '/home/user/mydir'
|
|
||||||
wanted_result = ('/home/user/mydir', '')
|
|
||||||
with patch('openlp.core.utils.os.path.isfile') as mocked_is_file:
|
|
||||||
mocked_is_file.return_value = False
|
|
||||||
|
|
||||||
# WHEN: Split the file name.
|
|
||||||
result = split_filename(file_path)
|
|
||||||
|
|
||||||
# THEN: A tuple should be returned.
|
|
||||||
self.assertEqual(wanted_result, result,
|
|
||||||
'A two-entry tuple with the directory and file name (empty) should have been returned.')
|
|
||||||
|
|
||||||
def clean_filename_test(self):
|
|
||||||
"""
|
|
||||||
Test the clean_filename() function
|
|
||||||
"""
|
|
||||||
# GIVEN: A invalid file name and the valid file name.
|
|
||||||
invalid_name = 'A_file_with_invalid_characters_[\\/:\*\?"<>\|\+\[\]%].py'
|
|
||||||
wanted_name = 'A_file_with_invalid_characters______________________.py'
|
|
||||||
|
|
||||||
# WHEN: Clean the name.
|
|
||||||
result = clean_filename(invalid_name)
|
|
||||||
|
|
||||||
# THEN: The file name should be cleaned.
|
|
||||||
self.assertEqual(wanted_name, result, 'The file name should not contain any special characters.')
|
|
||||||
|
|
||||||
def delete_file_no_path_test(self):
|
|
||||||
"""
|
|
||||||
Test the delete_file function when called with out a valid path
|
|
||||||
"""
|
|
||||||
# GIVEN: A blank path
|
|
||||||
# WEHN: Calling delete_file
|
|
||||||
result = delete_file('')
|
|
||||||
|
|
||||||
# THEN: delete_file should return False
|
|
||||||
self.assertFalse(result, "delete_file should return False when called with ''")
|
|
||||||
|
|
||||||
def delete_file_path_success_test(self):
|
|
||||||
"""
|
|
||||||
Test the delete_file function when it successfully deletes a file
|
|
||||||
"""
|
|
||||||
# GIVEN: A mocked os which returns True when os.path.exists is called
|
|
||||||
with patch('openlp.core.utils.os', **{'path.exists.return_value': False}):
|
|
||||||
|
|
||||||
# WHEN: Calling delete_file with a file path
|
|
||||||
result = delete_file('path/file.ext')
|
|
||||||
|
|
||||||
# THEN: delete_file should return True
|
|
||||||
self.assertTrue(result, 'delete_file should return True when it successfully deletes a file')
|
|
||||||
|
|
||||||
def delete_file_path_no_file_exists_test(self):
|
|
||||||
"""
|
|
||||||
Test the delete_file function when the file to remove does not exist
|
|
||||||
"""
|
|
||||||
# GIVEN: A mocked os which returns False when os.path.exists is called
|
|
||||||
with patch('openlp.core.utils.os', **{'path.exists.return_value': False}):
|
|
||||||
|
|
||||||
# WHEN: Calling delete_file with a file path
|
|
||||||
result = delete_file('path/file.ext')
|
|
||||||
|
|
||||||
# THEN: delete_file should return True
|
|
||||||
self.assertTrue(result, 'delete_file should return True when the file doesnt exist')
|
|
||||||
|
|
||||||
def delete_file_path_exception_test(self):
|
|
||||||
"""
|
|
||||||
Test the delete_file function when os.remove raises an exception
|
|
||||||
"""
|
|
||||||
# GIVEN: A mocked os which returns True when os.path.exists is called and raises an OSError when os.remove is
|
|
||||||
# called.
|
|
||||||
with patch('openlp.core.utils.os', **{'path.exists.return_value': True, 'path.exists.side_effect': OSError}), \
|
|
||||||
patch('openlp.core.utils.log') as mocked_log:
|
|
||||||
|
|
||||||
# WHEN: Calling delete_file with a file path
|
|
||||||
result = delete_file('path/file.ext')
|
|
||||||
|
|
||||||
# THEN: delete_file should log and exception and return False
|
|
||||||
self.assertEqual(mocked_log.exception.call_count, 1)
|
|
||||||
self.assertFalse(result, 'delete_file should return False when os.remove raises an OSError')
|
|
||||||
|
|
||||||
def get_locale_key_test(self):
|
|
||||||
"""
|
|
||||||
Test the get_locale_key(string) function
|
|
||||||
"""
|
|
||||||
with patch('openlp.core.common.languagemanager.LanguageManager.get_language') as mocked_get_language:
|
|
||||||
# GIVEN: The language is German
|
|
||||||
# 0x00C3 (A with diaresis) should be sorted as "A". 0x00DF (sharp s) should be sorted as "ss".
|
|
||||||
mocked_get_language.return_value = 'de'
|
|
||||||
unsorted_list = ['Auszug', 'Aushang', '\u00C4u\u00DFerung']
|
|
||||||
|
|
||||||
# WHEN: We sort the list and use get_locale_key() to generate the sorting keys
|
|
||||||
sorted_list = sorted(unsorted_list, key=get_locale_key)
|
|
||||||
|
|
||||||
# THEN: We get a properly sorted list
|
|
||||||
self.assertEqual(['Aushang', '\u00C4u\u00DFerung', 'Auszug'], sorted_list,
|
|
||||||
'Strings should be sorted properly')
|
|
||||||
|
|
||||||
def get_natural_key_test(self):
|
|
||||||
"""
|
|
||||||
Test the get_natural_key(string) function
|
|
||||||
"""
|
|
||||||
with patch('openlp.core.common.languagemanager.LanguageManager.get_language') as mocked_get_language:
|
|
||||||
# GIVEN: The language is English (a language, which sorts digits before letters)
|
|
||||||
mocked_get_language.return_value = 'en'
|
|
||||||
unsorted_list = ['item 10a', 'item 3b', '1st item']
|
|
||||||
|
|
||||||
# WHEN: We sort the list and use get_natural_key() to generate the sorting keys
|
|
||||||
sorted_list = sorted(unsorted_list, key=get_natural_key)
|
|
||||||
|
|
||||||
# THEN: We get a properly sorted list
|
|
||||||
self.assertEqual(['1st item', 'item 3b', 'item 10a'], sorted_list, 'Numbers should be sorted naturally')
|
|
||||||
|
|
||||||
def get_uno_instance_pipe_test(self):
|
|
||||||
"""
|
|
||||||
Test that when the UNO connection type is "pipe" the resolver is given the "pipe" URI
|
|
||||||
"""
|
|
||||||
# GIVEN: A mock resolver object and UNO_CONNECTION_TYPE is "pipe"
|
|
||||||
mock_resolver = MagicMock()
|
|
||||||
|
|
||||||
# WHEN: get_uno_instance() is called
|
|
||||||
get_uno_instance(mock_resolver)
|
|
||||||
|
|
||||||
# THEN: the resolve method is called with the correct argument
|
|
||||||
mock_resolver.resolve.assert_called_with('uno:pipe,name=openlp_pipe;urp;StarOffice.ComponentContext')
|
|
||||||
|
|
||||||
def get_uno_instance_socket_test(self):
|
|
||||||
"""
|
|
||||||
Test that when the UNO connection type is other than "pipe" the resolver is given the "socket" URI
|
|
||||||
"""
|
|
||||||
# GIVEN: A mock resolver object and UNO_CONNECTION_TYPE is "socket"
|
|
||||||
mock_resolver = MagicMock()
|
|
||||||
|
|
||||||
# WHEN: get_uno_instance() is called
|
|
||||||
get_uno_instance(mock_resolver, 'socket')
|
|
||||||
|
|
||||||
# THEN: the resolve method is called with the correct argument
|
|
||||||
mock_resolver.resolve.assert_called_with('uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext')
|
|
||||||
|
|
||||||
def get_user_agent_linux_test(self):
|
|
||||||
"""
|
|
||||||
Test that getting a user agent on Linux returns a user agent suitable for Linux
|
|
||||||
"""
|
|
||||||
with patch('openlp.core.utils.sys') as mocked_sys:
|
|
||||||
|
|
||||||
# GIVEN: The system is Linux
|
|
||||||
mocked_sys.platform = 'linux2'
|
|
||||||
|
|
||||||
# WHEN: We call _get_user_agent()
|
|
||||||
user_agent = _get_user_agent()
|
|
||||||
|
|
||||||
# THEN: The user agent is a Linux (or ChromeOS) user agent
|
|
||||||
result = 'Linux' in user_agent or 'CrOS' in user_agent
|
|
||||||
self.assertTrue(result, 'The user agent should be a valid Linux user agent')
|
|
||||||
|
|
||||||
def get_user_agent_windows_test(self):
|
|
||||||
"""
|
|
||||||
Test that getting a user agent on Windows returns a user agent suitable for Windows
|
|
||||||
"""
|
|
||||||
with patch('openlp.core.utils.sys') as mocked_sys:
|
|
||||||
|
|
||||||
# GIVEN: The system is Linux
|
|
||||||
mocked_sys.platform = 'win32'
|
|
||||||
|
|
||||||
# WHEN: We call _get_user_agent()
|
|
||||||
user_agent = _get_user_agent()
|
|
||||||
|
|
||||||
# THEN: The user agent is a Linux (or ChromeOS) user agent
|
|
||||||
self.assertIn('Windows', user_agent, 'The user agent should be a valid Windows user agent')
|
|
||||||
|
|
||||||
def get_user_agent_macos_test(self):
|
|
||||||
"""
|
|
||||||
Test that getting a user agent on OS X returns a user agent suitable for OS X
|
|
||||||
"""
|
|
||||||
with patch('openlp.core.utils.sys') as mocked_sys:
|
|
||||||
|
|
||||||
# GIVEN: The system is Linux
|
|
||||||
mocked_sys.platform = 'darwin'
|
|
||||||
|
|
||||||
# WHEN: We call _get_user_agent()
|
|
||||||
user_agent = _get_user_agent()
|
|
||||||
|
|
||||||
# THEN: The user agent is a Linux (or ChromeOS) user agent
|
|
||||||
self.assertIn('Mac OS X', user_agent, 'The user agent should be a valid OS X user agent')
|
|
||||||
|
|
||||||
def get_user_agent_default_test(self):
|
|
||||||
"""
|
|
||||||
Test that getting a user agent on a non-Linux/Windows/OS X platform returns the default user agent
|
|
||||||
"""
|
|
||||||
with patch('openlp.core.utils.sys') as mocked_sys:
|
|
||||||
|
|
||||||
# GIVEN: The system is Linux
|
|
||||||
mocked_sys.platform = 'freebsd'
|
|
||||||
|
|
||||||
# WHEN: We call _get_user_agent()
|
|
||||||
user_agent = _get_user_agent()
|
|
||||||
|
|
||||||
# THEN: The user agent is a Linux (or ChromeOS) user agent
|
|
||||||
self.assertIn('NetBSD', user_agent, 'The user agent should be the default user agent')
|
|
||||||
|
|
||||||
def get_web_page_no_url_test(self):
|
|
||||||
"""
|
|
||||||
Test that sending a URL of None to the get_web_page method returns None
|
|
||||||
"""
|
|
||||||
# GIVEN: A None url
|
|
||||||
test_url = None
|
|
||||||
|
|
||||||
# WHEN: We try to get the test URL
|
|
||||||
result = get_web_page(test_url)
|
|
||||||
|
|
||||||
# THEN: None should be returned
|
|
||||||
self.assertIsNone(result, 'The return value of get_web_page should be None')
|
|
||||||
|
|
||||||
def get_web_page_test(self):
|
|
||||||
"""
|
|
||||||
Test that the get_web_page method works correctly
|
|
||||||
"""
|
|
||||||
with patch('openlp.core.utils.urllib.request.Request') as MockRequest, \
|
|
||||||
patch('openlp.core.utils.urllib.request.urlopen') as mock_urlopen, \
|
|
||||||
patch('openlp.core.utils._get_user_agent') as mock_get_user_agent, \
|
|
||||||
patch('openlp.core.utils.Registry') as MockRegistry:
|
|
||||||
# GIVEN: Mocked out objects and a fake URL
|
|
||||||
mocked_request_object = MagicMock()
|
|
||||||
MockRequest.return_value = mocked_request_object
|
|
||||||
mocked_page_object = MagicMock()
|
|
||||||
mock_urlopen.return_value = mocked_page_object
|
|
||||||
mock_get_user_agent.return_value = 'user_agent'
|
|
||||||
fake_url = 'this://is.a.fake/url'
|
|
||||||
|
|
||||||
# WHEN: The get_web_page() method is called
|
|
||||||
returned_page = get_web_page(fake_url)
|
|
||||||
|
|
||||||
# THEN: The correct methods are called with the correct arguments and a web page is returned
|
|
||||||
MockRequest.assert_called_with(fake_url)
|
|
||||||
mocked_request_object.add_header.assert_called_with('User-Agent', 'user_agent')
|
|
||||||
self.assertEqual(1, mocked_request_object.add_header.call_count,
|
|
||||||
'There should only be 1 call to add_header')
|
|
||||||
mock_get_user_agent.assert_called_with()
|
|
||||||
mock_urlopen.assert_called_with(mocked_request_object, timeout=30)
|
|
||||||
mocked_page_object.geturl.assert_called_with()
|
|
||||||
self.assertEqual(0, MockRegistry.call_count, 'The Registry() object should have never been called')
|
|
||||||
self.assertEqual(mocked_page_object, returned_page, 'The returned page should be the mock object')
|
|
||||||
|
|
||||||
def get_web_page_with_header_test(self):
|
|
||||||
"""
|
|
||||||
Test that adding a header to the call to get_web_page() adds the header to the request
|
|
||||||
"""
|
|
||||||
with patch('openlp.core.utils.urllib.request.Request') as MockRequest, \
|
|
||||||
patch('openlp.core.utils.urllib.request.urlopen') as mock_urlopen, \
|
|
||||||
patch('openlp.core.utils._get_user_agent') as mock_get_user_agent:
|
|
||||||
# GIVEN: Mocked out objects, a fake URL and a fake header
|
|
||||||
mocked_request_object = MagicMock()
|
|
||||||
MockRequest.return_value = mocked_request_object
|
|
||||||
mocked_page_object = MagicMock()
|
|
||||||
mock_urlopen.return_value = mocked_page_object
|
|
||||||
mock_get_user_agent.return_value = 'user_agent'
|
|
||||||
fake_url = 'this://is.a.fake/url'
|
|
||||||
fake_header = ('Fake-Header', 'fake value')
|
|
||||||
|
|
||||||
# WHEN: The get_web_page() method is called
|
|
||||||
returned_page = get_web_page(fake_url, header=fake_header)
|
|
||||||
|
|
||||||
# THEN: The correct methods are called with the correct arguments and a web page is returned
|
|
||||||
MockRequest.assert_called_with(fake_url)
|
|
||||||
mocked_request_object.add_header.assert_called_with(fake_header[0], fake_header[1])
|
|
||||||
self.assertEqual(2, mocked_request_object.add_header.call_count,
|
|
||||||
'There should only be 2 calls to add_header')
|
|
||||||
mock_get_user_agent.assert_called_with()
|
|
||||||
mock_urlopen.assert_called_with(mocked_request_object, timeout=30)
|
|
||||||
mocked_page_object.geturl.assert_called_with()
|
|
||||||
self.assertEqual(mocked_page_object, returned_page, 'The returned page should be the mock object')
|
|
||||||
|
|
||||||
def get_web_page_with_user_agent_in_headers_test(self):
|
|
||||||
"""
|
|
||||||
Test that adding a user agent in the header when calling get_web_page() adds that user agent to the request
|
|
||||||
"""
|
|
||||||
with patch('openlp.core.utils.urllib.request.Request') as MockRequest, \
|
|
||||||
patch('openlp.core.utils.urllib.request.urlopen') as mock_urlopen, \
|
|
||||||
patch('openlp.core.utils._get_user_agent') as mock_get_user_agent:
|
|
||||||
# GIVEN: Mocked out objects, a fake URL and a fake header
|
|
||||||
mocked_request_object = MagicMock()
|
|
||||||
MockRequest.return_value = mocked_request_object
|
|
||||||
mocked_page_object = MagicMock()
|
|
||||||
mock_urlopen.return_value = mocked_page_object
|
|
||||||
fake_url = 'this://is.a.fake/url'
|
|
||||||
user_agent_header = ('User-Agent', 'OpenLP/2.2.0')
|
|
||||||
|
|
||||||
# WHEN: The get_web_page() method is called
|
|
||||||
returned_page = get_web_page(fake_url, header=user_agent_header)
|
|
||||||
|
|
||||||
# THEN: The correct methods are called with the correct arguments and a web page is returned
|
|
||||||
MockRequest.assert_called_with(fake_url)
|
|
||||||
mocked_request_object.add_header.assert_called_with(user_agent_header[0], user_agent_header[1])
|
|
||||||
self.assertEqual(1, mocked_request_object.add_header.call_count,
|
|
||||||
'There should only be 1 call to add_header')
|
|
||||||
self.assertEqual(0, mock_get_user_agent.call_count, '_get_user_agent should not have been called')
|
|
||||||
mock_urlopen.assert_called_with(mocked_request_object, timeout=30)
|
|
||||||
mocked_page_object.geturl.assert_called_with()
|
|
||||||
self.assertEqual(mocked_page_object, returned_page, 'The returned page should be the mock object')
|
|
||||||
|
|
||||||
def get_web_page_update_openlp_test(self):
|
|
||||||
"""
|
|
||||||
Test that passing "update_openlp" as true to get_web_page calls Registry().get('app').process_events()
|
|
||||||
"""
|
|
||||||
with patch('openlp.core.utils.urllib.request.Request') as MockRequest, \
|
|
||||||
patch('openlp.core.utils.urllib.request.urlopen') as mock_urlopen, \
|
|
||||||
patch('openlp.core.utils._get_user_agent') as mock_get_user_agent, \
|
|
||||||
patch('openlp.core.utils.Registry') as MockRegistry:
|
|
||||||
# GIVEN: Mocked out objects, a fake URL
|
|
||||||
mocked_request_object = MagicMock()
|
|
||||||
MockRequest.return_value = mocked_request_object
|
|
||||||
mocked_page_object = MagicMock()
|
|
||||||
mock_urlopen.return_value = mocked_page_object
|
|
||||||
mock_get_user_agent.return_value = 'user_agent'
|
|
||||||
mocked_registry_object = MagicMock()
|
|
||||||
mocked_application_object = MagicMock()
|
|
||||||
mocked_registry_object.get.return_value = mocked_application_object
|
|
||||||
MockRegistry.return_value = mocked_registry_object
|
|
||||||
fake_url = 'this://is.a.fake/url'
|
|
||||||
|
|
||||||
# WHEN: The get_web_page() method is called
|
|
||||||
returned_page = get_web_page(fake_url, update_openlp=True)
|
|
||||||
|
|
||||||
# THEN: The correct methods are called with the correct arguments and a web page is returned
|
|
||||||
MockRequest.assert_called_with(fake_url)
|
|
||||||
mocked_request_object.add_header.assert_called_with('User-Agent', 'user_agent')
|
|
||||||
self.assertEqual(1, mocked_request_object.add_header.call_count,
|
|
||||||
'There should only be 1 call to add_header')
|
|
||||||
mock_urlopen.assert_called_with(mocked_request_object, timeout=30)
|
|
||||||
mocked_page_object.geturl.assert_called_with()
|
|
||||||
mocked_registry_object.get.assert_called_with('application')
|
|
||||||
mocked_application_object.process_events.assert_called_with()
|
|
||||||
self.assertEqual(mocked_page_object, returned_page, 'The returned page should be the mock object')
|
|
@ -99,7 +99,7 @@ class TestRemoteTab(TestCase, TestMixin):
|
|||||||
"""
|
"""
|
||||||
# GIVEN: A mocked location
|
# GIVEN: A mocked location
|
||||||
with patch('openlp.core.common.Settings') as mocked_class, \
|
with patch('openlp.core.common.Settings') as mocked_class, \
|
||||||
patch('openlp.core.utils.AppLocation.get_directory') as mocked_get_directory, \
|
patch('openlp.core.common.applocation.AppLocation.get_directory') as mocked_get_directory, \
|
||||||
patch('openlp.core.common.check_directory_exists') as mocked_check_directory_exists, \
|
patch('openlp.core.common.check_directory_exists') as mocked_check_directory_exists, \
|
||||||
patch('openlp.core.common.applocation.os') as mocked_os:
|
patch('openlp.core.common.applocation.os') as mocked_os:
|
||||||
# GIVEN: A mocked out Settings class and a mocked out AppLocation.get_directory()
|
# GIVEN: A mocked out Settings class and a mocked out AppLocation.get_directory()
|
||||||
@ -127,7 +127,7 @@ class TestRemoteTab(TestCase, TestMixin):
|
|||||||
"""
|
"""
|
||||||
# GIVEN: A mocked location
|
# GIVEN: A mocked location
|
||||||
with patch('openlp.core.common.Settings') as mocked_class, \
|
with patch('openlp.core.common.Settings') as mocked_class, \
|
||||||
patch('openlp.core.utils.AppLocation.get_directory') as mocked_get_directory, \
|
patch('openlp.core.common.applocation.AppLocation.get_directory') as mocked_get_directory, \
|
||||||
patch('openlp.core.common.check_directory_exists') as mocked_check_directory_exists, \
|
patch('openlp.core.common.check_directory_exists') as mocked_check_directory_exists, \
|
||||||
patch('openlp.core.common.applocation.os') as mocked_os:
|
patch('openlp.core.common.applocation.os') as mocked_os:
|
||||||
# GIVEN: A mocked out Settings class and a mocked out AppLocation.get_directory()
|
# GIVEN: A mocked out Settings class and a mocked out AppLocation.get_directory()
|
||||||
|
@ -127,6 +127,38 @@ class TestMediaItem(TestCase, TestMixin):
|
|||||||
mock_qlist_widget.setData.assert_called_with(MockedUserRole, mock_song.id)
|
mock_qlist_widget.setData.assert_called_with(MockedUserRole, mock_song.id)
|
||||||
self.media_item.list_view.addItem.assert_called_with(mock_qlist_widget)
|
self.media_item.list_view.addItem.assert_called_with(mock_qlist_widget)
|
||||||
|
|
||||||
|
def display_results_book_test(self):
|
||||||
|
"""
|
||||||
|
Test displaying song search results grouped by book and entry with basic song
|
||||||
|
"""
|
||||||
|
# GIVEN: Search results grouped by book and entry, plus a mocked QtListWidgetItem
|
||||||
|
with patch('openlp.core.lib.QtWidgets.QListWidgetItem') as MockedQListWidgetItem, \
|
||||||
|
patch('openlp.core.lib.QtCore.Qt.UserRole') as MockedUserRole:
|
||||||
|
mock_search_results = []
|
||||||
|
mock_songbook_entry = MagicMock()
|
||||||
|
mock_songbook = MagicMock()
|
||||||
|
mock_song = MagicMock()
|
||||||
|
mock_songbook_entry.entry = '1'
|
||||||
|
mock_songbook.name = 'My Book'
|
||||||
|
mock_song.id = 1
|
||||||
|
mock_song.title = 'My Song'
|
||||||
|
mock_song.sort_key = 'My Song'
|
||||||
|
mock_song.temporary = False
|
||||||
|
mock_songbook_entry.song = mock_song
|
||||||
|
mock_songbook_entry.songbook = mock_songbook
|
||||||
|
mock_search_results.append(mock_songbook_entry)
|
||||||
|
mock_qlist_widget = MagicMock()
|
||||||
|
MockedQListWidgetItem.return_value = mock_qlist_widget
|
||||||
|
|
||||||
|
# WHEN: I display song search results grouped by book
|
||||||
|
self.media_item.display_results_book(mock_search_results)
|
||||||
|
|
||||||
|
# THEN: The current list view is cleared, the widget is created, and the relevant attributes set
|
||||||
|
self.media_item.list_view.clear.assert_called_with()
|
||||||
|
MockedQListWidgetItem.assert_called_with('My Book #1: My Song')
|
||||||
|
mock_qlist_widget.setData.assert_called_with(MockedUserRole, mock_songbook_entry.song.id)
|
||||||
|
self.media_item.list_view.addItem.assert_called_with(mock_qlist_widget)
|
||||||
|
|
||||||
def display_results_topic_test(self):
|
def display_results_topic_test(self):
|
||||||
"""
|
"""
|
||||||
Test displaying song search results grouped by topic with basic song
|
Test displaying song search results grouped by topic with basic song
|
||||||
@ -416,19 +448,6 @@ class TestMediaItem(TestCase, TestMixin):
|
|||||||
# THEN: They should not match
|
# THEN: They should not match
|
||||||
self.assertFalse(result, "Authors should not match")
|
self.assertFalse(result, "Authors should not match")
|
||||||
|
|
||||||
def natural_sort_key_test(self):
|
|
||||||
"""
|
|
||||||
Test the _natural_sort_key function
|
|
||||||
"""
|
|
||||||
# GIVEN: A string to be converted into a sort key
|
|
||||||
string_sort_key = 'A1B12C'
|
|
||||||
|
|
||||||
# WHEN: We attempt to create a sort key
|
|
||||||
sort_key_result = self.media_item._natural_sort_key(string_sort_key)
|
|
||||||
|
|
||||||
# THEN: We should get back a tuple split on integers
|
|
||||||
self.assertEqual(sort_key_result, ['a', 1, 'b', 12, 'c'])
|
|
||||||
|
|
||||||
def build_remote_search_test(self):
|
def build_remote_search_test(self):
|
||||||
"""
|
"""
|
||||||
Test results for the remote search api
|
Test results for the remote search api
|
||||||
|
@ -39,9 +39,23 @@ class TestProPresenterFileImport(SongImportTestHelper):
|
|||||||
self.importer_module_name = 'propresenter'
|
self.importer_module_name = 'propresenter'
|
||||||
super(TestProPresenterFileImport, self).__init__(*args, **kwargs)
|
super(TestProPresenterFileImport, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
def test_song_import(self):
|
def test_pro4_song_import(self):
|
||||||
"""
|
"""
|
||||||
Test that loading a ProPresenter file works correctly
|
Test that loading a ProPresenter 4 file works correctly
|
||||||
"""
|
"""
|
||||||
self.file_import([os.path.join(TEST_PATH, 'Amazing Grace.pro4')],
|
self.file_import([os.path.join(TEST_PATH, 'Amazing Grace.pro4')],
|
||||||
self.load_external_result_data(os.path.join(TEST_PATH, 'Amazing Grace.json')))
|
self.load_external_result_data(os.path.join(TEST_PATH, 'Amazing Grace.json')))
|
||||||
|
|
||||||
|
def test_pro5_song_import(self):
|
||||||
|
"""
|
||||||
|
Test that loading a ProPresenter 5 file works correctly
|
||||||
|
"""
|
||||||
|
self.file_import([os.path.join(TEST_PATH, 'Amazing Grace.pro5')],
|
||||||
|
self.load_external_result_data(os.path.join(TEST_PATH, 'Amazing Grace.json')))
|
||||||
|
|
||||||
|
def test_pro6_song_import(self):
|
||||||
|
"""
|
||||||
|
Test that loading a ProPresenter 6 file works correctly
|
||||||
|
"""
|
||||||
|
self.file_import([os.path.join(TEST_PATH, 'Amazing Grace.pro6')],
|
||||||
|
self.load_external_result_data(os.path.join(TEST_PATH, 'Amazing Grace.json')))
|
||||||
|
@ -25,7 +25,7 @@ Functional tests to test the AppLocation class and related methods.
|
|||||||
import os
|
import os
|
||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
|
|
||||||
from openlp.core.utils import is_not_image_file
|
from openlp.core.common import is_not_image_file
|
||||||
from tests.utils.constants import TEST_RESOURCES_PATH
|
from tests.utils.constants import TEST_RESOURCES_PATH
|
||||||
from tests.helpers.testmixin import TestMixin
|
from tests.helpers.testmixin import TestMixin
|
||||||
|
|
@ -28,9 +28,8 @@ from unittest import TestCase
|
|||||||
from PyQt5 import QtWidgets
|
from PyQt5 import QtWidgets
|
||||||
|
|
||||||
from openlp.core.common import Registry
|
from openlp.core.common import Registry
|
||||||
from openlp.core.common import HistoryComboBox
|
from openlp.core.ui.lib.historycombobox import HistoryComboBox
|
||||||
from tests.helpers.testmixin import TestMixin
|
from tests.helpers.testmixin import TestMixin
|
||||||
from tests.interfaces import MagicMock, patch
|
|
||||||
|
|
||||||
|
|
||||||
class TestHistoryComboBox(TestCase, TestMixin):
|
class TestHistoryComboBox(TestCase, TestMixin):
|
520
tests/resources/propresentersongs/Amazing Grace.pro5
Normal file
520
tests/resources/propresentersongs/Amazing Grace.pro5
Normal file
@ -0,0 +1,520 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<RVPresentationDocument height="768" width="1024" docType="0" versionNumber="500" creatorCode="1349676880" lastDateUsed="2016-03-30T16:21:32+0000" category="Hymn" backgroundColor="0 0 0 1" drawingBackgroundColor="0" notes="" artist="John Newton" author="" album="" CCLIDisplay="0" CCLIArtistCredits="" CCLISongTitle="Amazing Grace" CCLIPublisher="" CCLICopyrightInfo="" CCLILicenseNumber="" resourcesDirectory="" chordChartPath="">
|
||||||
|
<groups containerClass="NSMutableArray">
|
||||||
|
<RVSlideGrouping name="" uuid="E2F65DE0-5E6D-4290-8C07-D01CAFA3D00C" color="1 1 1 0" serialization-array-index="0">
|
||||||
|
<slides containerClass="NSMutableArray">
|
||||||
|
<RVDisplaySlide backgroundColor="0 0 0 0" enabled="1" highlightColor="" hotKey="" label="" notes="" slideType="1" sort_index="0" UUID="A67250CF-0DCC-4169-80EA-7E417CC233B3" drawingBackgroundColor="0" chordChartPath="" serialization-array-index="0">
|
||||||
|
<cues containerClass="NSMutableArray" />
|
||||||
|
<displayElements containerClass="NSMutableArray">
|
||||||
|
<RVTextElement displayDelay="0" locked="0" persistent="0" typeID="0" fromTemplate="0" bezelRadius="0" drawingFill="0" drawingShadow="1" drawingStroke="0" fillColor="0 0 0 0" rotation="0" source="" displayName="" adjustsHeightToFit="0" verticalAlignment="0" RTFData="e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBBbWF6aW5nIGdyYWNlISBIb3cgc3dlZXQgdGhlIHNvdW5kfVxsaTBcc2EwXHNiMFxmaTBccWNccGFyfQ0KfQ0KfQ==" revealType="0" serialization-array-index="0">
|
||||||
|
<_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" />
|
||||||
|
<_-D-_serializedShadow containerClass="NSMutableDictionary">
|
||||||
|
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="shadowColor" />
|
||||||
|
<NSMutableString serialization-native-value="{0, 0}" serialization-dictionary-key="shadowOffset" />
|
||||||
|
<NSNumber serialization-native-value="0" serialization-dictionary-key="shadowBlurRadius" />
|
||||||
|
</_-D-_serializedShadow>
|
||||||
|
<stroke containerClass="NSMutableDictionary">
|
||||||
|
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="RVShapeElementStrokeColorKey" />
|
||||||
|
<NSNumber serialization-native-value="0" serialization-dictionary-key="RVShapeElementStrokeWidthKey" />
|
||||||
|
</stroke>
|
||||||
|
</RVTextElement>
|
||||||
|
</displayElements>
|
||||||
|
<_-RVProTransitionObject-_transitionObject transitionType="-1" transitionDuration="1" motionEnabled="0" motionSpeed="0" />
|
||||||
|
</RVDisplaySlide>
|
||||||
|
<RVDisplaySlide backgroundColor="0 0 0 0" enabled="1" highlightColor="0 0 0 0" hotKey="" label="" notes="" slideType="1" sort_index="1" UUID="B09CAF20-B402-43C3-AA35-C09B1A2CEB25" drawingBackgroundColor="0" chordChartPath="" serialization-array-index="1">
|
||||||
|
<cues containerClass="NSMutableArray" />
|
||||||
|
<displayElements containerClass="NSMutableArray">
|
||||||
|
<RVTextElement displayDelay="0" locked="0" persistent="0" typeID="0" fromTemplate="0" bezelRadius="0" drawingFill="0" drawingShadow="1" drawingStroke="0" fillColor="0 0 0 0" rotation="0" source="" displayName="" adjustsHeightToFit="0" verticalAlignment="0" RTFData="e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBUaGF0IHNhdmVkIGEgd3JldGNoIGxpa2UgbWUhfVxsaTBcc2EwXHNiMFxmaTBccWNccGFyfQ0KfQ0KfQ==" revealType="0" serialization-array-index="0">
|
||||||
|
<_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" />
|
||||||
|
<_-D-_serializedShadow containerClass="NSMutableDictionary">
|
||||||
|
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="shadowColor" />
|
||||||
|
<NSMutableString serialization-native-value="{0, 0}" serialization-dictionary-key="shadowOffset" />
|
||||||
|
<NSNumber serialization-native-value="0" serialization-dictionary-key="shadowBlurRadius" />
|
||||||
|
</_-D-_serializedShadow>
|
||||||
|
<stroke containerClass="NSMutableDictionary">
|
||||||
|
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="RVShapeElementStrokeColorKey" />
|
||||||
|
<NSNumber serialization-native-value="0" serialization-dictionary-key="RVShapeElementStrokeWidthKey" />
|
||||||
|
</stroke>
|
||||||
|
</RVTextElement>
|
||||||
|
</displayElements>
|
||||||
|
<_-RVProTransitionObject-_transitionObject transitionType="-1" transitionDuration="1" motionEnabled="0" motionSpeed="0" />
|
||||||
|
</RVDisplaySlide>
|
||||||
|
<RVDisplaySlide backgroundColor="0 0 0 0" enabled="1" highlightColor="0 0 0 0" hotKey="" label="" notes="" slideType="1" sort_index="2" UUID="CCF908FC-0FE4-4C16-BE70-9543C2A76DC7" drawingBackgroundColor="0" chordChartPath="" serialization-array-index="2">
|
||||||
|
<cues containerClass="NSMutableArray" />
|
||||||
|
<displayElements containerClass="NSMutableArray">
|
||||||
|
<RVTextElement displayDelay="0" locked="0" persistent="0" typeID="0" fromTemplate="0" bezelRadius="0" drawingFill="0" drawingShadow="1" drawingStroke="0" fillColor="0 0 0 0" rotation="0" source="" displayName="" adjustsHeightToFit="0" verticalAlignment="0" RTFData="e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBJIG9uY2Ugd2FzIGxvc3QsIGJ1dCBub3cgYW0gZm91bmQ7fVxsaTBcc2EwXHNiMFxmaTBccWNccGFyfQ0KfQ0KfQ==" revealType="0" serialization-array-index="0">
|
||||||
|
<_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" />
|
||||||
|
<_-D-_serializedShadow containerClass="NSMutableDictionary">
|
||||||
|
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="shadowColor" />
|
||||||
|
<NSMutableString serialization-native-value="{0, 0}" serialization-dictionary-key="shadowOffset" />
|
||||||
|
<NSNumber serialization-native-value="0" serialization-dictionary-key="shadowBlurRadius" />
|
||||||
|
</_-D-_serializedShadow>
|
||||||
|
<stroke containerClass="NSMutableDictionary">
|
||||||
|
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="RVShapeElementStrokeColorKey" />
|
||||||
|
<NSNumber serialization-native-value="0" serialization-dictionary-key="RVShapeElementStrokeWidthKey" />
|
||||||
|
</stroke>
|
||||||
|
</RVTextElement>
|
||||||
|
</displayElements>
|
||||||
|
<_-RVProTransitionObject-_transitionObject transitionType="-1" transitionDuration="1" motionEnabled="0" motionSpeed="0" />
|
||||||
|
</RVDisplaySlide>
|
||||||
|
<RVDisplaySlide backgroundColor="0 0 0 0" enabled="1" highlightColor="0 0 0 0" hotKey="" label="" notes="" slideType="1" sort_index="3" UUID="B33AF602-61BB-47FE-95E3-98640D6BD76A" drawingBackgroundColor="0" chordChartPath="" serialization-array-index="3">
|
||||||
|
<cues containerClass="NSMutableArray" />
|
||||||
|
<displayElements containerClass="NSMutableArray">
|
||||||
|
<RVTextElement displayDelay="0" locked="0" persistent="0" typeID="0" fromTemplate="0" bezelRadius="0" drawingFill="0" drawingShadow="1" drawingStroke="0" fillColor="0 0 0 0" rotation="0" source="" displayName="" adjustsHeightToFit="0" verticalAlignment="0" RTFData="e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBXYXMgYmxpbmQsIGJ1dCBub3cgSSBzZWUufVxsaTBcc2EwXHNiMFxmaTBccWNccGFyfQ0KfQ0KfQ==" revealType="0" serialization-array-index="0">
|
||||||
|
<_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" />
|
||||||
|
<_-D-_serializedShadow containerClass="NSMutableDictionary">
|
||||||
|
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="shadowColor" />
|
||||||
|
<NSMutableString serialization-native-value="{0, 0}" serialization-dictionary-key="shadowOffset" />
|
||||||
|
<NSNumber serialization-native-value="0" serialization-dictionary-key="shadowBlurRadius" />
|
||||||
|
</_-D-_serializedShadow>
|
||||||
|
<stroke containerClass="NSMutableDictionary">
|
||||||
|
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="RVShapeElementStrokeColorKey" />
|
||||||
|
<NSNumber serialization-native-value="0" serialization-dictionary-key="RVShapeElementStrokeWidthKey" />
|
||||||
|
</stroke>
|
||||||
|
</RVTextElement>
|
||||||
|
</displayElements>
|
||||||
|
<_-RVProTransitionObject-_transitionObject transitionType="-1" transitionDuration="1" motionEnabled="0" motionSpeed="0" />
|
||||||
|
</RVDisplaySlide>
|
||||||
|
<RVDisplaySlide backgroundColor="0 0 0 0" enabled="1" highlightColor="0 0 0 0" hotKey="" label="" notes="" slideType="1" sort_index="4" UUID="02932C9A-C505-4856-A48E-339CA927B020" drawingBackgroundColor="0" chordChartPath="" serialization-array-index="4">
|
||||||
|
<cues containerClass="NSMutableArray" />
|
||||||
|
<displayElements containerClass="NSMutableArray">
|
||||||
|
<RVTextElement displayDelay="0" locked="0" persistent="0" typeID="0" fromTemplate="0" bezelRadius="0" drawingFill="0" drawingShadow="1" drawingStroke="0" fillColor="0 0 0 0" rotation="0" source="" displayName="" adjustsHeightToFit="0" verticalAlignment="0" RTFData="e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCAnVHdhcyBncmFjZSB0aGF0IHRhdWdodCBteSBoZWFydCB0byBmZWFyLH1cbGkwXHNhMFxzYjBcZmkwXHFjXHBhcn0NCn0NCn0=" revealType="0" serialization-array-index="0">
|
||||||
|
<_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" />
|
||||||
|
<_-D-_serializedShadow containerClass="NSMutableDictionary">
|
||||||
|
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="shadowColor" />
|
||||||
|
<NSMutableString serialization-native-value="{0, 0}" serialization-dictionary-key="shadowOffset" />
|
||||||
|
<NSNumber serialization-native-value="0" serialization-dictionary-key="shadowBlurRadius" />
|
||||||
|
</_-D-_serializedShadow>
|
||||||
|
<stroke containerClass="NSMutableDictionary">
|
||||||
|
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="RVShapeElementStrokeColorKey" />
|
||||||
|
<NSNumber serialization-native-value="0" serialization-dictionary-key="RVShapeElementStrokeWidthKey" />
|
||||||
|
</stroke>
|
||||||
|
</RVTextElement>
|
||||||
|
</displayElements>
|
||||||
|
<_-RVProTransitionObject-_transitionObject transitionType="-1" transitionDuration="1" motionEnabled="0" motionSpeed="0" />
|
||||||
|
</RVDisplaySlide>
|
||||||
|
<RVDisplaySlide backgroundColor="0 0 0 0" enabled="1" highlightColor="0 0 0 0" hotKey="" label="" notes="" slideType="1" sort_index="5" UUID="F6FC7C3F-2A38-4D63-83B1-7EDA30371535" drawingBackgroundColor="0" chordChartPath="" serialization-array-index="5">
|
||||||
|
<cues containerClass="NSMutableArray" />
|
||||||
|
<displayElements containerClass="NSMutableArray">
|
||||||
|
<RVTextElement displayDelay="0" locked="0" persistent="0" typeID="0" fromTemplate="0" bezelRadius="0" drawingFill="0" drawingShadow="1" drawingStroke="0" fillColor="0 0 0 0" rotation="0" source="" displayName="" adjustsHeightToFit="0" verticalAlignment="0" RTFData="e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBBbmQgZ3JhY2UgbXkgZmVhcnMgcmVsaWV2ZWQ7fVxsaTBcc2EwXHNiMFxmaTBccWNccGFyfQ0KfQ0KfQ==" revealType="0" serialization-array-index="0">
|
||||||
|
<_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" />
|
||||||
|
<_-D-_serializedShadow containerClass="NSMutableDictionary">
|
||||||
|
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="shadowColor" />
|
||||||
|
<NSMutableString serialization-native-value="{0, 0}" serialization-dictionary-key="shadowOffset" />
|
||||||
|
<NSNumber serialization-native-value="0" serialization-dictionary-key="shadowBlurRadius" />
|
||||||
|
</_-D-_serializedShadow>
|
||||||
|
<stroke containerClass="NSMutableDictionary">
|
||||||
|
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="RVShapeElementStrokeColorKey" />
|
||||||
|
<NSNumber serialization-native-value="0" serialization-dictionary-key="RVShapeElementStrokeWidthKey" />
|
||||||
|
</stroke>
|
||||||
|
</RVTextElement>
|
||||||
|
</displayElements>
|
||||||
|
<_-RVProTransitionObject-_transitionObject transitionType="-1" transitionDuration="1" motionEnabled="0" motionSpeed="0" />
|
||||||
|
</RVDisplaySlide>
|
||||||
|
<RVDisplaySlide backgroundColor="0 0 0 0" enabled="1" highlightColor="0 0 0 0" hotKey="" label="" notes="" slideType="1" sort_index="6" UUID="EEBFE94B-D0F2-4E41-BBE7-B5A7D4F62243" drawingBackgroundColor="0" chordChartPath="" serialization-array-index="6">
|
||||||
|
<cues containerClass="NSMutableArray" />
|
||||||
|
<displayElements containerClass="NSMutableArray">
|
||||||
|
<RVTextElement displayDelay="0" locked="0" persistent="0" typeID="0" fromTemplate="0" bezelRadius="0" drawingFill="0" drawingShadow="1" drawingStroke="0" fillColor="0 0 0 0" rotation="0" source="" displayName="" adjustsHeightToFit="0" verticalAlignment="0" RTFData="e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBIb3cgcHJlY2lvdXMgZGlkIHRoYXQgZ3JhY2UgYXBwZWFyfVxsaTBcc2EwXHNiMFxmaTBccWNccGFyfQ0KfQ0KfQ==" revealType="0" serialization-array-index="0">
|
||||||
|
<_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" />
|
||||||
|
<_-D-_serializedShadow containerClass="NSMutableDictionary">
|
||||||
|
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="shadowColor" />
|
||||||
|
<NSMutableString serialization-native-value="{0, 0}" serialization-dictionary-key="shadowOffset" />
|
||||||
|
<NSNumber serialization-native-value="0" serialization-dictionary-key="shadowBlurRadius" />
|
||||||
|
</_-D-_serializedShadow>
|
||||||
|
<stroke containerClass="NSMutableDictionary">
|
||||||
|
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="RVShapeElementStrokeColorKey" />
|
||||||
|
<NSNumber serialization-native-value="0" serialization-dictionary-key="RVShapeElementStrokeWidthKey" />
|
||||||
|
</stroke>
|
||||||
|
</RVTextElement>
|
||||||
|
</displayElements>
|
||||||
|
<_-RVProTransitionObject-_transitionObject transitionType="-1" transitionDuration="1" motionEnabled="0" motionSpeed="0" />
|
||||||
|
</RVDisplaySlide>
|
||||||
|
<RVDisplaySlide backgroundColor="0 0 0 0" enabled="1" highlightColor="0 0 0 0" hotKey="" label="" notes="" slideType="1" sort_index="7" UUID="0CDDEA18-F48E-4B85-8054-01140192EDC7" drawingBackgroundColor="0" chordChartPath="" serialization-array-index="7">
|
||||||
|
<cues containerClass="NSMutableArray" />
|
||||||
|
<displayElements containerClass="NSMutableArray">
|
||||||
|
<RVTextElement displayDelay="0" locked="0" persistent="0" typeID="0" fromTemplate="0" bezelRadius="0" drawingFill="0" drawingShadow="1" drawingStroke="0" fillColor="0 0 0 0" rotation="0" source="" displayName="" adjustsHeightToFit="0" verticalAlignment="0" RTFData="e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBUaGUgaG91ciBJIGZpcnN0IGJlbGlldmVkLn1cbGkwXHNhMFxzYjBcZmkwXHFjXHBhcn0NCn0NCn0=" revealType="0" serialization-array-index="0">
|
||||||
|
<_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" />
|
||||||
|
<_-D-_serializedShadow containerClass="NSMutableDictionary">
|
||||||
|
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="shadowColor" />
|
||||||
|
<NSMutableString serialization-native-value="{0, 0}" serialization-dictionary-key="shadowOffset" />
|
||||||
|
<NSNumber serialization-native-value="0" serialization-dictionary-key="shadowBlurRadius" />
|
||||||
|
</_-D-_serializedShadow>
|
||||||
|
<stroke containerClass="NSMutableDictionary">
|
||||||
|
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="RVShapeElementStrokeColorKey" />
|
||||||
|
<NSNumber serialization-native-value="0" serialization-dictionary-key="RVShapeElementStrokeWidthKey" />
|
||||||
|
</stroke>
|
||||||
|
</RVTextElement>
|
||||||
|
</displayElements>
|
||||||
|
<_-RVProTransitionObject-_transitionObject transitionType="-1" transitionDuration="1" motionEnabled="0" motionSpeed="0" />
|
||||||
|
</RVDisplaySlide>
|
||||||
|
<RVDisplaySlide backgroundColor="0 0 0 0" enabled="1" highlightColor="0 0 0 0" hotKey="" label="" notes="" slideType="1" sort_index="8" UUID="E1193588-A9B8-4371-8DC0-F16DC6D3B489" drawingBackgroundColor="0" chordChartPath="" serialization-array-index="8">
|
||||||
|
<cues containerClass="NSMutableArray" />
|
||||||
|
<displayElements containerClass="NSMutableArray">
|
||||||
|
<RVTextElement displayDelay="0" locked="0" persistent="0" typeID="0" fromTemplate="0" bezelRadius="0" drawingFill="0" drawingShadow="1" drawingStroke="0" fillColor="0 0 0 0" rotation="0" source="" displayName="" adjustsHeightToFit="0" verticalAlignment="0" RTFData="e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBUaHJvdWdoIG1hbnkgZGFuZ2VycywgdG9pbHMgYW5kIHNuYXJlcyx9XGxpMFxzYTBcc2IwXGZpMFxxY1xwYXJ9DQp9DQp9" revealType="0" serialization-array-index="0">
|
||||||
|
<_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" />
|
||||||
|
<_-D-_serializedShadow containerClass="NSMutableDictionary">
|
||||||
|
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="shadowColor" />
|
||||||
|
<NSMutableString serialization-native-value="{0, 0}" serialization-dictionary-key="shadowOffset" />
|
||||||
|
<NSNumber serialization-native-value="0" serialization-dictionary-key="shadowBlurRadius" />
|
||||||
|
</_-D-_serializedShadow>
|
||||||
|
<stroke containerClass="NSMutableDictionary">
|
||||||
|
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="RVShapeElementStrokeColorKey" />
|
||||||
|
<NSNumber serialization-native-value="0" serialization-dictionary-key="RVShapeElementStrokeWidthKey" />
|
||||||
|
</stroke>
|
||||||
|
</RVTextElement>
|
||||||
|
</displayElements>
|
||||||
|
<_-RVProTransitionObject-_transitionObject transitionType="-1" transitionDuration="1" motionEnabled="0" motionSpeed="0" />
|
||||||
|
</RVDisplaySlide>
|
||||||
|
<RVDisplaySlide backgroundColor="0 0 0 0" enabled="1" highlightColor="0 0 0 0" hotKey="" label="" notes="" slideType="1" sort_index="9" UUID="EBD1940D-7360-4E04-9E8F-E752B1F9ECBF" drawingBackgroundColor="0" chordChartPath="" serialization-array-index="9">
|
||||||
|
<cues containerClass="NSMutableArray" />
|
||||||
|
<displayElements containerClass="NSMutableArray">
|
||||||
|
<RVTextElement displayDelay="0" locked="0" persistent="0" typeID="0" fromTemplate="0" bezelRadius="0" drawingFill="0" drawingShadow="1" drawingStroke="0" fillColor="0 0 0 0" rotation="0" source="" displayName="" adjustsHeightToFit="0" verticalAlignment="0" RTFData="e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBJIGhhdmUgYWxyZWFkeSBjb21lO31cbGkwXHNhMFxzYjBcZmkwXHFjXHBhcn0NCn0NCn0=" revealType="0" serialization-array-index="0">
|
||||||
|
<_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" />
|
||||||
|
<_-D-_serializedShadow containerClass="NSMutableDictionary">
|
||||||
|
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="shadowColor" />
|
||||||
|
<NSMutableString serialization-native-value="{0, 0}" serialization-dictionary-key="shadowOffset" />
|
||||||
|
<NSNumber serialization-native-value="0" serialization-dictionary-key="shadowBlurRadius" />
|
||||||
|
</_-D-_serializedShadow>
|
||||||
|
<stroke containerClass="NSMutableDictionary">
|
||||||
|
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="RVShapeElementStrokeColorKey" />
|
||||||
|
<NSNumber serialization-native-value="0" serialization-dictionary-key="RVShapeElementStrokeWidthKey" />
|
||||||
|
</stroke>
|
||||||
|
</RVTextElement>
|
||||||
|
</displayElements>
|
||||||
|
<_-RVProTransitionObject-_transitionObject transitionType="-1" transitionDuration="1" motionEnabled="0" motionSpeed="0" />
|
||||||
|
</RVDisplaySlide>
|
||||||
|
<RVDisplaySlide backgroundColor="0 0 0 0" enabled="1" highlightColor="0 0 0 0" hotKey="" label="" notes="" slideType="1" sort_index="10" UUID="76F80153-DF39-4CE8-B186-79D548C596F5" drawingBackgroundColor="0" chordChartPath="" serialization-array-index="10">
|
||||||
|
<cues containerClass="NSMutableArray" />
|
||||||
|
<displayElements containerClass="NSMutableArray">
|
||||||
|
<RVTextElement displayDelay="0" locked="0" persistent="0" typeID="0" fromTemplate="0" bezelRadius="0" drawingFill="0" drawingShadow="1" drawingStroke="0" fillColor="0 0 0 0" rotation="0" source="" displayName="" adjustsHeightToFit="0" verticalAlignment="0" RTFData="e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCAnVGlzIGdyYWNlIGhhdGggYnJvdWdodCBtZSBzYWZlIHRodXMgZmFyLH1cbGkwXHNhMFxzYjBcZmkwXHFjXHBhcn0NCn0NCn0=" revealType="0" serialization-array-index="0">
|
||||||
|
<_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" />
|
||||||
|
<_-D-_serializedShadow containerClass="NSMutableDictionary">
|
||||||
|
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="shadowColor" />
|
||||||
|
<NSMutableString serialization-native-value="{0, 0}" serialization-dictionary-key="shadowOffset" />
|
||||||
|
<NSNumber serialization-native-value="0" serialization-dictionary-key="shadowBlurRadius" />
|
||||||
|
</_-D-_serializedShadow>
|
||||||
|
<stroke containerClass="NSMutableDictionary">
|
||||||
|
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="RVShapeElementStrokeColorKey" />
|
||||||
|
<NSNumber serialization-native-value="0" serialization-dictionary-key="RVShapeElementStrokeWidthKey" />
|
||||||
|
</stroke>
|
||||||
|
</RVTextElement>
|
||||||
|
</displayElements>
|
||||||
|
<_-RVProTransitionObject-_transitionObject transitionType="-1" transitionDuration="1" motionEnabled="0" motionSpeed="0" />
|
||||||
|
</RVDisplaySlide>
|
||||||
|
<RVDisplaySlide backgroundColor="0 0 0 0" enabled="1" highlightColor="0 0 0 0" hotKey="" label="" notes="" slideType="1" sort_index="11" UUID="D4E43B14-8E57-44AA-BCD3-0B1F1401A829" drawingBackgroundColor="0" chordChartPath="" serialization-array-index="11">
|
||||||
|
<cues containerClass="NSMutableArray" />
|
||||||
|
<displayElements containerClass="NSMutableArray">
|
||||||
|
<RVTextElement displayDelay="0" locked="0" persistent="0" typeID="0" fromTemplate="0" bezelRadius="0" drawingFill="0" drawingShadow="1" drawingStroke="0" fillColor="0 0 0 0" rotation="0" source="" displayName="" adjustsHeightToFit="0" verticalAlignment="0" RTFData="e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBBbmQgZ3JhY2Ugd2lsbCBsZWFkIG1lIGhvbWUufVxsaTBcc2EwXHNiMFxmaTBccWNccGFyfQ0KfQ0KfQ==" revealType="0" serialization-array-index="0">
|
||||||
|
<_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" />
|
||||||
|
<_-D-_serializedShadow containerClass="NSMutableDictionary">
|
||||||
|
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="shadowColor" />
|
||||||
|
<NSMutableString serialization-native-value="{0, 0}" serialization-dictionary-key="shadowOffset" />
|
||||||
|
<NSNumber serialization-native-value="0" serialization-dictionary-key="shadowBlurRadius" />
|
||||||
|
</_-D-_serializedShadow>
|
||||||
|
<stroke containerClass="NSMutableDictionary">
|
||||||
|
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="RVShapeElementStrokeColorKey" />
|
||||||
|
<NSNumber serialization-native-value="0" serialization-dictionary-key="RVShapeElementStrokeWidthKey" />
|
||||||
|
</stroke>
|
||||||
|
</RVTextElement>
|
||||||
|
</displayElements>
|
||||||
|
<_-RVProTransitionObject-_transitionObject transitionType="-1" transitionDuration="1" motionEnabled="0" motionSpeed="0" />
|
||||||
|
</RVDisplaySlide>
|
||||||
|
<RVDisplaySlide backgroundColor="0 0 0 0" enabled="1" highlightColor="0 0 0 0" hotKey="" label="" notes="" slideType="1" sort_index="12" UUID="D5B3DFC2-6C99-447B-A1E9-815F1550397F" drawingBackgroundColor="0" chordChartPath="" serialization-array-index="12">
|
||||||
|
<cues containerClass="NSMutableArray" />
|
||||||
|
<displayElements containerClass="NSMutableArray">
|
||||||
|
<RVTextElement displayDelay="0" locked="0" persistent="0" typeID="0" fromTemplate="0" bezelRadius="0" drawingFill="0" drawingShadow="1" drawingStroke="0" fillColor="0 0 0 0" rotation="0" source="" displayName="" adjustsHeightToFit="0" verticalAlignment="0" RTFData="e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBUaGUgTG9yZCBoYXMgcHJvbWlzZWQgZ29vZCB0byBtZSx9XGxpMFxzYTBcc2IwXGZpMFxxY1xwYXJ9DQp9DQp9" revealType="0" serialization-array-index="0">
|
||||||
|
<_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" />
|
||||||
|
<_-D-_serializedShadow containerClass="NSMutableDictionary">
|
||||||
|
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="shadowColor" />
|
||||||
|
<NSMutableString serialization-native-value="{0, 0}" serialization-dictionary-key="shadowOffset" />
|
||||||
|
<NSNumber serialization-native-value="0" serialization-dictionary-key="shadowBlurRadius" />
|
||||||
|
</_-D-_serializedShadow>
|
||||||
|
<stroke containerClass="NSMutableDictionary">
|
||||||
|
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="RVShapeElementStrokeColorKey" />
|
||||||
|
<NSNumber serialization-native-value="0" serialization-dictionary-key="RVShapeElementStrokeWidthKey" />
|
||||||
|
</stroke>
|
||||||
|
</RVTextElement>
|
||||||
|
</displayElements>
|
||||||
|
<_-RVProTransitionObject-_transitionObject transitionType="-1" transitionDuration="1" motionEnabled="0" motionSpeed="0" />
|
||||||
|
</RVDisplaySlide>
|
||||||
|
<RVDisplaySlide backgroundColor="0 0 0 0" enabled="1" highlightColor="0 0 0 0" hotKey="" label="" notes="" slideType="1" sort_index="13" UUID="E1573057-DB07-4442-BDCD-1C44B5B62A60" drawingBackgroundColor="0" chordChartPath="" serialization-array-index="13">
|
||||||
|
<cues containerClass="NSMutableArray" />
|
||||||
|
<displayElements containerClass="NSMutableArray">
|
||||||
|
<RVTextElement displayDelay="0" locked="0" persistent="0" typeID="0" fromTemplate="0" bezelRadius="0" drawingFill="0" drawingShadow="1" drawingStroke="0" fillColor="0 0 0 0" rotation="0" source="" displayName="" adjustsHeightToFit="0" verticalAlignment="0" RTFData="e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBIaXMgV29yZCBteSBob3BlIHNlY3VyZXM7fVxsaTBcc2EwXHNiMFxmaTBccWNccGFyfQ0KfQ0KfQ==" revealType="0" serialization-array-index="0">
|
||||||
|
<_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" />
|
||||||
|
<_-D-_serializedShadow containerClass="NSMutableDictionary">
|
||||||
|
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="shadowColor" />
|
||||||
|
<NSMutableString serialization-native-value="{0, 0}" serialization-dictionary-key="shadowOffset" />
|
||||||
|
<NSNumber serialization-native-value="0" serialization-dictionary-key="shadowBlurRadius" />
|
||||||
|
</_-D-_serializedShadow>
|
||||||
|
<stroke containerClass="NSMutableDictionary">
|
||||||
|
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="RVShapeElementStrokeColorKey" />
|
||||||
|
<NSNumber serialization-native-value="0" serialization-dictionary-key="RVShapeElementStrokeWidthKey" />
|
||||||
|
</stroke>
|
||||||
|
</RVTextElement>
|
||||||
|
</displayElements>
|
||||||
|
<_-RVProTransitionObject-_transitionObject transitionType="-1" transitionDuration="1" motionEnabled="0" motionSpeed="0" />
|
||||||
|
</RVDisplaySlide>
|
||||||
|
<RVDisplaySlide backgroundColor="0 0 0 0" enabled="1" highlightColor="0 0 0 0" hotKey="" label="" notes="" slideType="1" sort_index="14" UUID="D07DB5AA-710D-40F5-8FF0-C336B7C99B29" drawingBackgroundColor="0" chordChartPath="" serialization-array-index="14">
|
||||||
|
<cues containerClass="NSMutableArray" />
|
||||||
|
<displayElements containerClass="NSMutableArray">
|
||||||
|
<RVTextElement displayDelay="0" locked="0" persistent="0" typeID="0" fromTemplate="0" bezelRadius="0" drawingFill="0" drawingShadow="1" drawingStroke="0" fillColor="0 0 0 0" rotation="0" source="" displayName="" adjustsHeightToFit="0" verticalAlignment="0" RTFData="e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBIZSB3aWxsIG15IFNoaWVsZCBhbmQgUG9ydGlvbiBiZSx9XGxpMFxzYTBcc2IwXGZpMFxxY1xwYXJ9DQp9DQp9" revealType="0" serialization-array-index="0">
|
||||||
|
<_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" />
|
||||||
|
<_-D-_serializedShadow containerClass="NSMutableDictionary">
|
||||||
|
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="shadowColor" />
|
||||||
|
<NSMutableString serialization-native-value="{0, 0}" serialization-dictionary-key="shadowOffset" />
|
||||||
|
<NSNumber serialization-native-value="0" serialization-dictionary-key="shadowBlurRadius" />
|
||||||
|
</_-D-_serializedShadow>
|
||||||
|
<stroke containerClass="NSMutableDictionary">
|
||||||
|
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="RVShapeElementStrokeColorKey" />
|
||||||
|
<NSNumber serialization-native-value="0" serialization-dictionary-key="RVShapeElementStrokeWidthKey" />
|
||||||
|
</stroke>
|
||||||
|
</RVTextElement>
|
||||||
|
</displayElements>
|
||||||
|
<_-RVProTransitionObject-_transitionObject transitionType="-1" transitionDuration="1" motionEnabled="0" motionSpeed="0" />
|
||||||
|
</RVDisplaySlide>
|
||||||
|
<RVDisplaySlide backgroundColor="0 0 0 0" enabled="1" highlightColor="0 0 0 0" hotKey="" label="" notes="" slideType="1" sort_index="15" UUID="0D91E879-8C6A-4C68-A098-80E95E89F4F7" drawingBackgroundColor="0" chordChartPath="" serialization-array-index="15">
|
||||||
|
<cues containerClass="NSMutableArray" />
|
||||||
|
<displayElements containerClass="NSMutableArray">
|
||||||
|
<RVTextElement displayDelay="0" locked="0" persistent="0" typeID="0" fromTemplate="0" bezelRadius="0" drawingFill="0" drawingShadow="1" drawingStroke="0" fillColor="0 0 0 0" rotation="0" source="" displayName="" adjustsHeightToFit="0" verticalAlignment="0" RTFData="e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBBcyBsb25nIGFzIGxpZmUgZW5kdXJlcy59XGxpMFxzYTBcc2IwXGZpMFxxY1xwYXJ9DQp9DQp9" revealType="0" serialization-array-index="0">
|
||||||
|
<_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" />
|
||||||
|
<_-D-_serializedShadow containerClass="NSMutableDictionary">
|
||||||
|
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="shadowColor" />
|
||||||
|
<NSMutableString serialization-native-value="{0, 0}" serialization-dictionary-key="shadowOffset" />
|
||||||
|
<NSNumber serialization-native-value="0" serialization-dictionary-key="shadowBlurRadius" />
|
||||||
|
</_-D-_serializedShadow>
|
||||||
|
<stroke containerClass="NSMutableDictionary">
|
||||||
|
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="RVShapeElementStrokeColorKey" />
|
||||||
|
<NSNumber serialization-native-value="0" serialization-dictionary-key="RVShapeElementStrokeWidthKey" />
|
||||||
|
</stroke>
|
||||||
|
</RVTextElement>
|
||||||
|
</displayElements>
|
||||||
|
<_-RVProTransitionObject-_transitionObject transitionType="-1" transitionDuration="1" motionEnabled="0" motionSpeed="0" />
|
||||||
|
</RVDisplaySlide>
|
||||||
|
<RVDisplaySlide backgroundColor="0 0 0 0" enabled="1" highlightColor="0 0 0 0" hotKey="" label="" notes="" slideType="1" sort_index="16" UUID="5105264F-D786-453E-8D29-3ADC8D84C53F" drawingBackgroundColor="0" chordChartPath="" serialization-array-index="16">
|
||||||
|
<cues containerClass="NSMutableArray" />
|
||||||
|
<displayElements containerClass="NSMutableArray">
|
||||||
|
<RVTextElement displayDelay="0" locked="0" persistent="0" typeID="0" fromTemplate="0" bezelRadius="0" drawingFill="0" drawingShadow="1" drawingStroke="0" fillColor="0 0 0 0" rotation="0" source="" displayName="" adjustsHeightToFit="0" verticalAlignment="0" RTFData="e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBZZWEsIHdoZW4gdGhpcyBmbGVzaCBhbmQgaGVhcnQgc2hhbGwgZmFpbCx9XGxpMFxzYTBcc2IwXGZpMFxxY1xwYXJ9DQp9DQp9" revealType="0" serialization-array-index="0">
|
||||||
|
<_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" />
|
||||||
|
<_-D-_serializedShadow containerClass="NSMutableDictionary">
|
||||||
|
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="shadowColor" />
|
||||||
|
<NSMutableString serialization-native-value="{0, 0}" serialization-dictionary-key="shadowOffset" />
|
||||||
|
<NSNumber serialization-native-value="0" serialization-dictionary-key="shadowBlurRadius" />
|
||||||
|
</_-D-_serializedShadow>
|
||||||
|
<stroke containerClass="NSMutableDictionary">
|
||||||
|
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="RVShapeElementStrokeColorKey" />
|
||||||
|
<NSNumber serialization-native-value="0" serialization-dictionary-key="RVShapeElementStrokeWidthKey" />
|
||||||
|
</stroke>
|
||||||
|
</RVTextElement>
|
||||||
|
</displayElements>
|
||||||
|
<_-RVProTransitionObject-_transitionObject transitionType="-1" transitionDuration="1" motionEnabled="0" motionSpeed="0" />
|
||||||
|
</RVDisplaySlide>
|
||||||
|
<RVDisplaySlide backgroundColor="0 0 0 0" enabled="1" highlightColor="0 0 0 0" hotKey="" label="" notes="" slideType="1" sort_index="17" UUID="46D46358-A465-425E-866D-1D5E215952E4" drawingBackgroundColor="0" chordChartPath="" serialization-array-index="17">
|
||||||
|
<cues containerClass="NSMutableArray" />
|
||||||
|
<displayElements containerClass="NSMutableArray">
|
||||||
|
<RVTextElement displayDelay="0" locked="0" persistent="0" typeID="0" fromTemplate="0" bezelRadius="0" drawingFill="0" drawingShadow="1" drawingStroke="0" fillColor="0 0 0 0" rotation="0" source="" displayName="" adjustsHeightToFit="0" verticalAlignment="0" RTFData="e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBBbmQgbW9ydGFsIGxpZmUgc2hhbGwgY2Vhc2UsfVxsaTBcc2EwXHNiMFxmaTBccWNccGFyfQ0KfQ0KfQ==" revealType="0" serialization-array-index="0">
|
||||||
|
<_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" />
|
||||||
|
<_-D-_serializedShadow containerClass="NSMutableDictionary">
|
||||||
|
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="shadowColor" />
|
||||||
|
<NSMutableString serialization-native-value="{0, 0}" serialization-dictionary-key="shadowOffset" />
|
||||||
|
<NSNumber serialization-native-value="0" serialization-dictionary-key="shadowBlurRadius" />
|
||||||
|
</_-D-_serializedShadow>
|
||||||
|
<stroke containerClass="NSMutableDictionary">
|
||||||
|
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="RVShapeElementStrokeColorKey" />
|
||||||
|
<NSNumber serialization-native-value="0" serialization-dictionary-key="RVShapeElementStrokeWidthKey" />
|
||||||
|
</stroke>
|
||||||
|
</RVTextElement>
|
||||||
|
</displayElements>
|
||||||
|
<_-RVProTransitionObject-_transitionObject transitionType="-1" transitionDuration="1" motionEnabled="0" motionSpeed="0" />
|
||||||
|
</RVDisplaySlide>
|
||||||
|
<RVDisplaySlide backgroundColor="0 0 0 0" enabled="1" highlightColor="0 0 0 0" hotKey="" label="" notes="" slideType="1" sort_index="18" UUID="8B92AC4F-1470-416E-80CA-E088EF6F3AC4" drawingBackgroundColor="0" chordChartPath="" serialization-array-index="18">
|
||||||
|
<cues containerClass="NSMutableArray" />
|
||||||
|
<displayElements containerClass="NSMutableArray">
|
||||||
|
<RVTextElement displayDelay="0" locked="0" persistent="0" typeID="0" fromTemplate="0" bezelRadius="0" drawingFill="0" drawingShadow="1" drawingStroke="0" fillColor="0 0 0 0" rotation="0" source="" displayName="" adjustsHeightToFit="0" verticalAlignment="0" RTFData="e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBJIHNoYWxsIHBvc3Nlc3MsIHdpdGhpbiB0aGUgdmVpbCx9XGxpMFxzYTBcc2IwXGZpMFxxY1xwYXJ9DQp9DQp9" revealType="0" serialization-array-index="0">
|
||||||
|
<_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" />
|
||||||
|
<_-D-_serializedShadow containerClass="NSMutableDictionary">
|
||||||
|
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="shadowColor" />
|
||||||
|
<NSMutableString serialization-native-value="{0, 0}" serialization-dictionary-key="shadowOffset" />
|
||||||
|
<NSNumber serialization-native-value="0" serialization-dictionary-key="shadowBlurRadius" />
|
||||||
|
</_-D-_serializedShadow>
|
||||||
|
<stroke containerClass="NSMutableDictionary">
|
||||||
|
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="RVShapeElementStrokeColorKey" />
|
||||||
|
<NSNumber serialization-native-value="0" serialization-dictionary-key="RVShapeElementStrokeWidthKey" />
|
||||||
|
</stroke>
|
||||||
|
</RVTextElement>
|
||||||
|
</displayElements>
|
||||||
|
<_-RVProTransitionObject-_transitionObject transitionType="-1" transitionDuration="1" motionEnabled="0" motionSpeed="0" />
|
||||||
|
</RVDisplaySlide>
|
||||||
|
<RVDisplaySlide backgroundColor="0 0 0 0" enabled="1" highlightColor="0 0 0 0" hotKey="" label="" notes="" slideType="1" sort_index="19" UUID="D0865E31-B064-4817-B027-A35C231D4946" drawingBackgroundColor="0" chordChartPath="" serialization-array-index="19">
|
||||||
|
<cues containerClass="NSMutableArray" />
|
||||||
|
<displayElements containerClass="NSMutableArray">
|
||||||
|
<RVTextElement displayDelay="0" locked="0" persistent="0" typeID="0" fromTemplate="0" bezelRadius="0" drawingFill="0" drawingShadow="1" drawingStroke="0" fillColor="0 0 0 0" rotation="0" source="" displayName="" adjustsHeightToFit="0" verticalAlignment="0" RTFData="e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBBIGxpZmUgb2Ygam95IGFuZCBwZWFjZS59XGxpMFxzYTBcc2IwXGZpMFxxY1xwYXJ9DQp9DQp9" revealType="0" serialization-array-index="0">
|
||||||
|
<_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" />
|
||||||
|
<_-D-_serializedShadow containerClass="NSMutableDictionary">
|
||||||
|
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="shadowColor" />
|
||||||
|
<NSMutableString serialization-native-value="{0, 0}" serialization-dictionary-key="shadowOffset" />
|
||||||
|
<NSNumber serialization-native-value="0" serialization-dictionary-key="shadowBlurRadius" />
|
||||||
|
</_-D-_serializedShadow>
|
||||||
|
<stroke containerClass="NSMutableDictionary">
|
||||||
|
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="RVShapeElementStrokeColorKey" />
|
||||||
|
<NSNumber serialization-native-value="0" serialization-dictionary-key="RVShapeElementStrokeWidthKey" />
|
||||||
|
</stroke>
|
||||||
|
</RVTextElement>
|
||||||
|
</displayElements>
|
||||||
|
<_-RVProTransitionObject-_transitionObject transitionType="-1" transitionDuration="1" motionEnabled="0" motionSpeed="0" />
|
||||||
|
</RVDisplaySlide>
|
||||||
|
<RVDisplaySlide backgroundColor="0 0 0 0" enabled="1" highlightColor="0 0 0 0" hotKey="" label="" notes="" slideType="1" sort_index="20" UUID="28AC1D6E-1F79-4E88-80A4-CA318A634046" drawingBackgroundColor="0" chordChartPath="" serialization-array-index="20">
|
||||||
|
<cues containerClass="NSMutableArray" />
|
||||||
|
<displayElements containerClass="NSMutableArray">
|
||||||
|
<RVTextElement displayDelay="0" locked="0" persistent="0" typeID="0" fromTemplate="0" bezelRadius="0" drawingFill="0" drawingShadow="1" drawingStroke="0" fillColor="0 0 0 0" rotation="0" source="" displayName="" adjustsHeightToFit="0" verticalAlignment="0" RTFData="e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBUaGUgZWFydGggc2hhbGwgc29vbiBkaXNzb2x2ZSBsaWtlIHNub3csfVxsaTBcc2EwXHNiMFxmaTBccWNccGFyfQ0KfQ0KfQ==" revealType="0" serialization-array-index="0">
|
||||||
|
<_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" />
|
||||||
|
<_-D-_serializedShadow containerClass="NSMutableDictionary">
|
||||||
|
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="shadowColor" />
|
||||||
|
<NSMutableString serialization-native-value="{0, 0}" serialization-dictionary-key="shadowOffset" />
|
||||||
|
<NSNumber serialization-native-value="0" serialization-dictionary-key="shadowBlurRadius" />
|
||||||
|
</_-D-_serializedShadow>
|
||||||
|
<stroke containerClass="NSMutableDictionary">
|
||||||
|
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="RVShapeElementStrokeColorKey" />
|
||||||
|
<NSNumber serialization-native-value="0" serialization-dictionary-key="RVShapeElementStrokeWidthKey" />
|
||||||
|
</stroke>
|
||||||
|
</RVTextElement>
|
||||||
|
</displayElements>
|
||||||
|
<_-RVProTransitionObject-_transitionObject transitionType="-1" transitionDuration="1" motionEnabled="0" motionSpeed="0" />
|
||||||
|
</RVDisplaySlide>
|
||||||
|
<RVDisplaySlide backgroundColor="0 0 0 0" enabled="1" highlightColor="0 0 0 0" hotKey="" label="" notes="" slideType="1" sort_index="21" UUID="3E97F36D-D9CE-4C2B-AE1A-D337A43FD7F5" drawingBackgroundColor="0" chordChartPath="" serialization-array-index="21">
|
||||||
|
<cues containerClass="NSMutableArray" />
|
||||||
|
<displayElements containerClass="NSMutableArray">
|
||||||
|
<RVTextElement displayDelay="0" locked="0" persistent="0" typeID="0" fromTemplate="0" bezelRadius="0" drawingFill="0" drawingShadow="1" drawingStroke="0" fillColor="0 0 0 0" rotation="0" source="" displayName="" adjustsHeightToFit="0" verticalAlignment="0" RTFData="e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBUaGUgc3VuIGZvcmJlYXIgdG8gc2hpbmU7fVxsaTBcc2EwXHNiMFxmaTBccWNccGFyfQ0KfQ0KfQ==" revealType="0" serialization-array-index="0">
|
||||||
|
<_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" />
|
||||||
|
<_-D-_serializedShadow containerClass="NSMutableDictionary">
|
||||||
|
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="shadowColor" />
|
||||||
|
<NSMutableString serialization-native-value="{0, 0}" serialization-dictionary-key="shadowOffset" />
|
||||||
|
<NSNumber serialization-native-value="0" serialization-dictionary-key="shadowBlurRadius" />
|
||||||
|
</_-D-_serializedShadow>
|
||||||
|
<stroke containerClass="NSMutableDictionary">
|
||||||
|
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="RVShapeElementStrokeColorKey" />
|
||||||
|
<NSNumber serialization-native-value="0" serialization-dictionary-key="RVShapeElementStrokeWidthKey" />
|
||||||
|
</stroke>
|
||||||
|
</RVTextElement>
|
||||||
|
</displayElements>
|
||||||
|
<_-RVProTransitionObject-_transitionObject transitionType="-1" transitionDuration="1" motionEnabled="0" motionSpeed="0" />
|
||||||
|
</RVDisplaySlide>
|
||||||
|
<RVDisplaySlide backgroundColor="0 0 0 0" enabled="1" highlightColor="0 0 0 0" hotKey="" label="" notes="" slideType="1" sort_index="22" UUID="81E336F4-7170-47B0-B829-4E4A945A755F" drawingBackgroundColor="0" chordChartPath="" serialization-array-index="22">
|
||||||
|
<cues containerClass="NSMutableArray" />
|
||||||
|
<displayElements containerClass="NSMutableArray">
|
||||||
|
<RVTextElement displayDelay="0" locked="0" persistent="0" typeID="0" fromTemplate="0" bezelRadius="0" drawingFill="0" drawingShadow="1" drawingStroke="0" fillColor="0 0 0 0" rotation="0" source="" displayName="" adjustsHeightToFit="0" verticalAlignment="0" RTFData="e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBCdXQgR29kLCBXaG8gY2FsbGVkIG1lIGhlcmUgYmVsb3csfVxsaTBcc2EwXHNiMFxmaTBccWNccGFyfQ0KfQ0KfQ==" revealType="0" serialization-array-index="0">
|
||||||
|
<_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" />
|
||||||
|
<_-D-_serializedShadow containerClass="NSMutableDictionary">
|
||||||
|
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="shadowColor" />
|
||||||
|
<NSMutableString serialization-native-value="{0, 0}" serialization-dictionary-key="shadowOffset" />
|
||||||
|
<NSNumber serialization-native-value="0" serialization-dictionary-key="shadowBlurRadius" />
|
||||||
|
</_-D-_serializedShadow>
|
||||||
|
<stroke containerClass="NSMutableDictionary">
|
||||||
|
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="RVShapeElementStrokeColorKey" />
|
||||||
|
<NSNumber serialization-native-value="0" serialization-dictionary-key="RVShapeElementStrokeWidthKey" />
|
||||||
|
</stroke>
|
||||||
|
</RVTextElement>
|
||||||
|
</displayElements>
|
||||||
|
<_-RVProTransitionObject-_transitionObject transitionType="-1" transitionDuration="1" motionEnabled="0" motionSpeed="0" />
|
||||||
|
</RVDisplaySlide>
|
||||||
|
<RVDisplaySlide backgroundColor="0 0 0 0" enabled="1" highlightColor="0 0 0 0" hotKey="" label="" notes="" slideType="1" sort_index="23" UUID="4D669087-EB91-4972-A1F7-D866F339C502" drawingBackgroundColor="0" chordChartPath="" serialization-array-index="23">
|
||||||
|
<cues containerClass="NSMutableArray" />
|
||||||
|
<displayElements containerClass="NSMutableArray">
|
||||||
|
<RVTextElement displayDelay="0" locked="0" persistent="0" typeID="0" fromTemplate="0" bezelRadius="0" drawingFill="0" drawingShadow="1" drawingStroke="0" fillColor="0 0 0 0" rotation="0" source="" displayName="" adjustsHeightToFit="0" verticalAlignment="0" RTFData="e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBTaGFsbCBiZSBmb3JldmVyIG1pbmUufVxsaTBcc2EwXHNiMFxmaTBccWNccGFyfQ0KfQ0KfQ==" revealType="0" serialization-array-index="0">
|
||||||
|
<_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" />
|
||||||
|
<_-D-_serializedShadow containerClass="NSMutableDictionary">
|
||||||
|
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="shadowColor" />
|
||||||
|
<NSMutableString serialization-native-value="{0, 0}" serialization-dictionary-key="shadowOffset" />
|
||||||
|
<NSNumber serialization-native-value="0" serialization-dictionary-key="shadowBlurRadius" />
|
||||||
|
</_-D-_serializedShadow>
|
||||||
|
<stroke containerClass="NSMutableDictionary">
|
||||||
|
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="RVShapeElementStrokeColorKey" />
|
||||||
|
<NSNumber serialization-native-value="0" serialization-dictionary-key="RVShapeElementStrokeWidthKey" />
|
||||||
|
</stroke>
|
||||||
|
</RVTextElement>
|
||||||
|
</displayElements>
|
||||||
|
<_-RVProTransitionObject-_transitionObject transitionType="-1" transitionDuration="1" motionEnabled="0" motionSpeed="0" />
|
||||||
|
</RVDisplaySlide>
|
||||||
|
<RVDisplaySlide backgroundColor="0 0 0 0" enabled="1" highlightColor="0 0 0 0" hotKey="" label="" notes="" slideType="1" sort_index="24" UUID="ADE5EE3D-56A6-4439-96DD-51C53337D4B1" drawingBackgroundColor="0" chordChartPath="" serialization-array-index="24">
|
||||||
|
<cues containerClass="NSMutableArray" />
|
||||||
|
<displayElements containerClass="NSMutableArray">
|
||||||
|
<RVTextElement displayDelay="0" locked="0" persistent="0" typeID="0" fromTemplate="0" bezelRadius="0" drawingFill="0" drawingShadow="1" drawingStroke="0" fillColor="0 0 0 0" rotation="0" source="" displayName="" adjustsHeightToFit="0" verticalAlignment="0" RTFData="e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBXaGVuIHdlJ3ZlIGJlZW4gdGhlcmUgdGVuIHRob3VzYW5kIHllYXJzLH1cbGkwXHNhMFxzYjBcZmkwXHFjXHBhcn0NCn0NCn0=" revealType="0" serialization-array-index="0">
|
||||||
|
<_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" />
|
||||||
|
<_-D-_serializedShadow containerClass="NSMutableDictionary">
|
||||||
|
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="shadowColor" />
|
||||||
|
<NSMutableString serialization-native-value="{0, 0}" serialization-dictionary-key="shadowOffset" />
|
||||||
|
<NSNumber serialization-native-value="0" serialization-dictionary-key="shadowBlurRadius" />
|
||||||
|
</_-D-_serializedShadow>
|
||||||
|
<stroke containerClass="NSMutableDictionary">
|
||||||
|
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="RVShapeElementStrokeColorKey" />
|
||||||
|
<NSNumber serialization-native-value="0" serialization-dictionary-key="RVShapeElementStrokeWidthKey" />
|
||||||
|
</stroke>
|
||||||
|
</RVTextElement>
|
||||||
|
</displayElements>
|
||||||
|
<_-RVProTransitionObject-_transitionObject transitionType="-1" transitionDuration="1" motionEnabled="0" motionSpeed="0" />
|
||||||
|
</RVDisplaySlide>
|
||||||
|
<RVDisplaySlide backgroundColor="0 0 0 0" enabled="1" highlightColor="0 0 0 0" hotKey="" label="" notes="" slideType="1" sort_index="25" UUID="BD68D875-5154-485A-AEF3-D48D9CE27C05" drawingBackgroundColor="0" chordChartPath="" serialization-array-index="25">
|
||||||
|
<cues containerClass="NSMutableArray" />
|
||||||
|
<displayElements containerClass="NSMutableArray">
|
||||||
|
<RVTextElement displayDelay="0" locked="0" persistent="0" typeID="0" fromTemplate="0" bezelRadius="0" drawingFill="0" drawingShadow="1" drawingStroke="0" fillColor="0 0 0 0" rotation="0" source="" displayName="" adjustsHeightToFit="0" verticalAlignment="0" RTFData="e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBCcmlnaHQgc2hpbmluZyBhcyB0aGUgc3VuLH1cbGkwXHNhMFxzYjBcZmkwXHFjXHBhcn0NCn0NCn0=" revealType="0" serialization-array-index="0">
|
||||||
|
<_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" />
|
||||||
|
<_-D-_serializedShadow containerClass="NSMutableDictionary">
|
||||||
|
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="shadowColor" />
|
||||||
|
<NSMutableString serialization-native-value="{0, 0}" serialization-dictionary-key="shadowOffset" />
|
||||||
|
<NSNumber serialization-native-value="0" serialization-dictionary-key="shadowBlurRadius" />
|
||||||
|
</_-D-_serializedShadow>
|
||||||
|
<stroke containerClass="NSMutableDictionary">
|
||||||
|
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="RVShapeElementStrokeColorKey" />
|
||||||
|
<NSNumber serialization-native-value="0" serialization-dictionary-key="RVShapeElementStrokeWidthKey" />
|
||||||
|
</stroke>
|
||||||
|
</RVTextElement>
|
||||||
|
</displayElements>
|
||||||
|
<_-RVProTransitionObject-_transitionObject transitionType="-1" transitionDuration="1" motionEnabled="0" motionSpeed="0" />
|
||||||
|
</RVDisplaySlide>
|
||||||
|
<RVDisplaySlide backgroundColor="0 0 0 0" enabled="1" highlightColor="0 0 0 0" hotKey="" label="" notes="" slideType="1" sort_index="26" UUID="030026EE-A25C-4781-883D-0CAC394ADC93" drawingBackgroundColor="0" chordChartPath="" serialization-array-index="26">
|
||||||
|
<cues containerClass="NSMutableArray" />
|
||||||
|
<displayElements containerClass="NSMutableArray">
|
||||||
|
<RVTextElement displayDelay="0" locked="0" persistent="0" typeID="0" fromTemplate="0" bezelRadius="0" drawingFill="0" drawingShadow="1" drawingStroke="0" fillColor="0 0 0 0" rotation="0" source="" displayName="" adjustsHeightToFit="0" verticalAlignment="0" RTFData="e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBXZSd2ZSBubyBsZXNzIGRheXMgdG8gc2luZyBHb2QncyBwcmFpc2V9XGxpMFxzYTBcc2IwXGZpMFxxY1xwYXJ9DQp9DQp9" revealType="0" serialization-array-index="0">
|
||||||
|
<_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" />
|
||||||
|
<_-D-_serializedShadow containerClass="NSMutableDictionary">
|
||||||
|
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="shadowColor" />
|
||||||
|
<NSMutableString serialization-native-value="{0, 0}" serialization-dictionary-key="shadowOffset" />
|
||||||
|
<NSNumber serialization-native-value="0" serialization-dictionary-key="shadowBlurRadius" />
|
||||||
|
</_-D-_serializedShadow>
|
||||||
|
<stroke containerClass="NSMutableDictionary">
|
||||||
|
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="RVShapeElementStrokeColorKey" />
|
||||||
|
<NSNumber serialization-native-value="0" serialization-dictionary-key="RVShapeElementStrokeWidthKey" />
|
||||||
|
</stroke>
|
||||||
|
</RVTextElement>
|
||||||
|
</displayElements>
|
||||||
|
<_-RVProTransitionObject-_transitionObject transitionType="-1" transitionDuration="1" motionEnabled="0" motionSpeed="0" />
|
||||||
|
</RVDisplaySlide>
|
||||||
|
<RVDisplaySlide backgroundColor="0 0 0 0" enabled="1" highlightColor="0 0 0 0" hotKey="" label="" notes="" slideType="1" sort_index="27" UUID="50648C63-C1FC-40E0-8928-FEDFFCDA9689" drawingBackgroundColor="0" chordChartPath="" serialization-array-index="27">
|
||||||
|
<cues containerClass="NSMutableArray" />
|
||||||
|
<displayElements containerClass="NSMutableArray">
|
||||||
|
<RVTextElement displayDelay="0" locked="0" persistent="0" typeID="0" fromTemplate="0" bezelRadius="0" drawingFill="0" drawingShadow="1" drawingStroke="0" fillColor="0 0 0 0" rotation="0" source="" displayName="" adjustsHeightToFit="0" verticalAlignment="0" RTFData="e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBUaGFuIHdoZW4gd2UnZCBmaXJzdCBiZWd1bi59XGxpMFxzYTBcc2IwXGZpMFxxY1xwYXJ9DQp9DQp9" revealType="0" serialization-array-index="0">
|
||||||
|
<_-RVRect3D-_position x="10" y="10" z="0" width="1004" height="748" />
|
||||||
|
<_-D-_serializedShadow containerClass="NSMutableDictionary">
|
||||||
|
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="shadowColor" />
|
||||||
|
<NSMutableString serialization-native-value="{0, 0}" serialization-dictionary-key="shadowOffset" />
|
||||||
|
<NSNumber serialization-native-value="0" serialization-dictionary-key="shadowBlurRadius" />
|
||||||
|
</_-D-_serializedShadow>
|
||||||
|
<stroke containerClass="NSMutableDictionary">
|
||||||
|
<NSCalibratedRGBColor serialization-native-value="0 0 0 0" serialization-dictionary-key="RVShapeElementStrokeColorKey" />
|
||||||
|
<NSNumber serialization-native-value="0" serialization-dictionary-key="RVShapeElementStrokeWidthKey" />
|
||||||
|
</stroke>
|
||||||
|
</RVTextElement>
|
||||||
|
</displayElements>
|
||||||
|
<_-RVProTransitionObject-_transitionObject transitionType="-1" transitionDuration="1" motionEnabled="0" motionSpeed="0" />
|
||||||
|
</RVDisplaySlide>
|
||||||
|
</slides>
|
||||||
|
</RVSlideGrouping>
|
||||||
|
</groups>
|
||||||
|
<arrangements containerClass="NSMutableArray" />
|
||||||
|
<timeline timeOffSet="0" selectedMediaTrackIndex="-1" unitOfMeasure="60" duration="0" loop="0">
|
||||||
|
<timeCues containerClass="NSMutableArray" />
|
||||||
|
<mediaTracks containerClass="NSMutableArray" />
|
||||||
|
</timeline>
|
||||||
|
<bibleReference containerClass="NSMutableDictionary" />
|
||||||
|
<_-RVProTransitionObject-_transitionObject transitionType="-1" transitionDuration="1" motionEnabled="0" motionSpeed="0" />
|
||||||
|
</RVPresentationDocument>
|
490
tests/resources/propresentersongs/Amazing Grace.pro6
Normal file
490
tests/resources/propresentersongs/Amazing Grace.pro6
Normal file
@ -0,0 +1,490 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<RVPresentationDocument height="768" width="1024" docType="0" versionNumber="600" usedCount="0" backgroundColor="0 0 0 1" drawingBackgroundColor="false" CCLIDisplay="false" lastDateUsed="2016-03-30T16:21:32+00:00" selectedArrangementID="" category="Hymn" resourcesDirectory="" notes="" CCLIAuthor="" CCLIArtistCredits="John Newton" CCLISongTitle="Amazing Grace" CCLIPublisher="" CCLICopyrightYear="" CCLISongNumber="" chordChartPath="" os="1" buildNumber="6016">
|
||||||
|
<RVTimeline timeOffset="0" duration="0" selectedMediaTrackIndex="-1" loop="false" rvXMLIvarName="timeline">
|
||||||
|
<array rvXMLIvarName="timeCues" />
|
||||||
|
<array rvXMLIvarName="mediaTracks" />
|
||||||
|
</RVTimeline>
|
||||||
|
<array rvXMLIvarName="groups">
|
||||||
|
<RVSlideGrouping name="" color="1 1 1 0" uuid="E2F65DE0-5E6D-4290-8C07-D01CAFA3D00C">
|
||||||
|
<array rvXMLIvarName="slides">
|
||||||
|
<RVDisplaySlide backgroundColor="0 0 0 0" highlightColor="1 1 1 0" drawingBackgroundColor="false" enabled="true" hotKey="" label="" notes="" UUID="A67250CF-0DCC-4169-80EA-7E417CC233B3" chordChartPath="">
|
||||||
|
<array rvXMLIvarName="cues" />
|
||||||
|
<array rvXMLIvarName="displayElements">
|
||||||
|
<RVTextElement displayName="" UUID="ff599ca5-0655-462c-9705-29fdaf7b6ed6" typeID="0" displayDelay="0" locked="false" persistent="0" fromTemplate="false" opacity="1" source="" bezelRadius="0" rotation="0" drawingFill="false" drawingShadow="true" drawingStroke="false" fillColor="0 0 0 0" adjustsHeightToFit="false" verticalAlignment="0" revealType="0">
|
||||||
|
<RVRect3D rvXMLIvarName="position">{10 10 0 1004 748}</RVRect3D>
|
||||||
|
<shadow rvXMLIvarName="shadow">0|0 0 0 0|{0, 0}</shadow>
|
||||||
|
<dictionary rvXMLIvarName="stroke">
|
||||||
|
<NSColor rvXMLDictionaryKey="RVShapeElementStrokeColorKey">0 0 0 0</NSColor>
|
||||||
|
<NSNumber rvXMLDictionaryKey="RVShapeElementStrokeWidthKey" hint="double">0</NSNumber>
|
||||||
|
</dictionary>
|
||||||
|
<NSString rvXMLIvarName="PlainText">QW1hemluZyBncmFjZSEgSG93IHN3ZWV0IHRoZSBzb3VuZA==</NSString>
|
||||||
|
<NSString rvXMLIvarName="RTFData">e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBBbWF6aW5nIGdyYWNlISBIb3cgc3dlZXQgdGhlIHNvdW5kfVxsaTBcc2EwXHNiMFxmaTBccWNccGFyfQ0KfQ0KfQ==</NSString>
|
||||||
|
<NSString rvXMLIvarName="WinFlowData">PEZsb3dEb2N1bWVudCBUZXh0QWxpZ25tZW50PSJMZWZ0IiB4bWxucz0iaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS93aW5meC8yMDA2L3hhbWwvcHJlc2VudGF0aW9uIj48UGFyYWdyYXBoIE1hcmdpbj0iMCwwLDAsMCIgVGV4dEFsaWdubWVudD0iQ2VudGVyIiBGb250RmFtaWx5PSJIZWx2ZXRpY2EiIEZvbnRTaXplPSI2MCI+PFNwYW4gRm9yZWdyb3VuZD0iI0ZGRkZGRkZGIiB4bWw6bGFuZz0iZW4tdXMiPjxSdW4gQmxvY2suVGV4dEFsaWdubWVudD0iQ2VudGVyIj5BbWF6aW5nIGdyYWNlISBIb3cgc3dlZXQgdGhlIHNvdW5kPC9SdW4+PC9TcGFuPjwvUGFyYWdyYXBoPjwvRmxvd0RvY3VtZW50Pg==</NSString>
|
||||||
|
<NSString rvXMLIvarName="WinFontData">PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTE2Ij8+PFJWRm9udCB4bWxuczppPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYS1pbnN0YW5jZSIgeG1sbnM9Imh0dHA6Ly9zY2hlbWFzLmRhdGFjb250cmFjdC5vcmcvMjAwNC8wNy9Qcm9QcmVzZW50ZXIuQ29tbW9uIj48S2VybmluZz4wPC9LZXJuaW5nPjxMaW5lU3BhY2luZz4wPC9MaW5lU3BhY2luZz48T3V0bGluZUNvbG9yIHhtbG5zOmQycDE9Imh0dHA6Ly9zY2hlbWFzLmRhdGFjb250cmFjdC5vcmcvMjAwNC8wNy9TeXN0ZW0uV2luZG93cy5NZWRpYSI+PGQycDE6QT4wPC9kMnAxOkE+PGQycDE6Qj4wPC9kMnAxOkI+PGQycDE6Rz4wPC9kMnAxOkc+PGQycDE6Uj4wPC9kMnAxOlI+PGQycDE6U2NBPjA8L2QycDE6U2NBPjxkMnAxOlNjQj4wPC9kMnAxOlNjQj48ZDJwMTpTY0c+MDwvZDJwMTpTY0c+PGQycDE6U2NSPjA8L2QycDE6U2NSPjwvT3V0bGluZUNvbG9yPjxPdXRsaW5lV2lkdGg+MDwvT3V0bGluZVdpZHRoPjxWYXJpYW50cz5Ob3JtYWw8L1ZhcmlhbnRzPjwvUlZGb250Pg==</NSString>
|
||||||
|
</RVTextElement>
|
||||||
|
</array>
|
||||||
|
</RVDisplaySlide>
|
||||||
|
<RVDisplaySlide backgroundColor="0 0 0 0" highlightColor="0 0 0 0" drawingBackgroundColor="false" enabled="true" hotKey="" label="" notes="" UUID="B09CAF20-B402-43C3-AA35-C09B1A2CEB25" chordChartPath="">
|
||||||
|
<array rvXMLIvarName="cues" />
|
||||||
|
<array rvXMLIvarName="displayElements">
|
||||||
|
<RVTextElement displayName="" UUID="01193fe0-4aea-44e8-94dd-ffb979d04d21" typeID="0" displayDelay="0" locked="false" persistent="0" fromTemplate="false" opacity="1" source="" bezelRadius="0" rotation="0" drawingFill="false" drawingShadow="true" drawingStroke="false" fillColor="0 0 0 0" adjustsHeightToFit="false" verticalAlignment="0" revealType="0">
|
||||||
|
<RVRect3D rvXMLIvarName="position">{10 10 0 1004 748}</RVRect3D>
|
||||||
|
<shadow rvXMLIvarName="shadow">0|0 0 0 0|{0, 0}</shadow>
|
||||||
|
<dictionary rvXMLIvarName="stroke">
|
||||||
|
<NSColor rvXMLDictionaryKey="RVShapeElementStrokeColorKey">0 0 0 0</NSColor>
|
||||||
|
<NSNumber rvXMLDictionaryKey="RVShapeElementStrokeWidthKey" hint="double">0</NSNumber>
|
||||||
|
</dictionary>
|
||||||
|
<NSString rvXMLIvarName="PlainText">VGhhdCBzYXZlZCBhIHdyZXRjaCBsaWtlIG1lIQ==</NSString>
|
||||||
|
<NSString rvXMLIvarName="RTFData">e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBUaGF0IHNhdmVkIGEgd3JldGNoIGxpa2UgbWUhfVxsaTBcc2EwXHNiMFxmaTBccWNccGFyfQ0KfQ0KfQ==</NSString>
|
||||||
|
<NSString rvXMLIvarName="WinFlowData">PEZsb3dEb2N1bWVudCBUZXh0QWxpZ25tZW50PSJMZWZ0IiB4bWxucz0iaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS93aW5meC8yMDA2L3hhbWwvcHJlc2VudGF0aW9uIj48UGFyYWdyYXBoIE1hcmdpbj0iMCwwLDAsMCIgVGV4dEFsaWdubWVudD0iQ2VudGVyIiBGb250RmFtaWx5PSJIZWx2ZXRpY2EiIEZvbnRTaXplPSI2MCI+PFNwYW4gRm9yZWdyb3VuZD0iI0ZGRkZGRkZGIiB4bWw6bGFuZz0iZW4tdXMiPjxSdW4gQmxvY2suVGV4dEFsaWdubWVudD0iQ2VudGVyIj5UaGF0IHNhdmVkIGEgd3JldGNoIGxpa2UgbWUhPC9SdW4+PC9TcGFuPjwvUGFyYWdyYXBoPjwvRmxvd0RvY3VtZW50Pg==</NSString>
|
||||||
|
<NSString rvXMLIvarName="WinFontData">PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTE2Ij8+PFJWRm9udCB4bWxuczppPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYS1pbnN0YW5jZSIgeG1sbnM9Imh0dHA6Ly9zY2hlbWFzLmRhdGFjb250cmFjdC5vcmcvMjAwNC8wNy9Qcm9QcmVzZW50ZXIuQ29tbW9uIj48S2VybmluZz4wPC9LZXJuaW5nPjxMaW5lU3BhY2luZz4wPC9MaW5lU3BhY2luZz48T3V0bGluZUNvbG9yIHhtbG5zOmQycDE9Imh0dHA6Ly9zY2hlbWFzLmRhdGFjb250cmFjdC5vcmcvMjAwNC8wNy9TeXN0ZW0uV2luZG93cy5NZWRpYSI+PGQycDE6QT4wPC9kMnAxOkE+PGQycDE6Qj4wPC9kMnAxOkI+PGQycDE6Rz4wPC9kMnAxOkc+PGQycDE6Uj4wPC9kMnAxOlI+PGQycDE6U2NBPjA8L2QycDE6U2NBPjxkMnAxOlNjQj4wPC9kMnAxOlNjQj48ZDJwMTpTY0c+MDwvZDJwMTpTY0c+PGQycDE6U2NSPjA8L2QycDE6U2NSPjwvT3V0bGluZUNvbG9yPjxPdXRsaW5lV2lkdGg+MDwvT3V0bGluZVdpZHRoPjxWYXJpYW50cz5Ob3JtYWw8L1ZhcmlhbnRzPjwvUlZGb250Pg==</NSString>
|
||||||
|
</RVTextElement>
|
||||||
|
</array>
|
||||||
|
</RVDisplaySlide>
|
||||||
|
<RVDisplaySlide backgroundColor="0 0 0 0" highlightColor="0 0 0 0" drawingBackgroundColor="false" enabled="true" hotKey="" label="" notes="" UUID="CCF908FC-0FE4-4C16-BE70-9543C2A76DC7" chordChartPath="">
|
||||||
|
<array rvXMLIvarName="cues" />
|
||||||
|
<array rvXMLIvarName="displayElements">
|
||||||
|
<RVTextElement displayName="" UUID="1c7dc52f-cd5a-4c7b-a0b1-d6b591534c00" typeID="0" displayDelay="0" locked="false" persistent="0" fromTemplate="false" opacity="1" source="" bezelRadius="0" rotation="0" drawingFill="false" drawingShadow="true" drawingStroke="false" fillColor="0 0 0 0" adjustsHeightToFit="false" verticalAlignment="0" revealType="0">
|
||||||
|
<RVRect3D rvXMLIvarName="position">{10 10 0 1004 748}</RVRect3D>
|
||||||
|
<shadow rvXMLIvarName="shadow">0|0 0 0 0|{0, 0}</shadow>
|
||||||
|
<dictionary rvXMLIvarName="stroke">
|
||||||
|
<NSColor rvXMLDictionaryKey="RVShapeElementStrokeColorKey">0 0 0 0</NSColor>
|
||||||
|
<NSNumber rvXMLDictionaryKey="RVShapeElementStrokeWidthKey" hint="double">0</NSNumber>
|
||||||
|
</dictionary>
|
||||||
|
<NSString rvXMLIvarName="PlainText">SSBvbmNlIHdhcyBsb3N0LCBidXQgbm93IGFtIGZvdW5kOw==</NSString>
|
||||||
|
<NSString rvXMLIvarName="RTFData">e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBJIG9uY2Ugd2FzIGxvc3QsIGJ1dCBub3cgYW0gZm91bmQ7fVxsaTBcc2EwXHNiMFxmaTBccWNccGFyfQ0KfQ0KfQ==</NSString>
|
||||||
|
<NSString rvXMLIvarName="WinFlowData">PEZsb3dEb2N1bWVudCBUZXh0QWxpZ25tZW50PSJMZWZ0IiB4bWxucz0iaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS93aW5meC8yMDA2L3hhbWwvcHJlc2VudGF0aW9uIj48UGFyYWdyYXBoIE1hcmdpbj0iMCwwLDAsMCIgVGV4dEFsaWdubWVudD0iQ2VudGVyIiBGb250RmFtaWx5PSJIZWx2ZXRpY2EiIEZvbnRTaXplPSI2MCI+PFNwYW4gRm9yZWdyb3VuZD0iI0ZGRkZGRkZGIiB4bWw6bGFuZz0iZW4tdXMiPjxSdW4gQmxvY2suVGV4dEFsaWdubWVudD0iQ2VudGVyIj5JIG9uY2Ugd2FzIGxvc3QsIGJ1dCBub3cgYW0gZm91bmQ7PC9SdW4+PC9TcGFuPjwvUGFyYWdyYXBoPjwvRmxvd0RvY3VtZW50Pg==</NSString>
|
||||||
|
<NSString rvXMLIvarName="WinFontData">PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTE2Ij8+PFJWRm9udCB4bWxuczppPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYS1pbnN0YW5jZSIgeG1sbnM9Imh0dHA6Ly9zY2hlbWFzLmRhdGFjb250cmFjdC5vcmcvMjAwNC8wNy9Qcm9QcmVzZW50ZXIuQ29tbW9uIj48S2VybmluZz4wPC9LZXJuaW5nPjxMaW5lU3BhY2luZz4wPC9MaW5lU3BhY2luZz48T3V0bGluZUNvbG9yIHhtbG5zOmQycDE9Imh0dHA6Ly9zY2hlbWFzLmRhdGFjb250cmFjdC5vcmcvMjAwNC8wNy9TeXN0ZW0uV2luZG93cy5NZWRpYSI+PGQycDE6QT4wPC9kMnAxOkE+PGQycDE6Qj4wPC9kMnAxOkI+PGQycDE6Rz4wPC9kMnAxOkc+PGQycDE6Uj4wPC9kMnAxOlI+PGQycDE6U2NBPjA8L2QycDE6U2NBPjxkMnAxOlNjQj4wPC9kMnAxOlNjQj48ZDJwMTpTY0c+MDwvZDJwMTpTY0c+PGQycDE6U2NSPjA8L2QycDE6U2NSPjwvT3V0bGluZUNvbG9yPjxPdXRsaW5lV2lkdGg+MDwvT3V0bGluZVdpZHRoPjxWYXJpYW50cz5Ob3JtYWw8L1ZhcmlhbnRzPjwvUlZGb250Pg==</NSString>
|
||||||
|
</RVTextElement>
|
||||||
|
</array>
|
||||||
|
</RVDisplaySlide>
|
||||||
|
<RVDisplaySlide backgroundColor="0 0 0 0" highlightColor="0 0 0 0" drawingBackgroundColor="false" enabled="true" hotKey="" label="" notes="" UUID="B33AF602-61BB-47FE-95E3-98640D6BD76A" chordChartPath="">
|
||||||
|
<array rvXMLIvarName="cues" />
|
||||||
|
<array rvXMLIvarName="displayElements">
|
||||||
|
<RVTextElement displayName="" UUID="cfebb003-0589-4bd1-aedf-09f98de2df77" typeID="0" displayDelay="0" locked="false" persistent="0" fromTemplate="false" opacity="1" source="" bezelRadius="0" rotation="0" drawingFill="false" drawingShadow="true" drawingStroke="false" fillColor="0 0 0 0" adjustsHeightToFit="false" verticalAlignment="0" revealType="0">
|
||||||
|
<RVRect3D rvXMLIvarName="position">{10 10 0 1004 748}</RVRect3D>
|
||||||
|
<shadow rvXMLIvarName="shadow">0|0 0 0 0|{0, 0}</shadow>
|
||||||
|
<dictionary rvXMLIvarName="stroke">
|
||||||
|
<NSColor rvXMLDictionaryKey="RVShapeElementStrokeColorKey">0 0 0 0</NSColor>
|
||||||
|
<NSNumber rvXMLDictionaryKey="RVShapeElementStrokeWidthKey" hint="double">0</NSNumber>
|
||||||
|
</dictionary>
|
||||||
|
<NSString rvXMLIvarName="PlainText">V2FzIGJsaW5kLCBidXQgbm93IEkgc2VlLg==</NSString>
|
||||||
|
<NSString rvXMLIvarName="RTFData">e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBXYXMgYmxpbmQsIGJ1dCBub3cgSSBzZWUufVxsaTBcc2EwXHNiMFxmaTBccWNccGFyfQ0KfQ0KfQ==</NSString>
|
||||||
|
<NSString rvXMLIvarName="WinFlowData">PEZsb3dEb2N1bWVudCBUZXh0QWxpZ25tZW50PSJMZWZ0IiB4bWxucz0iaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS93aW5meC8yMDA2L3hhbWwvcHJlc2VudGF0aW9uIj48UGFyYWdyYXBoIE1hcmdpbj0iMCwwLDAsMCIgVGV4dEFsaWdubWVudD0iQ2VudGVyIiBGb250RmFtaWx5PSJIZWx2ZXRpY2EiIEZvbnRTaXplPSI2MCI+PFNwYW4gRm9yZWdyb3VuZD0iI0ZGRkZGRkZGIiB4bWw6bGFuZz0iZW4tdXMiPjxSdW4gQmxvY2suVGV4dEFsaWdubWVudD0iQ2VudGVyIj5XYXMgYmxpbmQsIGJ1dCBub3cgSSBzZWUuPC9SdW4+PC9TcGFuPjwvUGFyYWdyYXBoPjwvRmxvd0RvY3VtZW50Pg==</NSString>
|
||||||
|
<NSString rvXMLIvarName="WinFontData">PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTE2Ij8+PFJWRm9udCB4bWxuczppPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYS1pbnN0YW5jZSIgeG1sbnM9Imh0dHA6Ly9zY2hlbWFzLmRhdGFjb250cmFjdC5vcmcvMjAwNC8wNy9Qcm9QcmVzZW50ZXIuQ29tbW9uIj48S2VybmluZz4wPC9LZXJuaW5nPjxMaW5lU3BhY2luZz4wPC9MaW5lU3BhY2luZz48T3V0bGluZUNvbG9yIHhtbG5zOmQycDE9Imh0dHA6Ly9zY2hlbWFzLmRhdGFjb250cmFjdC5vcmcvMjAwNC8wNy9TeXN0ZW0uV2luZG93cy5NZWRpYSI+PGQycDE6QT4wPC9kMnAxOkE+PGQycDE6Qj4wPC9kMnAxOkI+PGQycDE6Rz4wPC9kMnAxOkc+PGQycDE6Uj4wPC9kMnAxOlI+PGQycDE6U2NBPjA8L2QycDE6U2NBPjxkMnAxOlNjQj4wPC9kMnAxOlNjQj48ZDJwMTpTY0c+MDwvZDJwMTpTY0c+PGQycDE6U2NSPjA8L2QycDE6U2NSPjwvT3V0bGluZUNvbG9yPjxPdXRsaW5lV2lkdGg+MDwvT3V0bGluZVdpZHRoPjxWYXJpYW50cz5Ob3JtYWw8L1ZhcmlhbnRzPjwvUlZGb250Pg==</NSString>
|
||||||
|
</RVTextElement>
|
||||||
|
</array>
|
||||||
|
</RVDisplaySlide>
|
||||||
|
<RVDisplaySlide backgroundColor="0 0 0 0" highlightColor="0 0 0 0" drawingBackgroundColor="false" enabled="true" hotKey="" label="" notes="" UUID="02932C9A-C505-4856-A48E-339CA927B020" chordChartPath="">
|
||||||
|
<array rvXMLIvarName="cues" />
|
||||||
|
<array rvXMLIvarName="displayElements">
|
||||||
|
<RVTextElement displayName="" UUID="a0421c73-4baf-47b3-a6f7-7c417dd50124" typeID="0" displayDelay="0" locked="false" persistent="0" fromTemplate="false" opacity="1" source="" bezelRadius="0" rotation="0" drawingFill="false" drawingShadow="true" drawingStroke="false" fillColor="0 0 0 0" adjustsHeightToFit="false" verticalAlignment="0" revealType="0">
|
||||||
|
<RVRect3D rvXMLIvarName="position">{10 10 0 1004 748}</RVRect3D>
|
||||||
|
<shadow rvXMLIvarName="shadow">0|0 0 0 0|{0, 0}</shadow>
|
||||||
|
<dictionary rvXMLIvarName="stroke">
|
||||||
|
<NSColor rvXMLDictionaryKey="RVShapeElementStrokeColorKey">0 0 0 0</NSColor>
|
||||||
|
<NSNumber rvXMLDictionaryKey="RVShapeElementStrokeWidthKey" hint="double">0</NSNumber>
|
||||||
|
</dictionary>
|
||||||
|
<NSString rvXMLIvarName="PlainText">J1R3YXMgZ3JhY2UgdGhhdCB0YXVnaHQgbXkgaGVhcnQgdG8gZmVhciw=</NSString>
|
||||||
|
<NSString rvXMLIvarName="RTFData">e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCAnVHdhcyBncmFjZSB0aGF0IHRhdWdodCBteSBoZWFydCB0byBmZWFyLH1cbGkwXHNhMFxzYjBcZmkwXHFjXHBhcn0NCn0NCn0=</NSString>
|
||||||
|
<NSString rvXMLIvarName="WinFlowData">PEZsb3dEb2N1bWVudCBUZXh0QWxpZ25tZW50PSJMZWZ0IiB4bWxucz0iaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS93aW5meC8yMDA2L3hhbWwvcHJlc2VudGF0aW9uIj48UGFyYWdyYXBoIE1hcmdpbj0iMCwwLDAsMCIgVGV4dEFsaWdubWVudD0iQ2VudGVyIiBGb250RmFtaWx5PSJIZWx2ZXRpY2EiIEZvbnRTaXplPSI2MCI+PFNwYW4gRm9yZWdyb3VuZD0iI0ZGRkZGRkZGIiB4bWw6bGFuZz0iZW4tdXMiPjxSdW4gQmxvY2suVGV4dEFsaWdubWVudD0iQ2VudGVyIj4nVHdhcyBncmFjZSB0aGF0IHRhdWdodCBteSBoZWFydCB0byBmZWFyLDwvUnVuPjwvU3Bhbj48L1BhcmFncmFwaD48L0Zsb3dEb2N1bWVudD4=</NSString>
|
||||||
|
<NSString rvXMLIvarName="WinFontData">PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTE2Ij8+PFJWRm9udCB4bWxuczppPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYS1pbnN0YW5jZSIgeG1sbnM9Imh0dHA6Ly9zY2hlbWFzLmRhdGFjb250cmFjdC5vcmcvMjAwNC8wNy9Qcm9QcmVzZW50ZXIuQ29tbW9uIj48S2VybmluZz4wPC9LZXJuaW5nPjxMaW5lU3BhY2luZz4wPC9MaW5lU3BhY2luZz48T3V0bGluZUNvbG9yIHhtbG5zOmQycDE9Imh0dHA6Ly9zY2hlbWFzLmRhdGFjb250cmFjdC5vcmcvMjAwNC8wNy9TeXN0ZW0uV2luZG93cy5NZWRpYSI+PGQycDE6QT4wPC9kMnAxOkE+PGQycDE6Qj4wPC9kMnAxOkI+PGQycDE6Rz4wPC9kMnAxOkc+PGQycDE6Uj4wPC9kMnAxOlI+PGQycDE6U2NBPjA8L2QycDE6U2NBPjxkMnAxOlNjQj4wPC9kMnAxOlNjQj48ZDJwMTpTY0c+MDwvZDJwMTpTY0c+PGQycDE6U2NSPjA8L2QycDE6U2NSPjwvT3V0bGluZUNvbG9yPjxPdXRsaW5lV2lkdGg+MDwvT3V0bGluZVdpZHRoPjxWYXJpYW50cz5Ob3JtYWw8L1ZhcmlhbnRzPjwvUlZGb250Pg==</NSString>
|
||||||
|
</RVTextElement>
|
||||||
|
</array>
|
||||||
|
</RVDisplaySlide>
|
||||||
|
<RVDisplaySlide backgroundColor="0 0 0 0" highlightColor="0 0 0 0" drawingBackgroundColor="false" enabled="true" hotKey="" label="" notes="" UUID="F6FC7C3F-2A38-4D63-83B1-7EDA30371535" chordChartPath="">
|
||||||
|
<array rvXMLIvarName="cues" />
|
||||||
|
<array rvXMLIvarName="displayElements">
|
||||||
|
<RVTextElement displayName="" UUID="d015718f-3893-417b-9566-442d4957b69f" typeID="0" displayDelay="0" locked="false" persistent="0" fromTemplate="false" opacity="1" source="" bezelRadius="0" rotation="0" drawingFill="false" drawingShadow="true" drawingStroke="false" fillColor="0 0 0 0" adjustsHeightToFit="false" verticalAlignment="0" revealType="0">
|
||||||
|
<RVRect3D rvXMLIvarName="position">{10 10 0 1004 748}</RVRect3D>
|
||||||
|
<shadow rvXMLIvarName="shadow">0|0 0 0 0|{0, 0}</shadow>
|
||||||
|
<dictionary rvXMLIvarName="stroke">
|
||||||
|
<NSColor rvXMLDictionaryKey="RVShapeElementStrokeColorKey">0 0 0 0</NSColor>
|
||||||
|
<NSNumber rvXMLDictionaryKey="RVShapeElementStrokeWidthKey" hint="double">0</NSNumber>
|
||||||
|
</dictionary>
|
||||||
|
<NSString rvXMLIvarName="PlainText">QW5kIGdyYWNlIG15IGZlYXJzIHJlbGlldmVkOw==</NSString>
|
||||||
|
<NSString rvXMLIvarName="RTFData">e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBBbmQgZ3JhY2UgbXkgZmVhcnMgcmVsaWV2ZWQ7fVxsaTBcc2EwXHNiMFxmaTBccWNccGFyfQ0KfQ0KfQ==</NSString>
|
||||||
|
<NSString rvXMLIvarName="WinFlowData">PEZsb3dEb2N1bWVudCBUZXh0QWxpZ25tZW50PSJMZWZ0IiB4bWxucz0iaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS93aW5meC8yMDA2L3hhbWwvcHJlc2VudGF0aW9uIj48UGFyYWdyYXBoIE1hcmdpbj0iMCwwLDAsMCIgVGV4dEFsaWdubWVudD0iQ2VudGVyIiBGb250RmFtaWx5PSJIZWx2ZXRpY2EiIEZvbnRTaXplPSI2MCI+PFNwYW4gRm9yZWdyb3VuZD0iI0ZGRkZGRkZGIiB4bWw6bGFuZz0iZW4tdXMiPjxSdW4gQmxvY2suVGV4dEFsaWdubWVudD0iQ2VudGVyIj5BbmQgZ3JhY2UgbXkgZmVhcnMgcmVsaWV2ZWQ7PC9SdW4+PC9TcGFuPjwvUGFyYWdyYXBoPjwvRmxvd0RvY3VtZW50Pg==</NSString>
|
||||||
|
<NSString rvXMLIvarName="WinFontData">PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTE2Ij8+PFJWRm9udCB4bWxuczppPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYS1pbnN0YW5jZSIgeG1sbnM9Imh0dHA6Ly9zY2hlbWFzLmRhdGFjb250cmFjdC5vcmcvMjAwNC8wNy9Qcm9QcmVzZW50ZXIuQ29tbW9uIj48S2VybmluZz4wPC9LZXJuaW5nPjxMaW5lU3BhY2luZz4wPC9MaW5lU3BhY2luZz48T3V0bGluZUNvbG9yIHhtbG5zOmQycDE9Imh0dHA6Ly9zY2hlbWFzLmRhdGFjb250cmFjdC5vcmcvMjAwNC8wNy9TeXN0ZW0uV2luZG93cy5NZWRpYSI+PGQycDE6QT4wPC9kMnAxOkE+PGQycDE6Qj4wPC9kMnAxOkI+PGQycDE6Rz4wPC9kMnAxOkc+PGQycDE6Uj4wPC9kMnAxOlI+PGQycDE6U2NBPjA8L2QycDE6U2NBPjxkMnAxOlNjQj4wPC9kMnAxOlNjQj48ZDJwMTpTY0c+MDwvZDJwMTpTY0c+PGQycDE6U2NSPjA8L2QycDE6U2NSPjwvT3V0bGluZUNvbG9yPjxPdXRsaW5lV2lkdGg+MDwvT3V0bGluZVdpZHRoPjxWYXJpYW50cz5Ob3JtYWw8L1ZhcmlhbnRzPjwvUlZGb250Pg==</NSString>
|
||||||
|
</RVTextElement>
|
||||||
|
</array>
|
||||||
|
</RVDisplaySlide>
|
||||||
|
<RVDisplaySlide backgroundColor="0 0 0 0" highlightColor="0 0 0 0" drawingBackgroundColor="false" enabled="true" hotKey="" label="" notes="" UUID="EEBFE94B-D0F2-4E41-BBE7-B5A7D4F62243" chordChartPath="">
|
||||||
|
<array rvXMLIvarName="cues" />
|
||||||
|
<array rvXMLIvarName="displayElements">
|
||||||
|
<RVTextElement displayName="" UUID="320f9dd4-fc87-493b-9dda-1a35f2ca41f5" typeID="0" displayDelay="0" locked="false" persistent="0" fromTemplate="false" opacity="1" source="" bezelRadius="0" rotation="0" drawingFill="false" drawingShadow="true" drawingStroke="false" fillColor="0 0 0 0" adjustsHeightToFit="false" verticalAlignment="0" revealType="0">
|
||||||
|
<RVRect3D rvXMLIvarName="position">{10 10 0 1004 748}</RVRect3D>
|
||||||
|
<shadow rvXMLIvarName="shadow">0|0 0 0 0|{0, 0}</shadow>
|
||||||
|
<dictionary rvXMLIvarName="stroke">
|
||||||
|
<NSColor rvXMLDictionaryKey="RVShapeElementStrokeColorKey">0 0 0 0</NSColor>
|
||||||
|
<NSNumber rvXMLDictionaryKey="RVShapeElementStrokeWidthKey" hint="double">0</NSNumber>
|
||||||
|
</dictionary>
|
||||||
|
<NSString rvXMLIvarName="PlainText">SG93IHByZWNpb3VzIGRpZCB0aGF0IGdyYWNlIGFwcGVhcg==</NSString>
|
||||||
|
<NSString rvXMLIvarName="RTFData">e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBIb3cgcHJlY2lvdXMgZGlkIHRoYXQgZ3JhY2UgYXBwZWFyfVxsaTBcc2EwXHNiMFxmaTBccWNccGFyfQ0KfQ0KfQ==</NSString>
|
||||||
|
<NSString rvXMLIvarName="WinFlowData">PEZsb3dEb2N1bWVudCBUZXh0QWxpZ25tZW50PSJMZWZ0IiB4bWxucz0iaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS93aW5meC8yMDA2L3hhbWwvcHJlc2VudGF0aW9uIj48UGFyYWdyYXBoIE1hcmdpbj0iMCwwLDAsMCIgVGV4dEFsaWdubWVudD0iQ2VudGVyIiBGb250RmFtaWx5PSJIZWx2ZXRpY2EiIEZvbnRTaXplPSI2MCI+PFNwYW4gRm9yZWdyb3VuZD0iI0ZGRkZGRkZGIiB4bWw6bGFuZz0iZW4tdXMiPjxSdW4gQmxvY2suVGV4dEFsaWdubWVudD0iQ2VudGVyIj5Ib3cgcHJlY2lvdXMgZGlkIHRoYXQgZ3JhY2UgYXBwZWFyPC9SdW4+PC9TcGFuPjwvUGFyYWdyYXBoPjwvRmxvd0RvY3VtZW50Pg==</NSString>
|
||||||
|
<NSString rvXMLIvarName="WinFontData">PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTE2Ij8+PFJWRm9udCB4bWxuczppPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYS1pbnN0YW5jZSIgeG1sbnM9Imh0dHA6Ly9zY2hlbWFzLmRhdGFjb250cmFjdC5vcmcvMjAwNC8wNy9Qcm9QcmVzZW50ZXIuQ29tbW9uIj48S2VybmluZz4wPC9LZXJuaW5nPjxMaW5lU3BhY2luZz4wPC9MaW5lU3BhY2luZz48T3V0bGluZUNvbG9yIHhtbG5zOmQycDE9Imh0dHA6Ly9zY2hlbWFzLmRhdGFjb250cmFjdC5vcmcvMjAwNC8wNy9TeXN0ZW0uV2luZG93cy5NZWRpYSI+PGQycDE6QT4wPC9kMnAxOkE+PGQycDE6Qj4wPC9kMnAxOkI+PGQycDE6Rz4wPC9kMnAxOkc+PGQycDE6Uj4wPC9kMnAxOlI+PGQycDE6U2NBPjA8L2QycDE6U2NBPjxkMnAxOlNjQj4wPC9kMnAxOlNjQj48ZDJwMTpTY0c+MDwvZDJwMTpTY0c+PGQycDE6U2NSPjA8L2QycDE6U2NSPjwvT3V0bGluZUNvbG9yPjxPdXRsaW5lV2lkdGg+MDwvT3V0bGluZVdpZHRoPjxWYXJpYW50cz5Ob3JtYWw8L1ZhcmlhbnRzPjwvUlZGb250Pg==</NSString>
|
||||||
|
</RVTextElement>
|
||||||
|
</array>
|
||||||
|
</RVDisplaySlide>
|
||||||
|
<RVDisplaySlide backgroundColor="0 0 0 0" highlightColor="0 0 0 0" drawingBackgroundColor="false" enabled="true" hotKey="" label="" notes="" UUID="0CDDEA18-F48E-4B85-8054-01140192EDC7" chordChartPath="">
|
||||||
|
<array rvXMLIvarName="cues" />
|
||||||
|
<array rvXMLIvarName="displayElements">
|
||||||
|
<RVTextElement displayName="" UUID="c65e90fa-554f-4977-bf2e-8fc6a832e67c" typeID="0" displayDelay="0" locked="false" persistent="0" fromTemplate="false" opacity="1" source="" bezelRadius="0" rotation="0" drawingFill="false" drawingShadow="true" drawingStroke="false" fillColor="0 0 0 0" adjustsHeightToFit="false" verticalAlignment="0" revealType="0">
|
||||||
|
<RVRect3D rvXMLIvarName="position">{10 10 0 1004 748}</RVRect3D>
|
||||||
|
<shadow rvXMLIvarName="shadow">0|0 0 0 0|{0, 0}</shadow>
|
||||||
|
<dictionary rvXMLIvarName="stroke">
|
||||||
|
<NSColor rvXMLDictionaryKey="RVShapeElementStrokeColorKey">0 0 0 0</NSColor>
|
||||||
|
<NSNumber rvXMLDictionaryKey="RVShapeElementStrokeWidthKey" hint="double">0</NSNumber>
|
||||||
|
</dictionary>
|
||||||
|
<NSString rvXMLIvarName="PlainText">VGhlIGhvdXIgSSBmaXJzdCBiZWxpZXZlZC4=</NSString>
|
||||||
|
<NSString rvXMLIvarName="RTFData">e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBUaGUgaG91ciBJIGZpcnN0IGJlbGlldmVkLn1cbGkwXHNhMFxzYjBcZmkwXHFjXHBhcn0NCn0NCn0=</NSString>
|
||||||
|
<NSString rvXMLIvarName="WinFlowData">PEZsb3dEb2N1bWVudCBUZXh0QWxpZ25tZW50PSJMZWZ0IiB4bWxucz0iaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS93aW5meC8yMDA2L3hhbWwvcHJlc2VudGF0aW9uIj48UGFyYWdyYXBoIE1hcmdpbj0iMCwwLDAsMCIgVGV4dEFsaWdubWVudD0iQ2VudGVyIiBGb250RmFtaWx5PSJIZWx2ZXRpY2EiIEZvbnRTaXplPSI2MCI+PFNwYW4gRm9yZWdyb3VuZD0iI0ZGRkZGRkZGIiB4bWw6bGFuZz0iZW4tdXMiPjxSdW4gQmxvY2suVGV4dEFsaWdubWVudD0iQ2VudGVyIj5UaGUgaG91ciBJIGZpcnN0IGJlbGlldmVkLjwvUnVuPjwvU3Bhbj48L1BhcmFncmFwaD48L0Zsb3dEb2N1bWVudD4=</NSString>
|
||||||
|
<NSString rvXMLIvarName="WinFontData">PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTE2Ij8+PFJWRm9udCB4bWxuczppPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYS1pbnN0YW5jZSIgeG1sbnM9Imh0dHA6Ly9zY2hlbWFzLmRhdGFjb250cmFjdC5vcmcvMjAwNC8wNy9Qcm9QcmVzZW50ZXIuQ29tbW9uIj48S2VybmluZz4wPC9LZXJuaW5nPjxMaW5lU3BhY2luZz4wPC9MaW5lU3BhY2luZz48T3V0bGluZUNvbG9yIHhtbG5zOmQycDE9Imh0dHA6Ly9zY2hlbWFzLmRhdGFjb250cmFjdC5vcmcvMjAwNC8wNy9TeXN0ZW0uV2luZG93cy5NZWRpYSI+PGQycDE6QT4wPC9kMnAxOkE+PGQycDE6Qj4wPC9kMnAxOkI+PGQycDE6Rz4wPC9kMnAxOkc+PGQycDE6Uj4wPC9kMnAxOlI+PGQycDE6U2NBPjA8L2QycDE6U2NBPjxkMnAxOlNjQj4wPC9kMnAxOlNjQj48ZDJwMTpTY0c+MDwvZDJwMTpTY0c+PGQycDE6U2NSPjA8L2QycDE6U2NSPjwvT3V0bGluZUNvbG9yPjxPdXRsaW5lV2lkdGg+MDwvT3V0bGluZVdpZHRoPjxWYXJpYW50cz5Ob3JtYWw8L1ZhcmlhbnRzPjwvUlZGb250Pg==</NSString>
|
||||||
|
</RVTextElement>
|
||||||
|
</array>
|
||||||
|
</RVDisplaySlide>
|
||||||
|
<RVDisplaySlide backgroundColor="0 0 0 0" highlightColor="0 0 0 0" drawingBackgroundColor="false" enabled="true" hotKey="" label="" notes="" UUID="E1193588-A9B8-4371-8DC0-F16DC6D3B489" chordChartPath="">
|
||||||
|
<array rvXMLIvarName="cues" />
|
||||||
|
<array rvXMLIvarName="displayElements">
|
||||||
|
<RVTextElement displayName="" UUID="d661ffdb-d209-44f1-9fba-dd2dec4642cf" typeID="0" displayDelay="0" locked="false" persistent="0" fromTemplate="false" opacity="1" source="" bezelRadius="0" rotation="0" drawingFill="false" drawingShadow="true" drawingStroke="false" fillColor="0 0 0 0" adjustsHeightToFit="false" verticalAlignment="0" revealType="0">
|
||||||
|
<RVRect3D rvXMLIvarName="position">{10 10 0 1004 748}</RVRect3D>
|
||||||
|
<shadow rvXMLIvarName="shadow">0|0 0 0 0|{0, 0}</shadow>
|
||||||
|
<dictionary rvXMLIvarName="stroke">
|
||||||
|
<NSColor rvXMLDictionaryKey="RVShapeElementStrokeColorKey">0 0 0 0</NSColor>
|
||||||
|
<NSNumber rvXMLDictionaryKey="RVShapeElementStrokeWidthKey" hint="double">0</NSNumber>
|
||||||
|
</dictionary>
|
||||||
|
<NSString rvXMLIvarName="PlainText">VGhyb3VnaCBtYW55IGRhbmdlcnMsIHRvaWxzIGFuZCBzbmFyZXMs</NSString>
|
||||||
|
<NSString rvXMLIvarName="RTFData">e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBUaHJvdWdoIG1hbnkgZGFuZ2VycywgdG9pbHMgYW5kIHNuYXJlcyx9XGxpMFxzYTBcc2IwXGZpMFxxY1xwYXJ9DQp9DQp9</NSString>
|
||||||
|
<NSString rvXMLIvarName="WinFlowData">PEZsb3dEb2N1bWVudCBUZXh0QWxpZ25tZW50PSJMZWZ0IiB4bWxucz0iaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS93aW5meC8yMDA2L3hhbWwvcHJlc2VudGF0aW9uIj48UGFyYWdyYXBoIE1hcmdpbj0iMCwwLDAsMCIgVGV4dEFsaWdubWVudD0iQ2VudGVyIiBGb250RmFtaWx5PSJIZWx2ZXRpY2EiIEZvbnRTaXplPSI2MCI+PFNwYW4gRm9yZWdyb3VuZD0iI0ZGRkZGRkZGIiB4bWw6bGFuZz0iZW4tdXMiPjxSdW4gQmxvY2suVGV4dEFsaWdubWVudD0iQ2VudGVyIj5UaHJvdWdoIG1hbnkgZGFuZ2VycywgdG9pbHMgYW5kIHNuYXJlcyw8L1J1bj48L1NwYW4+PC9QYXJhZ3JhcGg+PC9GbG93RG9jdW1lbnQ+</NSString>
|
||||||
|
<NSString rvXMLIvarName="WinFontData">PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTE2Ij8+PFJWRm9udCB4bWxuczppPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYS1pbnN0YW5jZSIgeG1sbnM9Imh0dHA6Ly9zY2hlbWFzLmRhdGFjb250cmFjdC5vcmcvMjAwNC8wNy9Qcm9QcmVzZW50ZXIuQ29tbW9uIj48S2VybmluZz4wPC9LZXJuaW5nPjxMaW5lU3BhY2luZz4wPC9MaW5lU3BhY2luZz48T3V0bGluZUNvbG9yIHhtbG5zOmQycDE9Imh0dHA6Ly9zY2hlbWFzLmRhdGFjb250cmFjdC5vcmcvMjAwNC8wNy9TeXN0ZW0uV2luZG93cy5NZWRpYSI+PGQycDE6QT4wPC9kMnAxOkE+PGQycDE6Qj4wPC9kMnAxOkI+PGQycDE6Rz4wPC9kMnAxOkc+PGQycDE6Uj4wPC9kMnAxOlI+PGQycDE6U2NBPjA8L2QycDE6U2NBPjxkMnAxOlNjQj4wPC9kMnAxOlNjQj48ZDJwMTpTY0c+MDwvZDJwMTpTY0c+PGQycDE6U2NSPjA8L2QycDE6U2NSPjwvT3V0bGluZUNvbG9yPjxPdXRsaW5lV2lkdGg+MDwvT3V0bGluZVdpZHRoPjxWYXJpYW50cz5Ob3JtYWw8L1ZhcmlhbnRzPjwvUlZGb250Pg==</NSString>
|
||||||
|
</RVTextElement>
|
||||||
|
</array>
|
||||||
|
</RVDisplaySlide>
|
||||||
|
<RVDisplaySlide backgroundColor="0 0 0 0" highlightColor="0 0 0 0" drawingBackgroundColor="false" enabled="true" hotKey="" label="" notes="" UUID="EBD1940D-7360-4E04-9E8F-E752B1F9ECBF" chordChartPath="">
|
||||||
|
<array rvXMLIvarName="cues" />
|
||||||
|
<array rvXMLIvarName="displayElements">
|
||||||
|
<RVTextElement displayName="" UUID="b1b54b33-8081-4277-a844-7e31256f4d48" typeID="0" displayDelay="0" locked="false" persistent="0" fromTemplate="false" opacity="1" source="" bezelRadius="0" rotation="0" drawingFill="false" drawingShadow="true" drawingStroke="false" fillColor="0 0 0 0" adjustsHeightToFit="false" verticalAlignment="0" revealType="0">
|
||||||
|
<RVRect3D rvXMLIvarName="position">{10 10 0 1004 748}</RVRect3D>
|
||||||
|
<shadow rvXMLIvarName="shadow">0|0 0 0 0|{0, 0}</shadow>
|
||||||
|
<dictionary rvXMLIvarName="stroke">
|
||||||
|
<NSColor rvXMLDictionaryKey="RVShapeElementStrokeColorKey">0 0 0 0</NSColor>
|
||||||
|
<NSNumber rvXMLDictionaryKey="RVShapeElementStrokeWidthKey" hint="double">0</NSNumber>
|
||||||
|
</dictionary>
|
||||||
|
<NSString rvXMLIvarName="PlainText">SSBoYXZlIGFscmVhZHkgY29tZTs=</NSString>
|
||||||
|
<NSString rvXMLIvarName="RTFData">e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBJIGhhdmUgYWxyZWFkeSBjb21lO31cbGkwXHNhMFxzYjBcZmkwXHFjXHBhcn0NCn0NCn0=</NSString>
|
||||||
|
<NSString rvXMLIvarName="WinFlowData">PEZsb3dEb2N1bWVudCBUZXh0QWxpZ25tZW50PSJMZWZ0IiB4bWxucz0iaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS93aW5meC8yMDA2L3hhbWwvcHJlc2VudGF0aW9uIj48UGFyYWdyYXBoIE1hcmdpbj0iMCwwLDAsMCIgVGV4dEFsaWdubWVudD0iQ2VudGVyIiBGb250RmFtaWx5PSJIZWx2ZXRpY2EiIEZvbnRTaXplPSI2MCI+PFNwYW4gRm9yZWdyb3VuZD0iI0ZGRkZGRkZGIiB4bWw6bGFuZz0iZW4tdXMiPjxSdW4gQmxvY2suVGV4dEFsaWdubWVudD0iQ2VudGVyIj5JIGhhdmUgYWxyZWFkeSBjb21lOzwvUnVuPjwvU3Bhbj48L1BhcmFncmFwaD48L0Zsb3dEb2N1bWVudD4=</NSString>
|
||||||
|
<NSString rvXMLIvarName="WinFontData">PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTE2Ij8+PFJWRm9udCB4bWxuczppPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYS1pbnN0YW5jZSIgeG1sbnM9Imh0dHA6Ly9zY2hlbWFzLmRhdGFjb250cmFjdC5vcmcvMjAwNC8wNy9Qcm9QcmVzZW50ZXIuQ29tbW9uIj48S2VybmluZz4wPC9LZXJuaW5nPjxMaW5lU3BhY2luZz4wPC9MaW5lU3BhY2luZz48T3V0bGluZUNvbG9yIHhtbG5zOmQycDE9Imh0dHA6Ly9zY2hlbWFzLmRhdGFjb250cmFjdC5vcmcvMjAwNC8wNy9TeXN0ZW0uV2luZG93cy5NZWRpYSI+PGQycDE6QT4wPC9kMnAxOkE+PGQycDE6Qj4wPC9kMnAxOkI+PGQycDE6Rz4wPC9kMnAxOkc+PGQycDE6Uj4wPC9kMnAxOlI+PGQycDE6U2NBPjA8L2QycDE6U2NBPjxkMnAxOlNjQj4wPC9kMnAxOlNjQj48ZDJwMTpTY0c+MDwvZDJwMTpTY0c+PGQycDE6U2NSPjA8L2QycDE6U2NSPjwvT3V0bGluZUNvbG9yPjxPdXRsaW5lV2lkdGg+MDwvT3V0bGluZVdpZHRoPjxWYXJpYW50cz5Ob3JtYWw8L1ZhcmlhbnRzPjwvUlZGb250Pg==</NSString>
|
||||||
|
</RVTextElement>
|
||||||
|
</array>
|
||||||
|
</RVDisplaySlide>
|
||||||
|
<RVDisplaySlide backgroundColor="0 0 0 0" highlightColor="0 0 0 0" drawingBackgroundColor="false" enabled="true" hotKey="" label="" notes="" UUID="76F80153-DF39-4CE8-B186-79D548C596F5" chordChartPath="">
|
||||||
|
<array rvXMLIvarName="cues" />
|
||||||
|
<array rvXMLIvarName="displayElements">
|
||||||
|
<RVTextElement displayName="" UUID="05637090-488c-4f57-a015-3b328caaa019" typeID="0" displayDelay="0" locked="false" persistent="0" fromTemplate="false" opacity="1" source="" bezelRadius="0" rotation="0" drawingFill="false" drawingShadow="true" drawingStroke="false" fillColor="0 0 0 0" adjustsHeightToFit="false" verticalAlignment="0" revealType="0">
|
||||||
|
<RVRect3D rvXMLIvarName="position">{10 10 0 1004 748}</RVRect3D>
|
||||||
|
<shadow rvXMLIvarName="shadow">0|0 0 0 0|{0, 0}</shadow>
|
||||||
|
<dictionary rvXMLIvarName="stroke">
|
||||||
|
<NSColor rvXMLDictionaryKey="RVShapeElementStrokeColorKey">0 0 0 0</NSColor>
|
||||||
|
<NSNumber rvXMLDictionaryKey="RVShapeElementStrokeWidthKey" hint="double">0</NSNumber>
|
||||||
|
</dictionary>
|
||||||
|
<NSString rvXMLIvarName="PlainText">J1RpcyBncmFjZSBoYXRoIGJyb3VnaHQgbWUgc2FmZSB0aHVzIGZhciw=</NSString>
|
||||||
|
<NSString rvXMLIvarName="RTFData">e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCAnVGlzIGdyYWNlIGhhdGggYnJvdWdodCBtZSBzYWZlIHRodXMgZmFyLH1cbGkwXHNhMFxzYjBcZmkwXHFjXHBhcn0NCn0NCn0=</NSString>
|
||||||
|
<NSString rvXMLIvarName="WinFlowData">PEZsb3dEb2N1bWVudCBUZXh0QWxpZ25tZW50PSJMZWZ0IiB4bWxucz0iaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS93aW5meC8yMDA2L3hhbWwvcHJlc2VudGF0aW9uIj48UGFyYWdyYXBoIE1hcmdpbj0iMCwwLDAsMCIgVGV4dEFsaWdubWVudD0iQ2VudGVyIiBGb250RmFtaWx5PSJIZWx2ZXRpY2EiIEZvbnRTaXplPSI2MCI+PFNwYW4gRm9yZWdyb3VuZD0iI0ZGRkZGRkZGIiB4bWw6bGFuZz0iZW4tdXMiPjxSdW4gQmxvY2suVGV4dEFsaWdubWVudD0iQ2VudGVyIj4nVGlzIGdyYWNlIGhhdGggYnJvdWdodCBtZSBzYWZlIHRodXMgZmFyLDwvUnVuPjwvU3Bhbj48L1BhcmFncmFwaD48L0Zsb3dEb2N1bWVudD4=</NSString>
|
||||||
|
<NSString rvXMLIvarName="WinFontData">PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTE2Ij8+PFJWRm9udCB4bWxuczppPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYS1pbnN0YW5jZSIgeG1sbnM9Imh0dHA6Ly9zY2hlbWFzLmRhdGFjb250cmFjdC5vcmcvMjAwNC8wNy9Qcm9QcmVzZW50ZXIuQ29tbW9uIj48S2VybmluZz4wPC9LZXJuaW5nPjxMaW5lU3BhY2luZz4wPC9MaW5lU3BhY2luZz48T3V0bGluZUNvbG9yIHhtbG5zOmQycDE9Imh0dHA6Ly9zY2hlbWFzLmRhdGFjb250cmFjdC5vcmcvMjAwNC8wNy9TeXN0ZW0uV2luZG93cy5NZWRpYSI+PGQycDE6QT4wPC9kMnAxOkE+PGQycDE6Qj4wPC9kMnAxOkI+PGQycDE6Rz4wPC9kMnAxOkc+PGQycDE6Uj4wPC9kMnAxOlI+PGQycDE6U2NBPjA8L2QycDE6U2NBPjxkMnAxOlNjQj4wPC9kMnAxOlNjQj48ZDJwMTpTY0c+MDwvZDJwMTpTY0c+PGQycDE6U2NSPjA8L2QycDE6U2NSPjwvT3V0bGluZUNvbG9yPjxPdXRsaW5lV2lkdGg+MDwvT3V0bGluZVdpZHRoPjxWYXJpYW50cz5Ob3JtYWw8L1ZhcmlhbnRzPjwvUlZGb250Pg==</NSString>
|
||||||
|
</RVTextElement>
|
||||||
|
</array>
|
||||||
|
</RVDisplaySlide>
|
||||||
|
<RVDisplaySlide backgroundColor="0 0 0 0" highlightColor="0 0 0 0" drawingBackgroundColor="false" enabled="true" hotKey="" label="" notes="" UUID="D4E43B14-8E57-44AA-BCD3-0B1F1401A829" chordChartPath="">
|
||||||
|
<array rvXMLIvarName="cues" />
|
||||||
|
<array rvXMLIvarName="displayElements">
|
||||||
|
<RVTextElement displayName="" UUID="4ba2d9c3-9602-4184-aace-05aedd37ad8e" typeID="0" displayDelay="0" locked="false" persistent="0" fromTemplate="false" opacity="1" source="" bezelRadius="0" rotation="0" drawingFill="false" drawingShadow="true" drawingStroke="false" fillColor="0 0 0 0" adjustsHeightToFit="false" verticalAlignment="0" revealType="0">
|
||||||
|
<RVRect3D rvXMLIvarName="position">{10 10 0 1004 748}</RVRect3D>
|
||||||
|
<shadow rvXMLIvarName="shadow">0|0 0 0 0|{0, 0}</shadow>
|
||||||
|
<dictionary rvXMLIvarName="stroke">
|
||||||
|
<NSColor rvXMLDictionaryKey="RVShapeElementStrokeColorKey">0 0 0 0</NSColor>
|
||||||
|
<NSNumber rvXMLDictionaryKey="RVShapeElementStrokeWidthKey" hint="double">0</NSNumber>
|
||||||
|
</dictionary>
|
||||||
|
<NSString rvXMLIvarName="PlainText">QW5kIGdyYWNlIHdpbGwgbGVhZCBtZSBob21lLg==</NSString>
|
||||||
|
<NSString rvXMLIvarName="RTFData">e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBBbmQgZ3JhY2Ugd2lsbCBsZWFkIG1lIGhvbWUufVxsaTBcc2EwXHNiMFxmaTBccWNccGFyfQ0KfQ0KfQ==</NSString>
|
||||||
|
<NSString rvXMLIvarName="WinFlowData">PEZsb3dEb2N1bWVudCBUZXh0QWxpZ25tZW50PSJMZWZ0IiB4bWxucz0iaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS93aW5meC8yMDA2L3hhbWwvcHJlc2VudGF0aW9uIj48UGFyYWdyYXBoIE1hcmdpbj0iMCwwLDAsMCIgVGV4dEFsaWdubWVudD0iQ2VudGVyIiBGb250RmFtaWx5PSJIZWx2ZXRpY2EiIEZvbnRTaXplPSI2MCI+PFNwYW4gRm9yZWdyb3VuZD0iI0ZGRkZGRkZGIiB4bWw6bGFuZz0iZW4tdXMiPjxSdW4gQmxvY2suVGV4dEFsaWdubWVudD0iQ2VudGVyIj5BbmQgZ3JhY2Ugd2lsbCBsZWFkIG1lIGhvbWUuPC9SdW4+PC9TcGFuPjwvUGFyYWdyYXBoPjwvRmxvd0RvY3VtZW50Pg==</NSString>
|
||||||
|
<NSString rvXMLIvarName="WinFontData">PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTE2Ij8+PFJWRm9udCB4bWxuczppPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYS1pbnN0YW5jZSIgeG1sbnM9Imh0dHA6Ly9zY2hlbWFzLmRhdGFjb250cmFjdC5vcmcvMjAwNC8wNy9Qcm9QcmVzZW50ZXIuQ29tbW9uIj48S2VybmluZz4wPC9LZXJuaW5nPjxMaW5lU3BhY2luZz4wPC9MaW5lU3BhY2luZz48T3V0bGluZUNvbG9yIHhtbG5zOmQycDE9Imh0dHA6Ly9zY2hlbWFzLmRhdGFjb250cmFjdC5vcmcvMjAwNC8wNy9TeXN0ZW0uV2luZG93cy5NZWRpYSI+PGQycDE6QT4wPC9kMnAxOkE+PGQycDE6Qj4wPC9kMnAxOkI+PGQycDE6Rz4wPC9kMnAxOkc+PGQycDE6Uj4wPC9kMnAxOlI+PGQycDE6U2NBPjA8L2QycDE6U2NBPjxkMnAxOlNjQj4wPC9kMnAxOlNjQj48ZDJwMTpTY0c+MDwvZDJwMTpTY0c+PGQycDE6U2NSPjA8L2QycDE6U2NSPjwvT3V0bGluZUNvbG9yPjxPdXRsaW5lV2lkdGg+MDwvT3V0bGluZVdpZHRoPjxWYXJpYW50cz5Ob3JtYWw8L1ZhcmlhbnRzPjwvUlZGb250Pg==</NSString>
|
||||||
|
</RVTextElement>
|
||||||
|
</array>
|
||||||
|
</RVDisplaySlide>
|
||||||
|
<RVDisplaySlide backgroundColor="0 0 0 0" highlightColor="0 0 0 0" drawingBackgroundColor="false" enabled="true" hotKey="" label="" notes="" UUID="D5B3DFC2-6C99-447B-A1E9-815F1550397F" chordChartPath="">
|
||||||
|
<array rvXMLIvarName="cues" />
|
||||||
|
<array rvXMLIvarName="displayElements">
|
||||||
|
<RVTextElement displayName="" UUID="89eef5b3-8181-476d-8ea7-c9c599d4d3c4" typeID="0" displayDelay="0" locked="false" persistent="0" fromTemplate="false" opacity="1" source="" bezelRadius="0" rotation="0" drawingFill="false" drawingShadow="true" drawingStroke="false" fillColor="0 0 0 0" adjustsHeightToFit="false" verticalAlignment="0" revealType="0">
|
||||||
|
<RVRect3D rvXMLIvarName="position">{10 10 0 1004 748}</RVRect3D>
|
||||||
|
<shadow rvXMLIvarName="shadow">0|0 0 0 0|{0, 0}</shadow>
|
||||||
|
<dictionary rvXMLIvarName="stroke">
|
||||||
|
<NSColor rvXMLDictionaryKey="RVShapeElementStrokeColorKey">0 0 0 0</NSColor>
|
||||||
|
<NSNumber rvXMLDictionaryKey="RVShapeElementStrokeWidthKey" hint="double">0</NSNumber>
|
||||||
|
</dictionary>
|
||||||
|
<NSString rvXMLIvarName="PlainText">VGhlIExvcmQgaGFzIHByb21pc2VkIGdvb2QgdG8gbWUs</NSString>
|
||||||
|
<NSString rvXMLIvarName="RTFData">e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBUaGUgTG9yZCBoYXMgcHJvbWlzZWQgZ29vZCB0byBtZSx9XGxpMFxzYTBcc2IwXGZpMFxxY1xwYXJ9DQp9DQp9</NSString>
|
||||||
|
<NSString rvXMLIvarName="WinFlowData">PEZsb3dEb2N1bWVudCBUZXh0QWxpZ25tZW50PSJMZWZ0IiB4bWxucz0iaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS93aW5meC8yMDA2L3hhbWwvcHJlc2VudGF0aW9uIj48UGFyYWdyYXBoIE1hcmdpbj0iMCwwLDAsMCIgVGV4dEFsaWdubWVudD0iQ2VudGVyIiBGb250RmFtaWx5PSJIZWx2ZXRpY2EiIEZvbnRTaXplPSI2MCI+PFNwYW4gRm9yZWdyb3VuZD0iI0ZGRkZGRkZGIiB4bWw6bGFuZz0iZW4tdXMiPjxSdW4gQmxvY2suVGV4dEFsaWdubWVudD0iQ2VudGVyIj5UaGUgTG9yZCBoYXMgcHJvbWlzZWQgZ29vZCB0byBtZSw8L1J1bj48L1NwYW4+PC9QYXJhZ3JhcGg+PC9GbG93RG9jdW1lbnQ+</NSString>
|
||||||
|
<NSString rvXMLIvarName="WinFontData">PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTE2Ij8+PFJWRm9udCB4bWxuczppPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYS1pbnN0YW5jZSIgeG1sbnM9Imh0dHA6Ly9zY2hlbWFzLmRhdGFjb250cmFjdC5vcmcvMjAwNC8wNy9Qcm9QcmVzZW50ZXIuQ29tbW9uIj48S2VybmluZz4wPC9LZXJuaW5nPjxMaW5lU3BhY2luZz4wPC9MaW5lU3BhY2luZz48T3V0bGluZUNvbG9yIHhtbG5zOmQycDE9Imh0dHA6Ly9zY2hlbWFzLmRhdGFjb250cmFjdC5vcmcvMjAwNC8wNy9TeXN0ZW0uV2luZG93cy5NZWRpYSI+PGQycDE6QT4wPC9kMnAxOkE+PGQycDE6Qj4wPC9kMnAxOkI+PGQycDE6Rz4wPC9kMnAxOkc+PGQycDE6Uj4wPC9kMnAxOlI+PGQycDE6U2NBPjA8L2QycDE6U2NBPjxkMnAxOlNjQj4wPC9kMnAxOlNjQj48ZDJwMTpTY0c+MDwvZDJwMTpTY0c+PGQycDE6U2NSPjA8L2QycDE6U2NSPjwvT3V0bGluZUNvbG9yPjxPdXRsaW5lV2lkdGg+MDwvT3V0bGluZVdpZHRoPjxWYXJpYW50cz5Ob3JtYWw8L1ZhcmlhbnRzPjwvUlZGb250Pg==</NSString>
|
||||||
|
</RVTextElement>
|
||||||
|
</array>
|
||||||
|
</RVDisplaySlide>
|
||||||
|
<RVDisplaySlide backgroundColor="0 0 0 0" highlightColor="0 0 0 0" drawingBackgroundColor="false" enabled="true" hotKey="" label="" notes="" UUID="E1573057-DB07-4442-BDCD-1C44B5B62A60" chordChartPath="">
|
||||||
|
<array rvXMLIvarName="cues" />
|
||||||
|
<array rvXMLIvarName="displayElements">
|
||||||
|
<RVTextElement displayName="" UUID="8c5af8ec-2958-4d10-890d-f0b29e4bfac5" typeID="0" displayDelay="0" locked="false" persistent="0" fromTemplate="false" opacity="1" source="" bezelRadius="0" rotation="0" drawingFill="false" drawingShadow="true" drawingStroke="false" fillColor="0 0 0 0" adjustsHeightToFit="false" verticalAlignment="0" revealType="0">
|
||||||
|
<RVRect3D rvXMLIvarName="position">{10 10 0 1004 748}</RVRect3D>
|
||||||
|
<shadow rvXMLIvarName="shadow">0|0 0 0 0|{0, 0}</shadow>
|
||||||
|
<dictionary rvXMLIvarName="stroke">
|
||||||
|
<NSColor rvXMLDictionaryKey="RVShapeElementStrokeColorKey">0 0 0 0</NSColor>
|
||||||
|
<NSNumber rvXMLDictionaryKey="RVShapeElementStrokeWidthKey" hint="double">0</NSNumber>
|
||||||
|
</dictionary>
|
||||||
|
<NSString rvXMLIvarName="PlainText">SGlzIFdvcmQgbXkgaG9wZSBzZWN1cmVzOw==</NSString>
|
||||||
|
<NSString rvXMLIvarName="RTFData">e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBIaXMgV29yZCBteSBob3BlIHNlY3VyZXM7fVxsaTBcc2EwXHNiMFxmaTBccWNccGFyfQ0KfQ0KfQ==</NSString>
|
||||||
|
<NSString rvXMLIvarName="WinFlowData">PEZsb3dEb2N1bWVudCBUZXh0QWxpZ25tZW50PSJMZWZ0IiB4bWxucz0iaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS93aW5meC8yMDA2L3hhbWwvcHJlc2VudGF0aW9uIj48UGFyYWdyYXBoIE1hcmdpbj0iMCwwLDAsMCIgVGV4dEFsaWdubWVudD0iQ2VudGVyIiBGb250RmFtaWx5PSJIZWx2ZXRpY2EiIEZvbnRTaXplPSI2MCI+PFNwYW4gRm9yZWdyb3VuZD0iI0ZGRkZGRkZGIiB4bWw6bGFuZz0iZW4tdXMiPjxSdW4gQmxvY2suVGV4dEFsaWdubWVudD0iQ2VudGVyIj5IaXMgV29yZCBteSBob3BlIHNlY3VyZXM7PC9SdW4+PC9TcGFuPjwvUGFyYWdyYXBoPjwvRmxvd0RvY3VtZW50Pg==</NSString>
|
||||||
|
<NSString rvXMLIvarName="WinFontData">PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTE2Ij8+PFJWRm9udCB4bWxuczppPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYS1pbnN0YW5jZSIgeG1sbnM9Imh0dHA6Ly9zY2hlbWFzLmRhdGFjb250cmFjdC5vcmcvMjAwNC8wNy9Qcm9QcmVzZW50ZXIuQ29tbW9uIj48S2VybmluZz4wPC9LZXJuaW5nPjxMaW5lU3BhY2luZz4wPC9MaW5lU3BhY2luZz48T3V0bGluZUNvbG9yIHhtbG5zOmQycDE9Imh0dHA6Ly9zY2hlbWFzLmRhdGFjb250cmFjdC5vcmcvMjAwNC8wNy9TeXN0ZW0uV2luZG93cy5NZWRpYSI+PGQycDE6QT4wPC9kMnAxOkE+PGQycDE6Qj4wPC9kMnAxOkI+PGQycDE6Rz4wPC9kMnAxOkc+PGQycDE6Uj4wPC9kMnAxOlI+PGQycDE6U2NBPjA8L2QycDE6U2NBPjxkMnAxOlNjQj4wPC9kMnAxOlNjQj48ZDJwMTpTY0c+MDwvZDJwMTpTY0c+PGQycDE6U2NSPjA8L2QycDE6U2NSPjwvT3V0bGluZUNvbG9yPjxPdXRsaW5lV2lkdGg+MDwvT3V0bGluZVdpZHRoPjxWYXJpYW50cz5Ob3JtYWw8L1ZhcmlhbnRzPjwvUlZGb250Pg==</NSString>
|
||||||
|
</RVTextElement>
|
||||||
|
</array>
|
||||||
|
</RVDisplaySlide>
|
||||||
|
<RVDisplaySlide backgroundColor="0 0 0 0" highlightColor="0 0 0 0" drawingBackgroundColor="false" enabled="true" hotKey="" label="" notes="" UUID="D07DB5AA-710D-40F5-8FF0-C336B7C99B29" chordChartPath="">
|
||||||
|
<array rvXMLIvarName="cues" />
|
||||||
|
<array rvXMLIvarName="displayElements">
|
||||||
|
<RVTextElement displayName="" UUID="0f938212-27d8-465b-b05f-f71c8ef4820a" typeID="0" displayDelay="0" locked="false" persistent="0" fromTemplate="false" opacity="1" source="" bezelRadius="0" rotation="0" drawingFill="false" drawingShadow="true" drawingStroke="false" fillColor="0 0 0 0" adjustsHeightToFit="false" verticalAlignment="0" revealType="0">
|
||||||
|
<RVRect3D rvXMLIvarName="position">{10 10 0 1004 748}</RVRect3D>
|
||||||
|
<shadow rvXMLIvarName="shadow">0|0 0 0 0|{0, 0}</shadow>
|
||||||
|
<dictionary rvXMLIvarName="stroke">
|
||||||
|
<NSColor rvXMLDictionaryKey="RVShapeElementStrokeColorKey">0 0 0 0</NSColor>
|
||||||
|
<NSNumber rvXMLDictionaryKey="RVShapeElementStrokeWidthKey" hint="double">0</NSNumber>
|
||||||
|
</dictionary>
|
||||||
|
<NSString rvXMLIvarName="PlainText">SGUgd2lsbCBteSBTaGllbGQgYW5kIFBvcnRpb24gYmUs</NSString>
|
||||||
|
<NSString rvXMLIvarName="RTFData">e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBIZSB3aWxsIG15IFNoaWVsZCBhbmQgUG9ydGlvbiBiZSx9XGxpMFxzYTBcc2IwXGZpMFxxY1xwYXJ9DQp9DQp9</NSString>
|
||||||
|
<NSString rvXMLIvarName="WinFlowData">PEZsb3dEb2N1bWVudCBUZXh0QWxpZ25tZW50PSJMZWZ0IiB4bWxucz0iaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS93aW5meC8yMDA2L3hhbWwvcHJlc2VudGF0aW9uIj48UGFyYWdyYXBoIE1hcmdpbj0iMCwwLDAsMCIgVGV4dEFsaWdubWVudD0iQ2VudGVyIiBGb250RmFtaWx5PSJIZWx2ZXRpY2EiIEZvbnRTaXplPSI2MCI+PFNwYW4gRm9yZWdyb3VuZD0iI0ZGRkZGRkZGIiB4bWw6bGFuZz0iZW4tdXMiPjxSdW4gQmxvY2suVGV4dEFsaWdubWVudD0iQ2VudGVyIj5IZSB3aWxsIG15IFNoaWVsZCBhbmQgUG9ydGlvbiBiZSw8L1J1bj48L1NwYW4+PC9QYXJhZ3JhcGg+PC9GbG93RG9jdW1lbnQ+</NSString>
|
||||||
|
<NSString rvXMLIvarName="WinFontData">PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTE2Ij8+PFJWRm9udCB4bWxuczppPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYS1pbnN0YW5jZSIgeG1sbnM9Imh0dHA6Ly9zY2hlbWFzLmRhdGFjb250cmFjdC5vcmcvMjAwNC8wNy9Qcm9QcmVzZW50ZXIuQ29tbW9uIj48S2VybmluZz4wPC9LZXJuaW5nPjxMaW5lU3BhY2luZz4wPC9MaW5lU3BhY2luZz48T3V0bGluZUNvbG9yIHhtbG5zOmQycDE9Imh0dHA6Ly9zY2hlbWFzLmRhdGFjb250cmFjdC5vcmcvMjAwNC8wNy9TeXN0ZW0uV2luZG93cy5NZWRpYSI+PGQycDE6QT4wPC9kMnAxOkE+PGQycDE6Qj4wPC9kMnAxOkI+PGQycDE6Rz4wPC9kMnAxOkc+PGQycDE6Uj4wPC9kMnAxOlI+PGQycDE6U2NBPjA8L2QycDE6U2NBPjxkMnAxOlNjQj4wPC9kMnAxOlNjQj48ZDJwMTpTY0c+MDwvZDJwMTpTY0c+PGQycDE6U2NSPjA8L2QycDE6U2NSPjwvT3V0bGluZUNvbG9yPjxPdXRsaW5lV2lkdGg+MDwvT3V0bGluZVdpZHRoPjxWYXJpYW50cz5Ob3JtYWw8L1ZhcmlhbnRzPjwvUlZGb250Pg==</NSString>
|
||||||
|
</RVTextElement>
|
||||||
|
</array>
|
||||||
|
</RVDisplaySlide>
|
||||||
|
<RVDisplaySlide backgroundColor="0 0 0 0" highlightColor="0 0 0 0" drawingBackgroundColor="false" enabled="true" hotKey="" label="" notes="" UUID="0D91E879-8C6A-4C68-A098-80E95E89F4F7" chordChartPath="">
|
||||||
|
<array rvXMLIvarName="cues" />
|
||||||
|
<array rvXMLIvarName="displayElements">
|
||||||
|
<RVTextElement displayName="" UUID="8b858c7c-7c6c-4885-9fea-59ba66e30e74" typeID="0" displayDelay="0" locked="false" persistent="0" fromTemplate="false" opacity="1" source="" bezelRadius="0" rotation="0" drawingFill="false" drawingShadow="true" drawingStroke="false" fillColor="0 0 0 0" adjustsHeightToFit="false" verticalAlignment="0" revealType="0">
|
||||||
|
<RVRect3D rvXMLIvarName="position">{10 10 0 1004 748}</RVRect3D>
|
||||||
|
<shadow rvXMLIvarName="shadow">0|0 0 0 0|{0, 0}</shadow>
|
||||||
|
<dictionary rvXMLIvarName="stroke">
|
||||||
|
<NSColor rvXMLDictionaryKey="RVShapeElementStrokeColorKey">0 0 0 0</NSColor>
|
||||||
|
<NSNumber rvXMLDictionaryKey="RVShapeElementStrokeWidthKey" hint="double">0</NSNumber>
|
||||||
|
</dictionary>
|
||||||
|
<NSString rvXMLIvarName="PlainText">QXMgbG9uZyBhcyBsaWZlIGVuZHVyZXMu</NSString>
|
||||||
|
<NSString rvXMLIvarName="RTFData">e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBBcyBsb25nIGFzIGxpZmUgZW5kdXJlcy59XGxpMFxzYTBcc2IwXGZpMFxxY1xwYXJ9DQp9DQp9</NSString>
|
||||||
|
<NSString rvXMLIvarName="WinFlowData">PEZsb3dEb2N1bWVudCBUZXh0QWxpZ25tZW50PSJMZWZ0IiB4bWxucz0iaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS93aW5meC8yMDA2L3hhbWwvcHJlc2VudGF0aW9uIj48UGFyYWdyYXBoIE1hcmdpbj0iMCwwLDAsMCIgVGV4dEFsaWdubWVudD0iQ2VudGVyIiBGb250RmFtaWx5PSJIZWx2ZXRpY2EiIEZvbnRTaXplPSI2MCI+PFNwYW4gRm9yZWdyb3VuZD0iI0ZGRkZGRkZGIiB4bWw6bGFuZz0iZW4tdXMiPjxSdW4gQmxvY2suVGV4dEFsaWdubWVudD0iQ2VudGVyIj5BcyBsb25nIGFzIGxpZmUgZW5kdXJlcy48L1J1bj48L1NwYW4+PC9QYXJhZ3JhcGg+PC9GbG93RG9jdW1lbnQ+</NSString>
|
||||||
|
<NSString rvXMLIvarName="WinFontData">PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTE2Ij8+PFJWRm9udCB4bWxuczppPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYS1pbnN0YW5jZSIgeG1sbnM9Imh0dHA6Ly9zY2hlbWFzLmRhdGFjb250cmFjdC5vcmcvMjAwNC8wNy9Qcm9QcmVzZW50ZXIuQ29tbW9uIj48S2VybmluZz4wPC9LZXJuaW5nPjxMaW5lU3BhY2luZz4wPC9MaW5lU3BhY2luZz48T3V0bGluZUNvbG9yIHhtbG5zOmQycDE9Imh0dHA6Ly9zY2hlbWFzLmRhdGFjb250cmFjdC5vcmcvMjAwNC8wNy9TeXN0ZW0uV2luZG93cy5NZWRpYSI+PGQycDE6QT4wPC9kMnAxOkE+PGQycDE6Qj4wPC9kMnAxOkI+PGQycDE6Rz4wPC9kMnAxOkc+PGQycDE6Uj4wPC9kMnAxOlI+PGQycDE6U2NBPjA8L2QycDE6U2NBPjxkMnAxOlNjQj4wPC9kMnAxOlNjQj48ZDJwMTpTY0c+MDwvZDJwMTpTY0c+PGQycDE6U2NSPjA8L2QycDE6U2NSPjwvT3V0bGluZUNvbG9yPjxPdXRsaW5lV2lkdGg+MDwvT3V0bGluZVdpZHRoPjxWYXJpYW50cz5Ob3JtYWw8L1ZhcmlhbnRzPjwvUlZGb250Pg==</NSString>
|
||||||
|
</RVTextElement>
|
||||||
|
</array>
|
||||||
|
</RVDisplaySlide>
|
||||||
|
<RVDisplaySlide backgroundColor="0 0 0 0" highlightColor="0 0 0 0" drawingBackgroundColor="false" enabled="true" hotKey="" label="" notes="" UUID="5105264F-D786-453E-8D29-3ADC8D84C53F" chordChartPath="">
|
||||||
|
<array rvXMLIvarName="cues" />
|
||||||
|
<array rvXMLIvarName="displayElements">
|
||||||
|
<RVTextElement displayName="" UUID="3325a6b6-e38f-4fe8-b9bd-7dcc2b5dfed7" typeID="0" displayDelay="0" locked="false" persistent="0" fromTemplate="false" opacity="1" source="" bezelRadius="0" rotation="0" drawingFill="false" drawingShadow="true" drawingStroke="false" fillColor="0 0 0 0" adjustsHeightToFit="false" verticalAlignment="0" revealType="0">
|
||||||
|
<RVRect3D rvXMLIvarName="position">{10 10 0 1004 748}</RVRect3D>
|
||||||
|
<shadow rvXMLIvarName="shadow">0|0 0 0 0|{0, 0}</shadow>
|
||||||
|
<dictionary rvXMLIvarName="stroke">
|
||||||
|
<NSColor rvXMLDictionaryKey="RVShapeElementStrokeColorKey">0 0 0 0</NSColor>
|
||||||
|
<NSNumber rvXMLDictionaryKey="RVShapeElementStrokeWidthKey" hint="double">0</NSNumber>
|
||||||
|
</dictionary>
|
||||||
|
<NSString rvXMLIvarName="PlainText">WWVhLCB3aGVuIHRoaXMgZmxlc2ggYW5kIGhlYXJ0IHNoYWxsIGZhaWws</NSString>
|
||||||
|
<NSString rvXMLIvarName="RTFData">e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBZZWEsIHdoZW4gdGhpcyBmbGVzaCBhbmQgaGVhcnQgc2hhbGwgZmFpbCx9XGxpMFxzYTBcc2IwXGZpMFxxY1xwYXJ9DQp9DQp9</NSString>
|
||||||
|
<NSString rvXMLIvarName="WinFlowData">PEZsb3dEb2N1bWVudCBUZXh0QWxpZ25tZW50PSJMZWZ0IiB4bWxucz0iaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS93aW5meC8yMDA2L3hhbWwvcHJlc2VudGF0aW9uIj48UGFyYWdyYXBoIE1hcmdpbj0iMCwwLDAsMCIgVGV4dEFsaWdubWVudD0iQ2VudGVyIiBGb250RmFtaWx5PSJIZWx2ZXRpY2EiIEZvbnRTaXplPSI2MCI+PFNwYW4gRm9yZWdyb3VuZD0iI0ZGRkZGRkZGIiB4bWw6bGFuZz0iZW4tdXMiPjxSdW4gQmxvY2suVGV4dEFsaWdubWVudD0iQ2VudGVyIj5ZZWEsIHdoZW4gdGhpcyBmbGVzaCBhbmQgaGVhcnQgc2hhbGwgZmFpbCw8L1J1bj48L1NwYW4+PC9QYXJhZ3JhcGg+PC9GbG93RG9jdW1lbnQ+</NSString>
|
||||||
|
<NSString rvXMLIvarName="WinFontData">PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTE2Ij8+PFJWRm9udCB4bWxuczppPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYS1pbnN0YW5jZSIgeG1sbnM9Imh0dHA6Ly9zY2hlbWFzLmRhdGFjb250cmFjdC5vcmcvMjAwNC8wNy9Qcm9QcmVzZW50ZXIuQ29tbW9uIj48S2VybmluZz4wPC9LZXJuaW5nPjxMaW5lU3BhY2luZz4wPC9MaW5lU3BhY2luZz48T3V0bGluZUNvbG9yIHhtbG5zOmQycDE9Imh0dHA6Ly9zY2hlbWFzLmRhdGFjb250cmFjdC5vcmcvMjAwNC8wNy9TeXN0ZW0uV2luZG93cy5NZWRpYSI+PGQycDE6QT4wPC9kMnAxOkE+PGQycDE6Qj4wPC9kMnAxOkI+PGQycDE6Rz4wPC9kMnAxOkc+PGQycDE6Uj4wPC9kMnAxOlI+PGQycDE6U2NBPjA8L2QycDE6U2NBPjxkMnAxOlNjQj4wPC9kMnAxOlNjQj48ZDJwMTpTY0c+MDwvZDJwMTpTY0c+PGQycDE6U2NSPjA8L2QycDE6U2NSPjwvT3V0bGluZUNvbG9yPjxPdXRsaW5lV2lkdGg+MDwvT3V0bGluZVdpZHRoPjxWYXJpYW50cz5Ob3JtYWw8L1ZhcmlhbnRzPjwvUlZGb250Pg==</NSString>
|
||||||
|
</RVTextElement>
|
||||||
|
</array>
|
||||||
|
</RVDisplaySlide>
|
||||||
|
<RVDisplaySlide backgroundColor="0 0 0 0" highlightColor="0 0 0 0" drawingBackgroundColor="false" enabled="true" hotKey="" label="" notes="" UUID="46D46358-A465-425E-866D-1D5E215952E4" chordChartPath="">
|
||||||
|
<array rvXMLIvarName="cues" />
|
||||||
|
<array rvXMLIvarName="displayElements">
|
||||||
|
<RVTextElement displayName="" UUID="3e10e71a-a978-4f1f-94f1-4e4008d577f8" typeID="0" displayDelay="0" locked="false" persistent="0" fromTemplate="false" opacity="1" source="" bezelRadius="0" rotation="0" drawingFill="false" drawingShadow="true" drawingStroke="false" fillColor="0 0 0 0" adjustsHeightToFit="false" verticalAlignment="0" revealType="0">
|
||||||
|
<RVRect3D rvXMLIvarName="position">{10 10 0 1004 748}</RVRect3D>
|
||||||
|
<shadow rvXMLIvarName="shadow">0|0 0 0 0|{0, 0}</shadow>
|
||||||
|
<dictionary rvXMLIvarName="stroke">
|
||||||
|
<NSColor rvXMLDictionaryKey="RVShapeElementStrokeColorKey">0 0 0 0</NSColor>
|
||||||
|
<NSNumber rvXMLDictionaryKey="RVShapeElementStrokeWidthKey" hint="double">0</NSNumber>
|
||||||
|
</dictionary>
|
||||||
|
<NSString rvXMLIvarName="PlainText">QW5kIG1vcnRhbCBsaWZlIHNoYWxsIGNlYXNlLA==</NSString>
|
||||||
|
<NSString rvXMLIvarName="RTFData">e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBBbmQgbW9ydGFsIGxpZmUgc2hhbGwgY2Vhc2UsfVxsaTBcc2EwXHNiMFxmaTBccWNccGFyfQ0KfQ0KfQ==</NSString>
|
||||||
|
<NSString rvXMLIvarName="WinFlowData">PEZsb3dEb2N1bWVudCBUZXh0QWxpZ25tZW50PSJMZWZ0IiB4bWxucz0iaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS93aW5meC8yMDA2L3hhbWwvcHJlc2VudGF0aW9uIj48UGFyYWdyYXBoIE1hcmdpbj0iMCwwLDAsMCIgVGV4dEFsaWdubWVudD0iQ2VudGVyIiBGb250RmFtaWx5PSJIZWx2ZXRpY2EiIEZvbnRTaXplPSI2MCI+PFNwYW4gRm9yZWdyb3VuZD0iI0ZGRkZGRkZGIiB4bWw6bGFuZz0iZW4tdXMiPjxSdW4gQmxvY2suVGV4dEFsaWdubWVudD0iQ2VudGVyIj5BbmQgbW9ydGFsIGxpZmUgc2hhbGwgY2Vhc2UsPC9SdW4+PC9TcGFuPjwvUGFyYWdyYXBoPjwvRmxvd0RvY3VtZW50Pg==</NSString>
|
||||||
|
<NSString rvXMLIvarName="WinFontData">PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTE2Ij8+PFJWRm9udCB4bWxuczppPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYS1pbnN0YW5jZSIgeG1sbnM9Imh0dHA6Ly9zY2hlbWFzLmRhdGFjb250cmFjdC5vcmcvMjAwNC8wNy9Qcm9QcmVzZW50ZXIuQ29tbW9uIj48S2VybmluZz4wPC9LZXJuaW5nPjxMaW5lU3BhY2luZz4wPC9MaW5lU3BhY2luZz48T3V0bGluZUNvbG9yIHhtbG5zOmQycDE9Imh0dHA6Ly9zY2hlbWFzLmRhdGFjb250cmFjdC5vcmcvMjAwNC8wNy9TeXN0ZW0uV2luZG93cy5NZWRpYSI+PGQycDE6QT4wPC9kMnAxOkE+PGQycDE6Qj4wPC9kMnAxOkI+PGQycDE6Rz4wPC9kMnAxOkc+PGQycDE6Uj4wPC9kMnAxOlI+PGQycDE6U2NBPjA8L2QycDE6U2NBPjxkMnAxOlNjQj4wPC9kMnAxOlNjQj48ZDJwMTpTY0c+MDwvZDJwMTpTY0c+PGQycDE6U2NSPjA8L2QycDE6U2NSPjwvT3V0bGluZUNvbG9yPjxPdXRsaW5lV2lkdGg+MDwvT3V0bGluZVdpZHRoPjxWYXJpYW50cz5Ob3JtYWw8L1ZhcmlhbnRzPjwvUlZGb250Pg==</NSString>
|
||||||
|
</RVTextElement>
|
||||||
|
</array>
|
||||||
|
</RVDisplaySlide>
|
||||||
|
<RVDisplaySlide backgroundColor="0 0 0 0" highlightColor="0 0 0 0" drawingBackgroundColor="false" enabled="true" hotKey="" label="" notes="" UUID="8B92AC4F-1470-416E-80CA-E088EF6F3AC4" chordChartPath="">
|
||||||
|
<array rvXMLIvarName="cues" />
|
||||||
|
<array rvXMLIvarName="displayElements">
|
||||||
|
<RVTextElement displayName="" UUID="4fd649f2-e48b-486b-a484-7ac375e4081a" typeID="0" displayDelay="0" locked="false" persistent="0" fromTemplate="false" opacity="1" source="" bezelRadius="0" rotation="0" drawingFill="false" drawingShadow="true" drawingStroke="false" fillColor="0 0 0 0" adjustsHeightToFit="false" verticalAlignment="0" revealType="0">
|
||||||
|
<RVRect3D rvXMLIvarName="position">{10 10 0 1004 748}</RVRect3D>
|
||||||
|
<shadow rvXMLIvarName="shadow">0|0 0 0 0|{0, 0}</shadow>
|
||||||
|
<dictionary rvXMLIvarName="stroke">
|
||||||
|
<NSColor rvXMLDictionaryKey="RVShapeElementStrokeColorKey">0 0 0 0</NSColor>
|
||||||
|
<NSNumber rvXMLDictionaryKey="RVShapeElementStrokeWidthKey" hint="double">0</NSNumber>
|
||||||
|
</dictionary>
|
||||||
|
<NSString rvXMLIvarName="PlainText">SSBzaGFsbCBwb3NzZXNzLCB3aXRoaW4gdGhlIHZlaWws</NSString>
|
||||||
|
<NSString rvXMLIvarName="RTFData">e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBJIHNoYWxsIHBvc3Nlc3MsIHdpdGhpbiB0aGUgdmVpbCx9XGxpMFxzYTBcc2IwXGZpMFxxY1xwYXJ9DQp9DQp9</NSString>
|
||||||
|
<NSString rvXMLIvarName="WinFlowData">PEZsb3dEb2N1bWVudCBUZXh0QWxpZ25tZW50PSJMZWZ0IiB4bWxucz0iaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS93aW5meC8yMDA2L3hhbWwvcHJlc2VudGF0aW9uIj48UGFyYWdyYXBoIE1hcmdpbj0iMCwwLDAsMCIgVGV4dEFsaWdubWVudD0iQ2VudGVyIiBGb250RmFtaWx5PSJIZWx2ZXRpY2EiIEZvbnRTaXplPSI2MCI+PFNwYW4gRm9yZWdyb3VuZD0iI0ZGRkZGRkZGIiB4bWw6bGFuZz0iZW4tdXMiPjxSdW4gQmxvY2suVGV4dEFsaWdubWVudD0iQ2VudGVyIj5JIHNoYWxsIHBvc3Nlc3MsIHdpdGhpbiB0aGUgdmVpbCw8L1J1bj48L1NwYW4+PC9QYXJhZ3JhcGg+PC9GbG93RG9jdW1lbnQ+</NSString>
|
||||||
|
<NSString rvXMLIvarName="WinFontData">PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTE2Ij8+PFJWRm9udCB4bWxuczppPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYS1pbnN0YW5jZSIgeG1sbnM9Imh0dHA6Ly9zY2hlbWFzLmRhdGFjb250cmFjdC5vcmcvMjAwNC8wNy9Qcm9QcmVzZW50ZXIuQ29tbW9uIj48S2VybmluZz4wPC9LZXJuaW5nPjxMaW5lU3BhY2luZz4wPC9MaW5lU3BhY2luZz48T3V0bGluZUNvbG9yIHhtbG5zOmQycDE9Imh0dHA6Ly9zY2hlbWFzLmRhdGFjb250cmFjdC5vcmcvMjAwNC8wNy9TeXN0ZW0uV2luZG93cy5NZWRpYSI+PGQycDE6QT4wPC9kMnAxOkE+PGQycDE6Qj4wPC9kMnAxOkI+PGQycDE6Rz4wPC9kMnAxOkc+PGQycDE6Uj4wPC9kMnAxOlI+PGQycDE6U2NBPjA8L2QycDE6U2NBPjxkMnAxOlNjQj4wPC9kMnAxOlNjQj48ZDJwMTpTY0c+MDwvZDJwMTpTY0c+PGQycDE6U2NSPjA8L2QycDE6U2NSPjwvT3V0bGluZUNvbG9yPjxPdXRsaW5lV2lkdGg+MDwvT3V0bGluZVdpZHRoPjxWYXJpYW50cz5Ob3JtYWw8L1ZhcmlhbnRzPjwvUlZGb250Pg==</NSString>
|
||||||
|
</RVTextElement>
|
||||||
|
</array>
|
||||||
|
</RVDisplaySlide>
|
||||||
|
<RVDisplaySlide backgroundColor="0 0 0 0" highlightColor="0 0 0 0" drawingBackgroundColor="false" enabled="true" hotKey="" label="" notes="" UUID="D0865E31-B064-4817-B027-A35C231D4946" chordChartPath="">
|
||||||
|
<array rvXMLIvarName="cues" />
|
||||||
|
<array rvXMLIvarName="displayElements">
|
||||||
|
<RVTextElement displayName="" UUID="fdb7bb58-139f-43eb-802c-14d9563f296c" typeID="0" displayDelay="0" locked="false" persistent="0" fromTemplate="false" opacity="1" source="" bezelRadius="0" rotation="0" drawingFill="false" drawingShadow="true" drawingStroke="false" fillColor="0 0 0 0" adjustsHeightToFit="false" verticalAlignment="0" revealType="0">
|
||||||
|
<RVRect3D rvXMLIvarName="position">{10 10 0 1004 748}</RVRect3D>
|
||||||
|
<shadow rvXMLIvarName="shadow">0|0 0 0 0|{0, 0}</shadow>
|
||||||
|
<dictionary rvXMLIvarName="stroke">
|
||||||
|
<NSColor rvXMLDictionaryKey="RVShapeElementStrokeColorKey">0 0 0 0</NSColor>
|
||||||
|
<NSNumber rvXMLDictionaryKey="RVShapeElementStrokeWidthKey" hint="double">0</NSNumber>
|
||||||
|
</dictionary>
|
||||||
|
<NSString rvXMLIvarName="PlainText">QSBsaWZlIG9mIGpveSBhbmQgcGVhY2Uu</NSString>
|
||||||
|
<NSString rvXMLIvarName="RTFData">e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBBIGxpZmUgb2Ygam95IGFuZCBwZWFjZS59XGxpMFxzYTBcc2IwXGZpMFxxY1xwYXJ9DQp9DQp9</NSString>
|
||||||
|
<NSString rvXMLIvarName="WinFlowData">PEZsb3dEb2N1bWVudCBUZXh0QWxpZ25tZW50PSJMZWZ0IiB4bWxucz0iaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS93aW5meC8yMDA2L3hhbWwvcHJlc2VudGF0aW9uIj48UGFyYWdyYXBoIE1hcmdpbj0iMCwwLDAsMCIgVGV4dEFsaWdubWVudD0iQ2VudGVyIiBGb250RmFtaWx5PSJIZWx2ZXRpY2EiIEZvbnRTaXplPSI2MCI+PFNwYW4gRm9yZWdyb3VuZD0iI0ZGRkZGRkZGIiB4bWw6bGFuZz0iZW4tdXMiPjxSdW4gQmxvY2suVGV4dEFsaWdubWVudD0iQ2VudGVyIj5BIGxpZmUgb2Ygam95IGFuZCBwZWFjZS48L1J1bj48L1NwYW4+PC9QYXJhZ3JhcGg+PC9GbG93RG9jdW1lbnQ+</NSString>
|
||||||
|
<NSString rvXMLIvarName="WinFontData">PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTE2Ij8+PFJWRm9udCB4bWxuczppPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYS1pbnN0YW5jZSIgeG1sbnM9Imh0dHA6Ly9zY2hlbWFzLmRhdGFjb250cmFjdC5vcmcvMjAwNC8wNy9Qcm9QcmVzZW50ZXIuQ29tbW9uIj48S2VybmluZz4wPC9LZXJuaW5nPjxMaW5lU3BhY2luZz4wPC9MaW5lU3BhY2luZz48T3V0bGluZUNvbG9yIHhtbG5zOmQycDE9Imh0dHA6Ly9zY2hlbWFzLmRhdGFjb250cmFjdC5vcmcvMjAwNC8wNy9TeXN0ZW0uV2luZG93cy5NZWRpYSI+PGQycDE6QT4wPC9kMnAxOkE+PGQycDE6Qj4wPC9kMnAxOkI+PGQycDE6Rz4wPC9kMnAxOkc+PGQycDE6Uj4wPC9kMnAxOlI+PGQycDE6U2NBPjA8L2QycDE6U2NBPjxkMnAxOlNjQj4wPC9kMnAxOlNjQj48ZDJwMTpTY0c+MDwvZDJwMTpTY0c+PGQycDE6U2NSPjA8L2QycDE6U2NSPjwvT3V0bGluZUNvbG9yPjxPdXRsaW5lV2lkdGg+MDwvT3V0bGluZVdpZHRoPjxWYXJpYW50cz5Ob3JtYWw8L1ZhcmlhbnRzPjwvUlZGb250Pg==</NSString>
|
||||||
|
</RVTextElement>
|
||||||
|
</array>
|
||||||
|
</RVDisplaySlide>
|
||||||
|
<RVDisplaySlide backgroundColor="0 0 0 0" highlightColor="0 0 0 0" drawingBackgroundColor="false" enabled="true" hotKey="" label="" notes="" UUID="28AC1D6E-1F79-4E88-80A4-CA318A634046" chordChartPath="">
|
||||||
|
<array rvXMLIvarName="cues" />
|
||||||
|
<array rvXMLIvarName="displayElements">
|
||||||
|
<RVTextElement displayName="" UUID="d6da398f-e918-4f1f-b567-d71e1aa23565" typeID="0" displayDelay="0" locked="false" persistent="0" fromTemplate="false" opacity="1" source="" bezelRadius="0" rotation="0" drawingFill="false" drawingShadow="true" drawingStroke="false" fillColor="0 0 0 0" adjustsHeightToFit="false" verticalAlignment="0" revealType="0">
|
||||||
|
<RVRect3D rvXMLIvarName="position">{10 10 0 1004 748}</RVRect3D>
|
||||||
|
<shadow rvXMLIvarName="shadow">0|0 0 0 0|{0, 0}</shadow>
|
||||||
|
<dictionary rvXMLIvarName="stroke">
|
||||||
|
<NSColor rvXMLDictionaryKey="RVShapeElementStrokeColorKey">0 0 0 0</NSColor>
|
||||||
|
<NSNumber rvXMLDictionaryKey="RVShapeElementStrokeWidthKey" hint="double">0</NSNumber>
|
||||||
|
</dictionary>
|
||||||
|
<NSString rvXMLIvarName="PlainText">VGhlIGVhcnRoIHNoYWxsIHNvb24gZGlzc29sdmUgbGlrZSBzbm93LA==</NSString>
|
||||||
|
<NSString rvXMLIvarName="RTFData">e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBUaGUgZWFydGggc2hhbGwgc29vbiBkaXNzb2x2ZSBsaWtlIHNub3csfVxsaTBcc2EwXHNiMFxmaTBccWNccGFyfQ0KfQ0KfQ==</NSString>
|
||||||
|
<NSString rvXMLIvarName="WinFlowData">PEZsb3dEb2N1bWVudCBUZXh0QWxpZ25tZW50PSJMZWZ0IiB4bWxucz0iaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS93aW5meC8yMDA2L3hhbWwvcHJlc2VudGF0aW9uIj48UGFyYWdyYXBoIE1hcmdpbj0iMCwwLDAsMCIgVGV4dEFsaWdubWVudD0iQ2VudGVyIiBGb250RmFtaWx5PSJIZWx2ZXRpY2EiIEZvbnRTaXplPSI2MCI+PFNwYW4gRm9yZWdyb3VuZD0iI0ZGRkZGRkZGIiB4bWw6bGFuZz0iZW4tdXMiPjxSdW4gQmxvY2suVGV4dEFsaWdubWVudD0iQ2VudGVyIj5UaGUgZWFydGggc2hhbGwgc29vbiBkaXNzb2x2ZSBsaWtlIHNub3csPC9SdW4+PC9TcGFuPjwvUGFyYWdyYXBoPjwvRmxvd0RvY3VtZW50Pg==</NSString>
|
||||||
|
<NSString rvXMLIvarName="WinFontData">PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTE2Ij8+PFJWRm9udCB4bWxuczppPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYS1pbnN0YW5jZSIgeG1sbnM9Imh0dHA6Ly9zY2hlbWFzLmRhdGFjb250cmFjdC5vcmcvMjAwNC8wNy9Qcm9QcmVzZW50ZXIuQ29tbW9uIj48S2VybmluZz4wPC9LZXJuaW5nPjxMaW5lU3BhY2luZz4wPC9MaW5lU3BhY2luZz48T3V0bGluZUNvbG9yIHhtbG5zOmQycDE9Imh0dHA6Ly9zY2hlbWFzLmRhdGFjb250cmFjdC5vcmcvMjAwNC8wNy9TeXN0ZW0uV2luZG93cy5NZWRpYSI+PGQycDE6QT4wPC9kMnAxOkE+PGQycDE6Qj4wPC9kMnAxOkI+PGQycDE6Rz4wPC9kMnAxOkc+PGQycDE6Uj4wPC9kMnAxOlI+PGQycDE6U2NBPjA8L2QycDE6U2NBPjxkMnAxOlNjQj4wPC9kMnAxOlNjQj48ZDJwMTpTY0c+MDwvZDJwMTpTY0c+PGQycDE6U2NSPjA8L2QycDE6U2NSPjwvT3V0bGluZUNvbG9yPjxPdXRsaW5lV2lkdGg+MDwvT3V0bGluZVdpZHRoPjxWYXJpYW50cz5Ob3JtYWw8L1ZhcmlhbnRzPjwvUlZGb250Pg==</NSString>
|
||||||
|
</RVTextElement>
|
||||||
|
</array>
|
||||||
|
</RVDisplaySlide>
|
||||||
|
<RVDisplaySlide backgroundColor="0 0 0 0" highlightColor="0 0 0 0" drawingBackgroundColor="false" enabled="true" hotKey="" label="" notes="" UUID="3E97F36D-D9CE-4C2B-AE1A-D337A43FD7F5" chordChartPath="">
|
||||||
|
<array rvXMLIvarName="cues" />
|
||||||
|
<array rvXMLIvarName="displayElements">
|
||||||
|
<RVTextElement displayName="" UUID="1fb46c81-2579-464c-8657-b6cf2326e1f8" typeID="0" displayDelay="0" locked="false" persistent="0" fromTemplate="false" opacity="1" source="" bezelRadius="0" rotation="0" drawingFill="false" drawingShadow="true" drawingStroke="false" fillColor="0 0 0 0" adjustsHeightToFit="false" verticalAlignment="0" revealType="0">
|
||||||
|
<RVRect3D rvXMLIvarName="position">{10 10 0 1004 748}</RVRect3D>
|
||||||
|
<shadow rvXMLIvarName="shadow">0|0 0 0 0|{0, 0}</shadow>
|
||||||
|
<dictionary rvXMLIvarName="stroke">
|
||||||
|
<NSColor rvXMLDictionaryKey="RVShapeElementStrokeColorKey">0 0 0 0</NSColor>
|
||||||
|
<NSNumber rvXMLDictionaryKey="RVShapeElementStrokeWidthKey" hint="double">0</NSNumber>
|
||||||
|
</dictionary>
|
||||||
|
<NSString rvXMLIvarName="PlainText">VGhlIHN1biBmb3JiZWFyIHRvIHNoaW5lOw==</NSString>
|
||||||
|
<NSString rvXMLIvarName="RTFData">e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBUaGUgc3VuIGZvcmJlYXIgdG8gc2hpbmU7fVxsaTBcc2EwXHNiMFxmaTBccWNccGFyfQ0KfQ0KfQ==</NSString>
|
||||||
|
<NSString rvXMLIvarName="WinFlowData">PEZsb3dEb2N1bWVudCBUZXh0QWxpZ25tZW50PSJMZWZ0IiB4bWxucz0iaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS93aW5meC8yMDA2L3hhbWwvcHJlc2VudGF0aW9uIj48UGFyYWdyYXBoIE1hcmdpbj0iMCwwLDAsMCIgVGV4dEFsaWdubWVudD0iQ2VudGVyIiBGb250RmFtaWx5PSJIZWx2ZXRpY2EiIEZvbnRTaXplPSI2MCI+PFNwYW4gRm9yZWdyb3VuZD0iI0ZGRkZGRkZGIiB4bWw6bGFuZz0iZW4tdXMiPjxSdW4gQmxvY2suVGV4dEFsaWdubWVudD0iQ2VudGVyIj5UaGUgc3VuIGZvcmJlYXIgdG8gc2hpbmU7PC9SdW4+PC9TcGFuPjwvUGFyYWdyYXBoPjwvRmxvd0RvY3VtZW50Pg==</NSString>
|
||||||
|
<NSString rvXMLIvarName="WinFontData">PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTE2Ij8+PFJWRm9udCB4bWxuczppPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYS1pbnN0YW5jZSIgeG1sbnM9Imh0dHA6Ly9zY2hlbWFzLmRhdGFjb250cmFjdC5vcmcvMjAwNC8wNy9Qcm9QcmVzZW50ZXIuQ29tbW9uIj48S2VybmluZz4wPC9LZXJuaW5nPjxMaW5lU3BhY2luZz4wPC9MaW5lU3BhY2luZz48T3V0bGluZUNvbG9yIHhtbG5zOmQycDE9Imh0dHA6Ly9zY2hlbWFzLmRhdGFjb250cmFjdC5vcmcvMjAwNC8wNy9TeXN0ZW0uV2luZG93cy5NZWRpYSI+PGQycDE6QT4wPC9kMnAxOkE+PGQycDE6Qj4wPC9kMnAxOkI+PGQycDE6Rz4wPC9kMnAxOkc+PGQycDE6Uj4wPC9kMnAxOlI+PGQycDE6U2NBPjA8L2QycDE6U2NBPjxkMnAxOlNjQj4wPC9kMnAxOlNjQj48ZDJwMTpTY0c+MDwvZDJwMTpTY0c+PGQycDE6U2NSPjA8L2QycDE6U2NSPjwvT3V0bGluZUNvbG9yPjxPdXRsaW5lV2lkdGg+MDwvT3V0bGluZVdpZHRoPjxWYXJpYW50cz5Ob3JtYWw8L1ZhcmlhbnRzPjwvUlZGb250Pg==</NSString>
|
||||||
|
</RVTextElement>
|
||||||
|
</array>
|
||||||
|
</RVDisplaySlide>
|
||||||
|
<RVDisplaySlide backgroundColor="0 0 0 0" highlightColor="0 0 0 0" drawingBackgroundColor="false" enabled="true" hotKey="" label="" notes="" UUID="81E336F4-7170-47B0-B829-4E4A945A755F" chordChartPath="">
|
||||||
|
<array rvXMLIvarName="cues" />
|
||||||
|
<array rvXMLIvarName="displayElements">
|
||||||
|
<RVTextElement displayName="" UUID="e5fda7b6-b325-4425-85b2-be237bf69906" typeID="0" displayDelay="0" locked="false" persistent="0" fromTemplate="false" opacity="1" source="" bezelRadius="0" rotation="0" drawingFill="false" drawingShadow="true" drawingStroke="false" fillColor="0 0 0 0" adjustsHeightToFit="false" verticalAlignment="0" revealType="0">
|
||||||
|
<RVRect3D rvXMLIvarName="position">{10 10 0 1004 748}</RVRect3D>
|
||||||
|
<shadow rvXMLIvarName="shadow">0|0 0 0 0|{0, 0}</shadow>
|
||||||
|
<dictionary rvXMLIvarName="stroke">
|
||||||
|
<NSColor rvXMLDictionaryKey="RVShapeElementStrokeColorKey">0 0 0 0</NSColor>
|
||||||
|
<NSNumber rvXMLDictionaryKey="RVShapeElementStrokeWidthKey" hint="double">0</NSNumber>
|
||||||
|
</dictionary>
|
||||||
|
<NSString rvXMLIvarName="PlainText">QnV0IEdvZCwgV2hvIGNhbGxlZCBtZSBoZXJlIGJlbG93LA==</NSString>
|
||||||
|
<NSString rvXMLIvarName="RTFData">e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBCdXQgR29kLCBXaG8gY2FsbGVkIG1lIGhlcmUgYmVsb3csfVxsaTBcc2EwXHNiMFxmaTBccWNccGFyfQ0KfQ0KfQ==</NSString>
|
||||||
|
<NSString rvXMLIvarName="WinFlowData">PEZsb3dEb2N1bWVudCBUZXh0QWxpZ25tZW50PSJMZWZ0IiB4bWxucz0iaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS93aW5meC8yMDA2L3hhbWwvcHJlc2VudGF0aW9uIj48UGFyYWdyYXBoIE1hcmdpbj0iMCwwLDAsMCIgVGV4dEFsaWdubWVudD0iQ2VudGVyIiBGb250RmFtaWx5PSJIZWx2ZXRpY2EiIEZvbnRTaXplPSI2MCI+PFNwYW4gRm9yZWdyb3VuZD0iI0ZGRkZGRkZGIiB4bWw6bGFuZz0iZW4tdXMiPjxSdW4gQmxvY2suVGV4dEFsaWdubWVudD0iQ2VudGVyIj5CdXQgR29kLCBXaG8gY2FsbGVkIG1lIGhlcmUgYmVsb3csPC9SdW4+PC9TcGFuPjwvUGFyYWdyYXBoPjwvRmxvd0RvY3VtZW50Pg==</NSString>
|
||||||
|
<NSString rvXMLIvarName="WinFontData">PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTE2Ij8+PFJWRm9udCB4bWxuczppPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYS1pbnN0YW5jZSIgeG1sbnM9Imh0dHA6Ly9zY2hlbWFzLmRhdGFjb250cmFjdC5vcmcvMjAwNC8wNy9Qcm9QcmVzZW50ZXIuQ29tbW9uIj48S2VybmluZz4wPC9LZXJuaW5nPjxMaW5lU3BhY2luZz4wPC9MaW5lU3BhY2luZz48T3V0bGluZUNvbG9yIHhtbG5zOmQycDE9Imh0dHA6Ly9zY2hlbWFzLmRhdGFjb250cmFjdC5vcmcvMjAwNC8wNy9TeXN0ZW0uV2luZG93cy5NZWRpYSI+PGQycDE6QT4wPC9kMnAxOkE+PGQycDE6Qj4wPC9kMnAxOkI+PGQycDE6Rz4wPC9kMnAxOkc+PGQycDE6Uj4wPC9kMnAxOlI+PGQycDE6U2NBPjA8L2QycDE6U2NBPjxkMnAxOlNjQj4wPC9kMnAxOlNjQj48ZDJwMTpTY0c+MDwvZDJwMTpTY0c+PGQycDE6U2NSPjA8L2QycDE6U2NSPjwvT3V0bGluZUNvbG9yPjxPdXRsaW5lV2lkdGg+MDwvT3V0bGluZVdpZHRoPjxWYXJpYW50cz5Ob3JtYWw8L1ZhcmlhbnRzPjwvUlZGb250Pg==</NSString>
|
||||||
|
</RVTextElement>
|
||||||
|
</array>
|
||||||
|
</RVDisplaySlide>
|
||||||
|
<RVDisplaySlide backgroundColor="0 0 0 0" highlightColor="0 0 0 0" drawingBackgroundColor="false" enabled="true" hotKey="" label="" notes="" UUID="4D669087-EB91-4972-A1F7-D866F339C502" chordChartPath="">
|
||||||
|
<array rvXMLIvarName="cues" />
|
||||||
|
<array rvXMLIvarName="displayElements">
|
||||||
|
<RVTextElement displayName="" UUID="22cedef3-308f-4869-b3d0-f0c6889a126c" typeID="0" displayDelay="0" locked="false" persistent="0" fromTemplate="false" opacity="1" source="" bezelRadius="0" rotation="0" drawingFill="false" drawingShadow="true" drawingStroke="false" fillColor="0 0 0 0" adjustsHeightToFit="false" verticalAlignment="0" revealType="0">
|
||||||
|
<RVRect3D rvXMLIvarName="position">{10 10 0 1004 748}</RVRect3D>
|
||||||
|
<shadow rvXMLIvarName="shadow">0|0 0 0 0|{0, 0}</shadow>
|
||||||
|
<dictionary rvXMLIvarName="stroke">
|
||||||
|
<NSColor rvXMLDictionaryKey="RVShapeElementStrokeColorKey">0 0 0 0</NSColor>
|
||||||
|
<NSNumber rvXMLDictionaryKey="RVShapeElementStrokeWidthKey" hint="double">0</NSNumber>
|
||||||
|
</dictionary>
|
||||||
|
<NSString rvXMLIvarName="PlainText">U2hhbGwgYmUgZm9yZXZlciBtaW5lLg==</NSString>
|
||||||
|
<NSString rvXMLIvarName="RTFData">e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBTaGFsbCBiZSBmb3JldmVyIG1pbmUufVxsaTBcc2EwXHNiMFxmaTBccWNccGFyfQ0KfQ0KfQ==</NSString>
|
||||||
|
<NSString rvXMLIvarName="WinFlowData">PEZsb3dEb2N1bWVudCBUZXh0QWxpZ25tZW50PSJMZWZ0IiB4bWxucz0iaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS93aW5meC8yMDA2L3hhbWwvcHJlc2VudGF0aW9uIj48UGFyYWdyYXBoIE1hcmdpbj0iMCwwLDAsMCIgVGV4dEFsaWdubWVudD0iQ2VudGVyIiBGb250RmFtaWx5PSJIZWx2ZXRpY2EiIEZvbnRTaXplPSI2MCI+PFNwYW4gRm9yZWdyb3VuZD0iI0ZGRkZGRkZGIiB4bWw6bGFuZz0iZW4tdXMiPjxSdW4gQmxvY2suVGV4dEFsaWdubWVudD0iQ2VudGVyIj5TaGFsbCBiZSBmb3JldmVyIG1pbmUuPC9SdW4+PC9TcGFuPjwvUGFyYWdyYXBoPjwvRmxvd0RvY3VtZW50Pg==</NSString>
|
||||||
|
<NSString rvXMLIvarName="WinFontData">PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTE2Ij8+PFJWRm9udCB4bWxuczppPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYS1pbnN0YW5jZSIgeG1sbnM9Imh0dHA6Ly9zY2hlbWFzLmRhdGFjb250cmFjdC5vcmcvMjAwNC8wNy9Qcm9QcmVzZW50ZXIuQ29tbW9uIj48S2VybmluZz4wPC9LZXJuaW5nPjxMaW5lU3BhY2luZz4wPC9MaW5lU3BhY2luZz48T3V0bGluZUNvbG9yIHhtbG5zOmQycDE9Imh0dHA6Ly9zY2hlbWFzLmRhdGFjb250cmFjdC5vcmcvMjAwNC8wNy9TeXN0ZW0uV2luZG93cy5NZWRpYSI+PGQycDE6QT4wPC9kMnAxOkE+PGQycDE6Qj4wPC9kMnAxOkI+PGQycDE6Rz4wPC9kMnAxOkc+PGQycDE6Uj4wPC9kMnAxOlI+PGQycDE6U2NBPjA8L2QycDE6U2NBPjxkMnAxOlNjQj4wPC9kMnAxOlNjQj48ZDJwMTpTY0c+MDwvZDJwMTpTY0c+PGQycDE6U2NSPjA8L2QycDE6U2NSPjwvT3V0bGluZUNvbG9yPjxPdXRsaW5lV2lkdGg+MDwvT3V0bGluZVdpZHRoPjxWYXJpYW50cz5Ob3JtYWw8L1ZhcmlhbnRzPjwvUlZGb250Pg==</NSString>
|
||||||
|
</RVTextElement>
|
||||||
|
</array>
|
||||||
|
</RVDisplaySlide>
|
||||||
|
<RVDisplaySlide backgroundColor="0 0 0 0" highlightColor="0 0 0 0" drawingBackgroundColor="false" enabled="true" hotKey="" label="" notes="" UUID="ADE5EE3D-56A6-4439-96DD-51C53337D4B1" chordChartPath="">
|
||||||
|
<array rvXMLIvarName="cues" />
|
||||||
|
<array rvXMLIvarName="displayElements">
|
||||||
|
<RVTextElement displayName="" UUID="6863ae3d-4e74-4a8c-8396-bda4cb366eb9" typeID="0" displayDelay="0" locked="false" persistent="0" fromTemplate="false" opacity="1" source="" bezelRadius="0" rotation="0" drawingFill="false" drawingShadow="true" drawingStroke="false" fillColor="0 0 0 0" adjustsHeightToFit="false" verticalAlignment="0" revealType="0">
|
||||||
|
<RVRect3D rvXMLIvarName="position">{10 10 0 1004 748}</RVRect3D>
|
||||||
|
<shadow rvXMLIvarName="shadow">0|0 0 0 0|{0, 0}</shadow>
|
||||||
|
<dictionary rvXMLIvarName="stroke">
|
||||||
|
<NSColor rvXMLDictionaryKey="RVShapeElementStrokeColorKey">0 0 0 0</NSColor>
|
||||||
|
<NSNumber rvXMLDictionaryKey="RVShapeElementStrokeWidthKey" hint="double">0</NSNumber>
|
||||||
|
</dictionary>
|
||||||
|
<NSString rvXMLIvarName="PlainText">V2hlbiB3ZSd2ZSBiZWVuIHRoZXJlIHRlbiB0aG91c2FuZCB5ZWFycyw=</NSString>
|
||||||
|
<NSString rvXMLIvarName="RTFData">e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBXaGVuIHdlJ3ZlIGJlZW4gdGhlcmUgdGVuIHRob3VzYW5kIHllYXJzLH1cbGkwXHNhMFxzYjBcZmkwXHFjXHBhcn0NCn0NCn0=</NSString>
|
||||||
|
<NSString rvXMLIvarName="WinFlowData">PEZsb3dEb2N1bWVudCBUZXh0QWxpZ25tZW50PSJMZWZ0IiB4bWxucz0iaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS93aW5meC8yMDA2L3hhbWwvcHJlc2VudGF0aW9uIj48UGFyYWdyYXBoIE1hcmdpbj0iMCwwLDAsMCIgVGV4dEFsaWdubWVudD0iQ2VudGVyIiBGb250RmFtaWx5PSJIZWx2ZXRpY2EiIEZvbnRTaXplPSI2MCI+PFNwYW4gRm9yZWdyb3VuZD0iI0ZGRkZGRkZGIiB4bWw6bGFuZz0iZW4tdXMiPjxSdW4gQmxvY2suVGV4dEFsaWdubWVudD0iQ2VudGVyIj5XaGVuIHdlJ3ZlIGJlZW4gdGhlcmUgdGVuIHRob3VzYW5kIHllYXJzLDwvUnVuPjwvU3Bhbj48L1BhcmFncmFwaD48L0Zsb3dEb2N1bWVudD4=</NSString>
|
||||||
|
<NSString rvXMLIvarName="WinFontData">PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTE2Ij8+PFJWRm9udCB4bWxuczppPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYS1pbnN0YW5jZSIgeG1sbnM9Imh0dHA6Ly9zY2hlbWFzLmRhdGFjb250cmFjdC5vcmcvMjAwNC8wNy9Qcm9QcmVzZW50ZXIuQ29tbW9uIj48S2VybmluZz4wPC9LZXJuaW5nPjxMaW5lU3BhY2luZz4wPC9MaW5lU3BhY2luZz48T3V0bGluZUNvbG9yIHhtbG5zOmQycDE9Imh0dHA6Ly9zY2hlbWFzLmRhdGFjb250cmFjdC5vcmcvMjAwNC8wNy9TeXN0ZW0uV2luZG93cy5NZWRpYSI+PGQycDE6QT4wPC9kMnAxOkE+PGQycDE6Qj4wPC9kMnAxOkI+PGQycDE6Rz4wPC9kMnAxOkc+PGQycDE6Uj4wPC9kMnAxOlI+PGQycDE6U2NBPjA8L2QycDE6U2NBPjxkMnAxOlNjQj4wPC9kMnAxOlNjQj48ZDJwMTpTY0c+MDwvZDJwMTpTY0c+PGQycDE6U2NSPjA8L2QycDE6U2NSPjwvT3V0bGluZUNvbG9yPjxPdXRsaW5lV2lkdGg+MDwvT3V0bGluZVdpZHRoPjxWYXJpYW50cz5Ob3JtYWw8L1ZhcmlhbnRzPjwvUlZGb250Pg==</NSString>
|
||||||
|
</RVTextElement>
|
||||||
|
</array>
|
||||||
|
</RVDisplaySlide>
|
||||||
|
<RVDisplaySlide backgroundColor="0 0 0 0" highlightColor="0 0 0 0" drawingBackgroundColor="false" enabled="true" hotKey="" label="" notes="" UUID="BD68D875-5154-485A-AEF3-D48D9CE27C05" chordChartPath="">
|
||||||
|
<array rvXMLIvarName="cues" />
|
||||||
|
<array rvXMLIvarName="displayElements">
|
||||||
|
<RVTextElement displayName="" UUID="13ba09a3-d3bb-4348-96d2-0cf6870b89f5" typeID="0" displayDelay="0" locked="false" persistent="0" fromTemplate="false" opacity="1" source="" bezelRadius="0" rotation="0" drawingFill="false" drawingShadow="true" drawingStroke="false" fillColor="0 0 0 0" adjustsHeightToFit="false" verticalAlignment="0" revealType="0">
|
||||||
|
<RVRect3D rvXMLIvarName="position">{10 10 0 1004 748}</RVRect3D>
|
||||||
|
<shadow rvXMLIvarName="shadow">0|0 0 0 0|{0, 0}</shadow>
|
||||||
|
<dictionary rvXMLIvarName="stroke">
|
||||||
|
<NSColor rvXMLDictionaryKey="RVShapeElementStrokeColorKey">0 0 0 0</NSColor>
|
||||||
|
<NSNumber rvXMLDictionaryKey="RVShapeElementStrokeWidthKey" hint="double">0</NSNumber>
|
||||||
|
</dictionary>
|
||||||
|
<NSString rvXMLIvarName="PlainText">QnJpZ2h0IHNoaW5pbmcgYXMgdGhlIHN1biw=</NSString>
|
||||||
|
<NSString rvXMLIvarName="RTFData">e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBCcmlnaHQgc2hpbmluZyBhcyB0aGUgc3VuLH1cbGkwXHNhMFxzYjBcZmkwXHFjXHBhcn0NCn0NCn0=</NSString>
|
||||||
|
<NSString rvXMLIvarName="WinFlowData">PEZsb3dEb2N1bWVudCBUZXh0QWxpZ25tZW50PSJMZWZ0IiB4bWxucz0iaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS93aW5meC8yMDA2L3hhbWwvcHJlc2VudGF0aW9uIj48UGFyYWdyYXBoIE1hcmdpbj0iMCwwLDAsMCIgVGV4dEFsaWdubWVudD0iQ2VudGVyIiBGb250RmFtaWx5PSJIZWx2ZXRpY2EiIEZvbnRTaXplPSI2MCI+PFNwYW4gRm9yZWdyb3VuZD0iI0ZGRkZGRkZGIiB4bWw6bGFuZz0iZW4tdXMiPjxSdW4gQmxvY2suVGV4dEFsaWdubWVudD0iQ2VudGVyIj5CcmlnaHQgc2hpbmluZyBhcyB0aGUgc3VuLDwvUnVuPjwvU3Bhbj48L1BhcmFncmFwaD48L0Zsb3dEb2N1bWVudD4=</NSString>
|
||||||
|
<NSString rvXMLIvarName="WinFontData">PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTE2Ij8+PFJWRm9udCB4bWxuczppPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYS1pbnN0YW5jZSIgeG1sbnM9Imh0dHA6Ly9zY2hlbWFzLmRhdGFjb250cmFjdC5vcmcvMjAwNC8wNy9Qcm9QcmVzZW50ZXIuQ29tbW9uIj48S2VybmluZz4wPC9LZXJuaW5nPjxMaW5lU3BhY2luZz4wPC9MaW5lU3BhY2luZz48T3V0bGluZUNvbG9yIHhtbG5zOmQycDE9Imh0dHA6Ly9zY2hlbWFzLmRhdGFjb250cmFjdC5vcmcvMjAwNC8wNy9TeXN0ZW0uV2luZG93cy5NZWRpYSI+PGQycDE6QT4wPC9kMnAxOkE+PGQycDE6Qj4wPC9kMnAxOkI+PGQycDE6Rz4wPC9kMnAxOkc+PGQycDE6Uj4wPC9kMnAxOlI+PGQycDE6U2NBPjA8L2QycDE6U2NBPjxkMnAxOlNjQj4wPC9kMnAxOlNjQj48ZDJwMTpTY0c+MDwvZDJwMTpTY0c+PGQycDE6U2NSPjA8L2QycDE6U2NSPjwvT3V0bGluZUNvbG9yPjxPdXRsaW5lV2lkdGg+MDwvT3V0bGluZVdpZHRoPjxWYXJpYW50cz5Ob3JtYWw8L1ZhcmlhbnRzPjwvUlZGb250Pg==</NSString>
|
||||||
|
</RVTextElement>
|
||||||
|
</array>
|
||||||
|
</RVDisplaySlide>
|
||||||
|
<RVDisplaySlide backgroundColor="0 0 0 0" highlightColor="0 0 0 0" drawingBackgroundColor="false" enabled="true" hotKey="" label="" notes="" UUID="030026EE-A25C-4781-883D-0CAC394ADC93" chordChartPath="">
|
||||||
|
<array rvXMLIvarName="cues" />
|
||||||
|
<array rvXMLIvarName="displayElements">
|
||||||
|
<RVTextElement displayName="" UUID="3ecf8eb2-a1dd-4c87-9a42-e485d4bc312b" typeID="0" displayDelay="0" locked="false" persistent="0" fromTemplate="false" opacity="1" source="" bezelRadius="0" rotation="0" drawingFill="false" drawingShadow="true" drawingStroke="false" fillColor="0 0 0 0" adjustsHeightToFit="false" verticalAlignment="0" revealType="0">
|
||||||
|
<RVRect3D rvXMLIvarName="position">{10 10 0 1004 748}</RVRect3D>
|
||||||
|
<shadow rvXMLIvarName="shadow">0|0 0 0 0|{0, 0}</shadow>
|
||||||
|
<dictionary rvXMLIvarName="stroke">
|
||||||
|
<NSColor rvXMLDictionaryKey="RVShapeElementStrokeColorKey">0 0 0 0</NSColor>
|
||||||
|
<NSNumber rvXMLDictionaryKey="RVShapeElementStrokeWidthKey" hint="double">0</NSNumber>
|
||||||
|
</dictionary>
|
||||||
|
<NSString rvXMLIvarName="PlainText">V2UndmUgbm8gbGVzcyBkYXlzIHRvIHNpbmcgR29kJ3MgcHJhaXNl</NSString>
|
||||||
|
<NSString rvXMLIvarName="RTFData">e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBXZSd2ZSBubyBsZXNzIGRheXMgdG8gc2luZyBHb2QncyBwcmFpc2V9XGxpMFxzYTBcc2IwXGZpMFxxY1xwYXJ9DQp9DQp9</NSString>
|
||||||
|
<NSString rvXMLIvarName="WinFlowData">PEZsb3dEb2N1bWVudCBUZXh0QWxpZ25tZW50PSJMZWZ0IiB4bWxucz0iaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS93aW5meC8yMDA2L3hhbWwvcHJlc2VudGF0aW9uIj48UGFyYWdyYXBoIE1hcmdpbj0iMCwwLDAsMCIgVGV4dEFsaWdubWVudD0iQ2VudGVyIiBGb250RmFtaWx5PSJIZWx2ZXRpY2EiIEZvbnRTaXplPSI2MCI+PFNwYW4gRm9yZWdyb3VuZD0iI0ZGRkZGRkZGIiB4bWw6bGFuZz0iZW4tdXMiPjxSdW4gQmxvY2suVGV4dEFsaWdubWVudD0iQ2VudGVyIj5XZSd2ZSBubyBsZXNzIGRheXMgdG8gc2luZyBHb2QncyBwcmFpc2U8L1J1bj48L1NwYW4+PC9QYXJhZ3JhcGg+PC9GbG93RG9jdW1lbnQ+</NSString>
|
||||||
|
<NSString rvXMLIvarName="WinFontData">PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTE2Ij8+PFJWRm9udCB4bWxuczppPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYS1pbnN0YW5jZSIgeG1sbnM9Imh0dHA6Ly9zY2hlbWFzLmRhdGFjb250cmFjdC5vcmcvMjAwNC8wNy9Qcm9QcmVzZW50ZXIuQ29tbW9uIj48S2VybmluZz4wPC9LZXJuaW5nPjxMaW5lU3BhY2luZz4wPC9MaW5lU3BhY2luZz48T3V0bGluZUNvbG9yIHhtbG5zOmQycDE9Imh0dHA6Ly9zY2hlbWFzLmRhdGFjb250cmFjdC5vcmcvMjAwNC8wNy9TeXN0ZW0uV2luZG93cy5NZWRpYSI+PGQycDE6QT4wPC9kMnAxOkE+PGQycDE6Qj4wPC9kMnAxOkI+PGQycDE6Rz4wPC9kMnAxOkc+PGQycDE6Uj4wPC9kMnAxOlI+PGQycDE6U2NBPjA8L2QycDE6U2NBPjxkMnAxOlNjQj4wPC9kMnAxOlNjQj48ZDJwMTpTY0c+MDwvZDJwMTpTY0c+PGQycDE6U2NSPjA8L2QycDE6U2NSPjwvT3V0bGluZUNvbG9yPjxPdXRsaW5lV2lkdGg+MDwvT3V0bGluZVdpZHRoPjxWYXJpYW50cz5Ob3JtYWw8L1ZhcmlhbnRzPjwvUlZGb250Pg==</NSString>
|
||||||
|
</RVTextElement>
|
||||||
|
</array>
|
||||||
|
</RVDisplaySlide>
|
||||||
|
<RVDisplaySlide backgroundColor="0 0 0 0" highlightColor="0 0 0 0" drawingBackgroundColor="false" enabled="true" hotKey="" label="" notes="" UUID="50648C63-C1FC-40E0-8928-FEDFFCDA9689" chordChartPath="">
|
||||||
|
<array rvXMLIvarName="cues" />
|
||||||
|
<array rvXMLIvarName="displayElements">
|
||||||
|
<RVTextElement displayName="" UUID="a8c192f7-dac5-4fdd-8912-eb40d06e1210" typeID="0" displayDelay="0" locked="false" persistent="0" fromTemplate="false" opacity="1" source="" bezelRadius="0" rotation="0" drawingFill="false" drawingShadow="true" drawingStroke="false" fillColor="0 0 0 0" adjustsHeightToFit="false" verticalAlignment="0" revealType="0">
|
||||||
|
<RVRect3D rvXMLIvarName="position">{10 10 0 1004 748}</RVRect3D>
|
||||||
|
<shadow rvXMLIvarName="shadow">0|0 0 0 0|{0, 0}</shadow>
|
||||||
|
<dictionary rvXMLIvarName="stroke">
|
||||||
|
<NSColor rvXMLDictionaryKey="RVShapeElementStrokeColorKey">0 0 0 0</NSColor>
|
||||||
|
<NSNumber rvXMLDictionaryKey="RVShapeElementStrokeWidthKey" hint="double">0</NSNumber>
|
||||||
|
</dictionary>
|
||||||
|
<NSString rvXMLIvarName="PlainText">VGhhbiB3aGVuIHdlJ2QgZmlyc3QgYmVndW4u</NSString>
|
||||||
|
<NSString rvXMLIvarName="RTFData">e1xydGYxXHByb3J0ZjFcYW5zaVxhbnNpY3BnMTI1Mlx1YzFcaHRtYXV0c3BcZGVmZjJ7XGZvbnR0Ymx7XGYwXGZjaGFyc2V0MCBUaW1lcyBOZXcgUm9tYW47fXtcZjJcZmNoYXJzZXQwIEdlb3JnaWE7fXtcZjNcZmNoYXJzZXQwIEhlbHZldGljYTt9fXtcY29sb3J0Ymw7XHJlZDBcZ3JlZW4wXGJsdWUwO1xyZWQyNTVcZ3JlZW4yNTVcYmx1ZTI1NTt9XGxvY2hcaGljaFxkYmNoXHBhcmRcc2xsZWFkaW5nMFxwbGFpblxsdHJwYXJcaXRhcDB7XGxhbmcxMDMzXGZzMTIwXGYzXGNmMSBcY2YxXHFse1xmMyB7XGNmMlxsdHJjaCBUaGFuIHdoZW4gd2UnZCBmaXJzdCBiZWd1bi59XGxpMFxzYTBcc2IwXGZpMFxxY1xwYXJ9DQp9DQp9</NSString>
|
||||||
|
<NSString rvXMLIvarName="WinFlowData">PEZsb3dEb2N1bWVudCBUZXh0QWxpZ25tZW50PSJMZWZ0IiB4bWxucz0iaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS93aW5meC8yMDA2L3hhbWwvcHJlc2VudGF0aW9uIj48UGFyYWdyYXBoIE1hcmdpbj0iMCwwLDAsMCIgVGV4dEFsaWdubWVudD0iQ2VudGVyIiBGb250RmFtaWx5PSJIZWx2ZXRpY2EiIEZvbnRTaXplPSI2MCI+PFNwYW4gRm9yZWdyb3VuZD0iI0ZGRkZGRkZGIiB4bWw6bGFuZz0iZW4tdXMiPjxSdW4gQmxvY2suVGV4dEFsaWdubWVudD0iQ2VudGVyIj5UaGFuIHdoZW4gd2UnZCBmaXJzdCBiZWd1bi48L1J1bj48L1NwYW4+PC9QYXJhZ3JhcGg+PC9GbG93RG9jdW1lbnQ+</NSString>
|
||||||
|
<NSString rvXMLIvarName="WinFontData">PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTE2Ij8+PFJWRm9udCB4bWxuczppPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYS1pbnN0YW5jZSIgeG1sbnM9Imh0dHA6Ly9zY2hlbWFzLmRhdGFjb250cmFjdC5vcmcvMjAwNC8wNy9Qcm9QcmVzZW50ZXIuQ29tbW9uIj48S2VybmluZz4wPC9LZXJuaW5nPjxMaW5lU3BhY2luZz4wPC9MaW5lU3BhY2luZz48T3V0bGluZUNvbG9yIHhtbG5zOmQycDE9Imh0dHA6Ly9zY2hlbWFzLmRhdGFjb250cmFjdC5vcmcvMjAwNC8wNy9TeXN0ZW0uV2luZG93cy5NZWRpYSI+PGQycDE6QT4wPC9kMnAxOkE+PGQycDE6Qj4wPC9kMnAxOkI+PGQycDE6Rz4wPC9kMnAxOkc+PGQycDE6Uj4wPC9kMnAxOlI+PGQycDE6U2NBPjA8L2QycDE6U2NBPjxkMnAxOlNjQj4wPC9kMnAxOlNjQj48ZDJwMTpTY0c+MDwvZDJwMTpTY0c+PGQycDE6U2NSPjA8L2QycDE6U2NSPjwvT3V0bGluZUNvbG9yPjxPdXRsaW5lV2lkdGg+MDwvT3V0bGluZVdpZHRoPjxWYXJpYW50cz5Ob3JtYWw8L1ZhcmlhbnRzPjwvUlZGb250Pg==</NSString>
|
||||||
|
</RVTextElement>
|
||||||
|
</array>
|
||||||
|
</RVDisplaySlide>
|
||||||
|
</array>
|
||||||
|
</RVSlideGrouping>
|
||||||
|
</array>
|
||||||
|
<array rvXMLIvarName="arrangements" />
|
||||||
|
</RVPresentationDocument>
|
Loading…
Reference in New Issue
Block a user