Browse Source

just some files

master
Nils 2 months ago
parent
commit
75cdc4120c
41 changed files with 18682 additions and 2 deletions
  1. +131
    -0
      .gitignore
  2. +10
    -0
      CHANGELOG
  3. +134
    -2
      README.md
  4. +1
    -0
      __main__.py
  5. +6
    -0
      configure
  6. +10
    -0
      desktop/desktop.desktop
  7. BIN
      desktop/icon256x256.png
  8. BIN
      desktop/icon32x32.png
  9. +430
    -0
      documentation/LICENSE
  10. +7
    -0
      documentation/README.txt
  11. +18
    -0
      documentation/build-documentation.sh
  12. +5
    -0
      documentation/english.part.adoc
  13. BIN
      documentation/favicon.ico
  14. BIN
      documentation/favicon.png
  15. +5
    -0
      documentation/german.part.adoc
  16. +37
    -0
      documentation/index.adoc
  17. +45
    -0
      documentation/manpageinclude.h2m
  18. +64
    -0
      documentation/readme.template
  19. BIN
      documentation/screenshot.png
  20. +30
    -0
      engine/__init__.py
  21. +65
    -0
      engine/api.py
  22. +63
    -0
      engine/config.py
  23. +40
    -0
      engine/main.py
  24. +0
    -0
      qtgui/__init__.py
  25. +30
    -0
      qtgui/constantsAndConfigs.py
  26. +93
    -0
      qtgui/designer/mainwindow.py
  27. +189
    -0
      qtgui/designer/mainwindow.ui
  28. +165
    -0
      qtgui/instrument.py
  29. +85
    -0
      qtgui/mainwindow.py
  30. +884
    -0
      qtgui/resources.py
  31. BIN
      qtgui/resources/aboutlogo.png
  32. +4
    -0
      qtgui/resources/buildresources.sh
  33. BIN
      qtgui/resources/icon.png
  34. +7
    -0
      qtgui/resources/resources.qrc
  35. +2
    -0
      qtgui/resources/translations/config.pro
  36. BIN
      qtgui/resources/translations/de.qm
  37. +29
    -0
      qtgui/resources/translations/de.ts
  38. +5
    -0
      qtgui/resources/translations/update.sh
  39. +1
    -0
      tembro
  40. +16086
    -0
      template/calfbox/configure~
  41. +1
    -0
      template/documentation/index.adoc.template

+ 131
- 0
.gitignore View File

@@ -0,0 +1,131 @@
# Byte-compiled / optimized / DLL files
*__pycache__
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
.pytest_cache/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py
db.sqlite3

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
target/

# Jupyter Notebook
.ipynb_checkpoints

# pyenv
.python-version

# celery beat schedule file
celerybeat-schedule

# SageMath parsed files
*.sage.py

# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# mypy
.mypy_cache/


#build process
*.bin
*.build
build/
Makefile
compiledprefix.py
sitepackages
template/calfbox/.deps
template/calfbox/build
template/calfbox/autom4te.cache
template/calfbox/Makefile.in
template/calfbox/aclocal.m4
template/calfbox/compile
template/calfbox/config.h
template/calfbox/config.h.in
template/calfbox/config.h.in~
template/calfbox/config.status
template/calfbox/configure
template/calfbox/depcomp
template/calfbox/install-sh
template/calfbox/ltmain.sh
template/calfbox/missing
template/calfbox/stamp-h1
tempalte/calfbox/configure~


+ 10
- 0
CHANGELOG View File

@@ -0,0 +1,10 @@
#Changelog
Format: Double ## for a version number followed by a space, ISO-Date, Semantic Versioning:
## YYYY-MM-DD major.minor.patch
Two empty lines before the next entry.
External contributors notice at the end of the line: (LastName, FirstName / nick)


## 1111-11-11 0.1.0
Initial proof-of-concept release


+ 134
- 2
README.md View File

@@ -1,3 +1,135 @@
# Tembro

Sampled Instrument Player with static and monolithic design. All instruments are built-in.
[//]: # (Generated 2021-02-13T20:17:14.249024. Changes belong into template/documentation/readme.template)

#Patroneo
Program version 2.1.0


![Screenshot](https://git.laborejo.org/lss/Patroneo/raw/branch/master/documentation/screenshot.png "Screenshot")



Patroneo (which is Esperanto for "Pattern") is an easy to use, pattern based midi sequencer, a
program that sends digital "notes" to software instruments such as synthesizers and samplers.

Patroneo is primarily designed for educational purposes, where the main goal is to teach the
importance of patterns and repetitions in any kind of music. However, Patroneo is a full sequencer
you can use to create real music. The constraints it presents will more likely boost your
creativity than suppressing it.

You have tracks with one pattern each. Turn on steps in the pattern to play
musical notes. Switch the patterns on and off in a sequence to create a song structure.
Connect external synthesizers and samplers to create sounds.


This README is just a short introduction. Consult the manual (see below) for more information.

# Contact and Information

* Website https://www.laborejo.org
* Bugs and Issues: https://www.laborejo.org/bugs
* Git Repositories for all programs: https://git.laborejo.org
* Documentation and Manual https://www.laborejo.org/documentation/patroneo

# Installation and Starting

## Download

### Release Version
If the latest release is not available through your package manger you can build it yourself:
Download the latest code release on https://www.laborejo.org/downloads and extract it.

### Git Version
It is possible to clone a git repository.

`git clone https://git.laborejo.org/lss/patroneo.git`

## Dependencies
* Glibc
* Python 3.6 (maybe earlier)
* PyQt5 for Python 3
* DejaVu Sans Sarif TTF (Font) (recommended, but not technically necessary)


#### Build Dependencies
* Bash
* GCC (development is done on 8.2, but most likely you can use a much earlier version)

### Environment:
* Jack Audio Connection Kit must be running
* Agordejo / New Session Manager ("NSM")

## Build
./configure --prefix=/usr/local
make
sudo make install


## Starting

There are multiple ways to run Patroneo which should give you the flexibility to configure your
system as you want.

We make no distinction if you installed Patroneo yourself or through the distributions package-manager.

The differences are: With or without Agordejo, with or without sound, installed or from the source dir.

### Installed , running through Agordejo (New Session Manager) (recommended)
Starting Patroneo through Agordejo after you installed patroneo system-wide
is the recommended and only supported way. Start agordejo and load or create a new
session. Then use the program launcher to add `patroneo`.
It should appear with an icon in the list and open its GUI.

### Installed without Agordejo
If you start patroneo directly it will present you with a dialog to choose your session directory.

You can also start patroneo from a terminal (or create a starter script).

`patroneo --save DIRECTORY`

Uses the given directory to save. The dir will be created or loaded from if already present. Use
the applications file menu to save (Ctrl+s).

You can use this to load and save the files from an existing NSM session. If you create a new
directory you can copy it manually to an NSM session directory, but that requires renaming the
directory to append the unique ID provided by NSM.

Sending SIGUSR1 to the program in this mode will trigger a save.

Closing through your window manager in this mode will actually quit the application without a
prompt to save changes.

## From source directory
You can run Patroneo after extracting the release archive or cloning from git, without installation.

### Calfbox
"Calfbox" is the name of our internal realtime midi/audio python module.

* It is bundled with the application for a normal install.
* Or you could run `./configure` and `make calfbox` without subsequent install, which creates a `sitepackages` directory in the source dir. You can then run `./patroneo` directly from the source.
* A third option is `./patroneo --mute` which runs without sound at all and does not need calfbox.

### From source directory with NSM
The developer uses this way to develop and use the software, so it will always be as stable as the
compiled version. But it is a bit less performant than building and installing it.

After extracting the release archive create a symlink from `patroneo` into your PATH. e.g. /usr/bin
or ~/bin, if that exists on your system.

If you compiled without installing you can also symlink to `./patroneo.bin`

### From source dir without NSM
Use `./patroneo --save` (see above). If you compiled without installing you can also run `./patroneo.bin`

### No NSM, no Make, No Sound
Combining the above options you can start the program directly after unpacking or cloning from git:

`./patroneo --save /tmp --mute`

Or even shorter:

`./patroneo -s /tmp -m`

This is the minimal run mode which is only useful for testing and development. But if you only want
to look at the GUI and are not in the mood to install anything -including dependencies-, go ahead.


+ 1
- 0
__main__.py View File

@@ -0,0 +1 @@
template/main.py.template

+ 6
- 0
configure View File

@@ -0,0 +1,6 @@
#!/bin/bash
program=tembro
cboxconfigure="--without-fluidsynth --without-libsmf"
version=0.1.0

. template/configure.template #. is the posix compatible version of source

+ 10
- 0
desktop/desktop.desktop View File

@@ -0,0 +1,10 @@
[Desktop Entry]
Type=Application
Name=QtCboxNsm Exämple ツ
Comment=Just an example
Exec=exampleClientCboxQtNsm
Icon=exampleClientCboxQtNsm
Terminal=false
StartupNotify=false
Version=1.0
Categories=AudioVideo;Audio;X-Recorders;X-Multitrack;X-Jack;

BIN
desktop/icon256x256.png View File

Before After
Width: 32  |  Height: 32  |  Size: 680B

BIN
desktop/icon32x32.png View File

Before After
Width: 32  |  Height: 32  |  Size: 680B

+ 430
- 0
documentation/LICENSE View File

@@ -0,0 +1,430 @@
from: https://creativecommons.org/licenses/by-sa/4.0/legalcode.txt

Attribution-ShareAlike 4.0 International

=======================================================================

Creative Commons Corporation ("Creative Commons") is not a law firm and
does not provide legal services or legal advice. Distribution of
Creative Commons public licenses does not create a lawyer-client or
other relationship. Creative Commons makes its licenses and related
information available on an "as-is" basis. Creative Commons gives no
warranties regarding its licenses, any material licensed under their
terms and conditions, or any related information. Creative Commons
disclaims all liability for damages resulting from their use to the
fullest extent possible.

Using Creative Commons Public Licenses

Creative Commons public licenses provide a standard set of terms and
conditions that creators and other rights holders may use to share
original works of authorship and other material subject to copyright
and certain other rights specified in the public license below. The
following considerations are for informational purposes only, are not
exhaustive, and do not form part of our licenses.

Considerations for licensors: Our public licenses are
intended for use by those authorized to give the public
permission to use material in ways otherwise restricted by
copyright and certain other rights. Our licenses are
irrevocable. Licensors should read and understand the terms
and conditions of the license they choose before applying it.
Licensors should also secure all rights necessary before
applying our licenses so that the public can reuse the
material as expected. Licensors should clearly mark any
material not subject to the license. This includes other CC-
licensed material, or material used under an exception or
limitation to copyright. More considerations for licensors:
wiki.creativecommons.org/Considerations_for_licensors

Considerations for the public: By using one of our public
licenses, a licensor grants the public permission to use the
licensed material under specified terms and conditions. If
the licensor's permission is not necessary for any reason--for
example, because of any applicable exception or limitation to
copyright--then that use is not regulated by the license. Our
licenses grant only permissions under copyright and certain
other rights that a licensor has authority to grant. Use of
the licensed material may still be restricted for other
reasons, including because others have copyright or other
rights in the material. A licensor may make special requests,
such as asking that all changes be marked or described.
Although not required by our licenses, you are encouraged to
respect those requests where reasonable. More considerations
for the public:
wiki.creativecommons.org/Considerations_for_licensees

=======================================================================

Creative Commons Attribution-ShareAlike 4.0 International Public
License

By exercising the Licensed Rights (defined below), You accept and agree
to be bound by the terms and conditions of this Creative Commons
Attribution-ShareAlike 4.0 International Public License ("Public
License"). To the extent this Public License may be interpreted as a
contract, You are granted the Licensed Rights in consideration of Your
acceptance of these terms and conditions, and the Licensor grants You
such rights in consideration of benefits the Licensor receives from
making the Licensed Material available under these terms and
conditions.


Section 1 -- Definitions.

a. Adapted Material means material subject to Copyright and Similar
Rights that is derived from or based upon the Licensed Material
and in which the Licensed Material is translated, altered,
arranged, transformed, or otherwise modified in a manner requiring
permission under the Copyright and Similar Rights held by the
Licensor. For purposes of this Public License, where the Licensed
Material is a musical work, performance, or sound recording,
Adapted Material is always produced where the Licensed Material is
synched in timed relation with a moving image.

b. Adapter's License means the license You apply to Your Copyright
and Similar Rights in Your contributions to Adapted Material in
accordance with the terms and conditions of this Public License.

c. BY-SA Compatible License means a license listed at
creativecommons.org/compatiblelicenses, approved by Creative
Commons as essentially the equivalent of this Public License.

d. Copyright and Similar Rights means copyright and/or similar rights
closely related to copyright including, without limitation,
performance, broadcast, sound recording, and Sui Generis Database
Rights, without regard to how the rights are labeled or
categorized. For purposes of this Public License, the rights
specified in Section 2(b)(1)-(2) are not Copyright and Similar
Rights.

e. Effective Technological Measures means those measures that, in the
absence of proper authority, may not be circumvented under laws
fulfilling obligations under Article 11 of the WIPO Copyright
Treaty adopted on December 20, 1996, and/or similar international
agreements.

f. Exceptions and Limitations means fair use, fair dealing, and/or
any other exception or limitation to Copyright and Similar Rights
that applies to Your use of the Licensed Material.

g. License Elements means the license attributes listed in the name
of a Creative Commons Public License. The License Elements of this
Public License are Attribution and ShareAlike.

h. Licensed Material means the artistic or literary work, database,
or other material to which the Licensor applied this Public
License.

i. Licensed Rights means the rights granted to You subject to the
terms and conditions of this Public License, which are limited to
all Copyright and Similar Rights that apply to Your use of the
Licensed Material and that the Licensor has authority to license.

j. Licensor means the individual(s) or entity(ies) granting rights
under this Public License.

k. Share means to provide material to the public by any means or
process that requires permission under the Licensed Rights, such
as reproduction, public display, public performance, distribution,
dissemination, communication, or importation, and to make material
available to the public including in ways that members of the
public may access the material from a place and at a time
individually chosen by them.

l. Sui Generis Database Rights means rights other than copyright
resulting from Directive 96/9/EC of the European Parliament and of
the Council of 11 March 1996 on the legal protection of databases,
as amended and/or succeeded, as well as other essentially
equivalent rights anywhere in the world.

m. You means the individual or entity exercising the Licensed Rights
under this Public License. Your has a corresponding meaning.


Section 2 -- Scope.

a. License grant.

1. Subject to the terms and conditions of this Public License,
the Licensor hereby grants You a worldwide, royalty-free,
non-sublicensable, non-exclusive, irrevocable license to
exercise the Licensed Rights in the Licensed Material to:

a. reproduce and Share the Licensed Material, in whole or
in part; and

b. produce, reproduce, and Share Adapted Material.

2. Exceptions and Limitations. For the avoidance of doubt, where
Exceptions and Limitations apply to Your use, this Public
License does not apply, and You do not need to comply with
its terms and conditions.

3. Term. The term of this Public License is specified in Section
6(a).

4. Media and formats; technical modifications allowed. The
Licensor authorizes You to exercise the Licensed Rights in
all media and formats whether now known or hereafter created,
and to make technical modifications necessary to do so. The
Licensor waives and/or agrees not to assert any right or
authority to forbid You from making technical modifications
necessary to exercise the Licensed Rights, including
technical modifications necessary to circumvent Effective
Technological Measures. For purposes of this Public License,
simply making modifications authorized by this Section 2(a)
(4) never produces Adapted Material.

5. Downstream recipients.

a. Offer from the Licensor -- Licensed Material. Every
recipient of the Licensed Material automatically
receives an offer from the Licensor to exercise the
Licensed Rights under the terms and conditions of this
Public License.

b. Additional offer from the Licensor -- Adapted Material.
Every recipient of Adapted Material from You
automatically receives an offer from the Licensor to
exercise the Licensed Rights in the Adapted Material
under the conditions of the Adapter's License You apply.

c. No downstream restrictions. You may not offer or impose
any additional or different terms or conditions on, or
apply any Effective Technological Measures to, the
Licensed Material if doing so restricts exercise of the
Licensed Rights by any recipient of the Licensed
Material.

6. No endorsement. Nothing in this Public License constitutes or
may be construed as permission to assert or imply that You
are, or that Your use of the Licensed Material is, connected
with, or sponsored, endorsed, or granted official status by,
the Licensor or others designated to receive attribution as
provided in Section 3(a)(1)(A)(i).

b. Other rights.

1. Moral rights, such as the right of integrity, are not
licensed under this Public License, nor are publicity,
privacy, and/or other similar personality rights; however, to
the extent possible, the Licensor waives and/or agrees not to
assert any such rights held by the Licensor to the limited
extent necessary to allow You to exercise the Licensed
Rights, but not otherwise.

2. Patent and trademark rights are not licensed under this
Public License.

3. To the extent possible, the Licensor waives any right to
collect royalties from You for the exercise of the Licensed
Rights, whether directly or through a collecting society
under any voluntary or waivable statutory or compulsory
licensing scheme. In all other cases the Licensor expressly
reserves any right to collect such royalties.


Section 3 -- License Conditions.

Your exercise of the Licensed Rights is expressly made subject to the
following conditions.

a. Attribution.

1. If You Share the Licensed Material (including in modified
form), You must:

a. retain the following if it is supplied by the Licensor
with the Licensed Material:

i. identification of the creator(s) of the Licensed
Material and any others designated to receive
attribution, in any reasonable manner requested by
the Licensor (including by pseudonym if
designated);

ii. a copyright notice;

iii. a notice that refers to this Public License;

iv. a notice that refers to the disclaimer of
warranties;

v. a URI or hyperlink to the Licensed Material to the
extent reasonably practicable;

b. indicate if You modified the Licensed Material and
retain an indication of any previous modifications; and

c. indicate the Licensed Material is licensed under this
Public License, and include the text of, or the URI or
hyperlink to, this Public License.

2. You may satisfy the conditions in Section 3(a)(1) in any
reasonable manner based on the medium, means, and context in
which You Share the Licensed Material. For example, it may be
reasonable to satisfy the conditions by providing a URI or
hyperlink to a resource that includes the required
information.

3. If requested by the Licensor, You must remove any of the
information required by Section 3(a)(1)(A) to the extent
reasonably practicable.

b. ShareAlike.

In addition to the conditions in Section 3(a), if You Share
Adapted Material You produce, the following conditions also apply.

1. The Adapter's License You apply must be a Creative Commons
license with the same License Elements, this version or
later, or a BY-SA Compatible License.

2. You must include the text of, or the URI or hyperlink to, the
Adapter's License You apply. You may satisfy this condition
in any reasonable manner based on the medium, means, and
context in which You Share Adapted Material.

3. You may not offer or impose any additional or different terms
or conditions on, or apply any Effective Technological
Measures to, Adapted Material that restrict exercise of the
rights granted under the Adapter's License You apply.


Section 4 -- Sui Generis Database Rights.

Where the Licensed Rights include Sui Generis Database Rights that
apply to Your use of the Licensed Material:

a. for the avoidance of doubt, Section 2(a)(1) grants You the right
to extract, reuse, reproduce, and Share all or a substantial
portion of the contents of the database;

b. if You include all or a substantial portion of the database
contents in a database in which You have Sui Generis Database
Rights, then the database in which You have Sui Generis Database
Rights (but not its individual contents) is Adapted Material,

including for purposes of Section 3(b); and
c. You must comply with the conditions in Section 3(a) if You Share
all or a substantial portion of the contents of the database.

For the avoidance of doubt, this Section 4 supplements and does not
replace Your obligations under this Public License where the Licensed
Rights include other Copyright and Similar Rights.


Section 5 -- Disclaimer of Warranties and Limitation of Liability.

a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.

b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.

c. The disclaimer of warranties and limitation of liability provided
above shall be interpreted in a manner that, to the extent
possible, most closely approximates an absolute disclaimer and
waiver of all liability.


Section 6 -- Term and Termination.

a. This Public License applies for the term of the Copyright and
Similar Rights licensed here. However, if You fail to comply with
this Public License, then Your rights under this Public License
terminate automatically.

b. Where Your right to use the Licensed Material has terminated under
Section 6(a), it reinstates:

1. automatically as of the date the violation is cured, provided
it is cured within 30 days of Your discovery of the
violation; or

2. upon express reinstatement by the Licensor.

For the avoidance of doubt, this Section 6(b) does not affect any
right the Licensor may have to seek remedies for Your violations
of this Public License.

c. For the avoidance of doubt, the Licensor may also offer the
Licensed Material under separate terms or conditions or stop
distributing the Licensed Material at any time; however, doing so
will not terminate this Public License.

d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
License.


Section 7 -- Other Terms and Conditions.

a. The Licensor shall not be bound by any additional or different
terms or conditions communicated by You unless expressly agreed.

b. Any arrangements, understandings, or agreements regarding the
Licensed Material not stated herein are separate from and
independent of the terms and conditions of this Public License.


Section 8 -- Interpretation.

a. For the avoidance of doubt, this Public License does not, and
shall not be interpreted to, reduce, limit, restrict, or impose
conditions on any use of the Licensed Material that could lawfully
be made without permission under this Public License.

b. To the extent possible, if any provision of this Public License is
deemed unenforceable, it shall be automatically reformed to the
minimum extent necessary to make it enforceable. If the provision
cannot be reformed, it shall be severed from this Public License
without affecting the enforceability of the remaining terms and
conditions.

c. No term or condition of this Public License will be waived and no
failure to comply consented to unless expressly agreed to by the
Licensor.

d. Nothing in this Public License constitutes or may be interpreted
as a limitation upon, or waiver of, any privileges and immunities
that apply to the Licensor or You, including from the legal
processes of any jurisdiction or authority.


=======================================================================

Creative Commons is not a party to its public
licenses. Notwithstanding, Creative Commons may elect to apply one of
its public licenses to material it publishes and in those instances
will be considered the “Licensor.” The text of the Creative Commons
public licenses is dedicated to the public domain under the CC0 Public
Domain Dedication. Except for the limited purpose of indicating that
material is shared under a Creative Commons public license or as
otherwise permitted by the Creative Commons policies published at
creativecommons.org/policies, Creative Commons does not authorize the
use of the trademark "Creative Commons" or any other trademark or logo
of Creative Commons without its prior written consent including,
without limitation, in connection with any unauthorized modifications
to any of its public licenses or any other arrangements,
understandings, or agreements concerning use of licensed material. For
the avoidance of doubt, this paragraph does not form part of the
public licenses.

Creative Commons may be contacted at creativecommons.org.


+ 7
- 0
documentation/README.txt View File

@@ -0,0 +1,7 @@
Run ./build-documentation.sh for html output in the /out directory.

.adoc is asciidoctor, not simple asciidoc.

This documentation is licensed under Creative Commons-BY-SA-4.0.
Please read the provided documentation/LICENSE file or visit
https://creativecommons.org/licenses/by-sa/4.0/legalcode

+ 18
- 0
documentation/build-documentation.sh View File

@@ -0,0 +1,18 @@
#!/bin/sh

#The documentation is built statically and does not belong to the normal build process with configure and make
#Its updating is part of the development process, not packaging and running.
#The correct out/ dir is already part of git.

set -e
asciidoctor index.adoc -o out/index.html

asciidoctor german.adoc -o out/german.html
cp overview-german.png out/overview-german.png

asciidoctor english.adoc -o out/english.html
cp overview-english.png out/overview-english.png

#cp *-quickstart*.mp4 out/

cp favicon.* out/

+ 5
- 0
documentation/english.part.adoc View File

@@ -0,0 +1,5 @@
== Usage
* Nothing
* To
* See
* Here

BIN
documentation/favicon.ico View File

Before After

BIN
documentation/favicon.png View File

Before After
Width: 32  |  Height: 32  |  Size: 942B

+ 5
- 0
documentation/german.part.adoc View File

@@ -0,0 +1,5 @@
== Bedienung
Hier gibt es nichts zu sehen.

* Weiter
* Gehen

+ 37
- 0
documentation/index.adoc View File

@@ -0,0 +1,37 @@
:Author: Laborejo Software Suite
:Version: 2.1.0
:iconfont-remote!:
:!webfonts:

////
This documentation is licensed under the Creative Commons Attribution-ShareAlike 4.0 International License.
To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/4.0/ or send a
letter to Creative Commons, PO Box 1866, Mountain View, CA 94042, USA.
A copy of the license has been provided in the file documentation/LICENSE.
////

////
https://powerman.name/doc/asciidoc
https://asciidoctor.org/docs/user-manual/
////

:nofooter:


== Patroneo Multi-Language Documentation
image::logo.png["logo", 320, 180]

For program version 2.1.0

This site is part of the https://www.laborejo.org[Laborejo Software Suite]


Please choose a language

* link:english.html[English]
* link:german.html[Deutsch (German)]


Further Links
* https://laborejo.org/bugs/[Bug and Issues, and other Feedback]
* Write to info@laborejo.org for any comment or question.

+ 45
- 0
documentation/manpageinclude.h2m View File

@@ -0,0 +1,45 @@

[name]
Patroneo - Easy to use pattern based midi sequencer.

[usage]

Patroneo (which is Esperanto for "Pattern") is an easy to use, pattern based midi sequencer, a
program that sends digital "notes" to software instruments such as synthesizers and samplers.

Patroneo is primarily designed for educational purposes, where the main goal is to teach the
importance of patterns and repetitions in any kind of music. However, Patroneo is a full sequencer
you can use to create real music. The constraints it presents will more likely boost your
creativity than suppressing it.

You have tracks with one pattern each. Turn on steps in the pattern to play
musical notes. Switch the patterns on and off in a sequence to create a song structure.
Connect external synthesizers and samplers to create sounds.


[Reporting bugs]
https://www.laborejo.org/bugs

[copyright]
Patroneo 2.1.0 - Copyright 2021
Laborejo Software Suite
https://www.laborejo.org/

[examples]
Start patroneo through NSM, e.g. through Agordejo. This will take care of all
settings and save directories.

Other modes of operations, mostly for testing, are:

Run without session management and save in /tmp.
patroneo --save /tmp

Run without audio and midi. Skips all JACK checks. Used to just look at the GUI, e.g. to make screenshots
patroneo --mute

[see also]
The full documentation for Patroneo is maintained as a multi-lingual html site to your systems doc-dir.
For example:
xdg-open file:///usr/share/doc/patroneo/index.html

The documentation can also be found online https://www.laborejo.org/documentation/patroneo

+ 64
- 0
documentation/readme.template View File

@@ -0,0 +1,64 @@

[//]: # (Generated <date>. Changes belong into template/documentation/readme.template)

#<name>
Program version <version>


![Screenshot](https://git.laborejo.org/lss/<name>/raw/branch/master/documentation/screenshot.png "Screenshot")


<description>

This README is just a short introduction. Consult the manual (see below) for more information.

# Contact and Information

* Website https://www.laborejo.org
* Bugs and Issues: https://www.laborejo.org/bugs
* Git Repositories for all programs: https://git.laborejo.org
* Documentation and Manual https://www.laborejo.org/documentation/<shortname>

# Installation and Starting

## Download

### Release Version
If the latest release is not available through your package manger you can build it yourself:
Download the latest code release on https://www.laborejo.org/downloads and extract it.

### Git Version
It is possible to clone a git repository.

`git clone https://git.laborejo.org/lss/<shortname>.git`

## Dependencies
* Glibc
* Python 3.6 (maybe earlier)
* PyQt5 for Python 3
* DejaVu Sans Sarif TTF (Font) (recommended, but not technically necessary)
<dependencies>

#### Build Dependencies
* Bash
* GCC (development is done on 8.2, but most likely you can use a much earlier version)

### Environment:
* Jack Audio Connection Kit must be running

## Build and Install
./configure --prefix=/usr/local
make
sudo make install


## Starting

If you installed <name> through a packager manager or yourself simple use your application launcher
or terminal to start the executable `<shortname>`

You can also run <name> after extracting the release archive or cloning from git, without make or
installation. If you did so, for additional features please link tools/nsm-data to your executable PATH.

Use the manpage `man <shortname>` or run `<shortname> --help` (or local variant `./<shortname> --help` )
to see available command line parameters.

BIN
documentation/screenshot.png View File

Before After
Width: 1280  |  Height: 720  |  Size: 80KB

+ 30
- 0
engine/__init__.py View File

@@ -0,0 +1,30 @@
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Copyright 2021, Nils Hilbricht, Germany ( https://www.hilbricht.net )

This file is part of the Laborejo Software Suite ( https://www.laborejo.org ),

This application 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, either version 3 of the License, or
(at your option) any later version.

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, see <http://www.gnu.org/licenses/>.
"""

import logging; logger = logging.getLogger(__name__); logger.info("import")

#This file only exists as a reminder to _not_ create it again wrongly in the future.

#from .api import * #Do not star-import here!
#This leads to uncontrollable behaviour because importing _any_ file from engine will first import this init file, which would trigger the api to start its session.
#Instead use explicit import to get the api.

#No!: import engine.api as api #This loads the engine and starts a session.

+ 65
- 0
engine/api.py View File

@@ -0,0 +1,65 @@
#! /usr/bin/env python3
# -*- coding: utf-8 -*-

"""
Copyright 2021, Nils Hilbricht, Germany ( https://www.hilbricht.net )

This file is part of the Laborejo Software Suite ( https://www.laborejo.org ),

This application 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, either version 3 of the License, or
(at your option) any later version.

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, see <http://www.gnu.org/licenses/>.
"""

import logging; logger = logging.getLogger(__name__); logger.info("import")

#Standard Library Modules
from typing import List, Set, Dict, Tuple

#Third Party Modules
from calfbox import cbox

#Template Modules
import template.engine.api #we need direct access to the module to inject data in the provided structures. but we also need the functions directly. next line:
from template.engine.api import *


#New callbacks
class ClientCallbacks(Callbacks): #inherits from the templates api callbacks
def __init__(self):
super().__init__()

self.tempCallback = []

def _tempCallback(self):
"""Just for copy paste during development"""
export = session.data.export()
for func in self.tempCallback:
func(export)
callbacks._dataChanged()

#Inject our derived Callbacks into the parent module
template.engine.api.callbacks = ClientCallbacks()
from template.engine.api import callbacks

_templateStartEngine = startEngine

def startEngine(nsmClient):
_templateStartEngine(nsmClient) #loads save files or creates empty structure.

#Send initial Callbacks to create the first GUI state.
#The order of initial callbacks must not change to avoid GUI problems.
#For example it is important that the tracks get created first and only then the number of measures
logger.info("Sending initial callbacks to GUI")
callbacks._tempCallback()

logger.info("Tembro api startEngine complete")

+ 63
- 0
engine/config.py View File

@@ -0,0 +1,63 @@
#! /usr/bin/env python3
# -*- coding: utf-8 -*-

#Do not change these during runtime!

METADATA={
#The pretty name of this program. Used for NSM display and Jack client name
#Can contain everything a linux file/path supports. Never change this or it will break the
#session, making your file unable to load and destroying saved Jack connections.
"name" : "Tembro",

#Set this to the name the user types into a terminal.
#MUST be the same as the binary name as well as the name in configure.
#Program reports that as proc title so you can killall it by name.
#Should not contain spaces or special characters. We use this as save file extension as well
#to distinguish between compatible program versions. In basic programs this will just be e.g.
#patroneo. But in complex programs with a bright future it will be "laborejo1" "laborejo2" etc.
"shortName" : "tembro",

#A very short description used in various places: Desktop file, overview on the website,
#release announcements, entries in software directories etc.
"tagline" : 'Sampled Software Instruments ',

"version" : "0.1.0",
"year" : "2021",
"author" : "Laborejo Software Suite",
"url" : "https://www.laborejo.org/tembro",

"supportedLanguages" : {"German":"de.qm"},

#Show the About Dialog the first time the program starts up. This is the initial state for a
#new instance in NSM, not the saved state! Decide on how annoying it would be for every new
#instance to show about. Fluajho does not show it because you add it many times into a session.
#Patroneo does because its only added once.
"showAboutDialogFirstStart" : False,

#If your program handles very small duration with n-tuplets you should increase D4.
#This will not be visible to the outside jack world
"quarterNoteInTicks" : 96,

#How many audio outputs do you want? must be pairs. These are just unconnected jack outputs
#that need to be connected internally to instrument outputs like fluidsynth
"cboxOutputs" : 2 * 4,

#Does the program uses a metronome? In this case you need at least two cboxOutputs above
"metronome" : False,

#Various strings for the README
#Extra whitespace will be stripped so we don't need to worry about docstring indentation
"description" : """
Tembro (which is Esperanto for musical "Timbre") is a virtual software instrument based on
samples. All instruments are permanently built-in, there is no option to load your own files.
New instruments are only added with new releases, old ones are never removed.

That makes Tembro reliable, predictable, portable and compatible.
All projects and all users have the same "instrument" with the same instrument sounds,
numbering system, midi controls etc.

Only "soft" settings, such as filters, can be changed dynamically and will be saved in your project.
""",

"dependencies" : "\n".join("* "+dep for dep in ()),
}

+ 40
- 0
engine/main.py View File

@@ -0,0 +1,40 @@
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Copyright 2021, Nils Hilbricht, Germany ( https://www.hilbricht.net )

This file is part of the Laborejo Software Suite ( https://www.laborejo.org ),

This application 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, either version 3 of the License, or
(at your option) any later version.

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, see <http://www.gnu.org/licenses/>.
"""

import logging; logger = logging.getLogger(__name__); logger.info("import")

#Python Standard Lib
import os.path

#Third Party
from calfbox import cbox

#Template Modules
from template.engine.data import Data as TemplateData
from template.start import PATHS

class Data(TemplateData):
"""There must always be a Data class in a file main.py.
Simply inheriting from engine.data.Data is easiest.
"""

def __init__(self, parentSession): #Program start.
pass

+ 0
- 0
qtgui/__init__.py View File


+ 30
- 0
qtgui/constantsAndConfigs.py View File

@@ -0,0 +1,30 @@
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Copyright 2021, Nils Hilbricht, Germany ( https://www.hilbricht.net )

This file is part of the Laborejo Software Suite ( https://www.laborejo.org ),

Laborejo2 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, either version 3 of the License, or
(at your option) any later version.

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, see <http://www.gnu.org/licenses/>.
"""

import logging; logging.info("import {}".format(__file__))

from template.qtgui.constantsAndConfigs import ConstantsAndConfigs as TemplateConstantsAndConfigs

class ConstantsAndConfigs(TemplateConstantsAndConfigs):
def __init__(self):
super().__init__()
constantsAndConfigs = ConstantsAndConfigs() #singleton

+ 93
- 0
qtgui/designer/mainwindow.py View File

@@ -0,0 +1,93 @@
# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'mainwindow.ui'
#
# Created by: PyQt5 UI code generator 5.15.4
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.


from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(894, 836)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
self.verticalLayout.setObjectName("verticalLayout")
self.splitter_2 = QtWidgets.QSplitter(self.centralwidget)
self.splitter_2.setOrientation(QtCore.Qt.Horizontal)
self.splitter_2.setObjectName("splitter_2")
self.search_groupBox = QtWidgets.QGroupBox(self.splitter_2)
self.search_groupBox.setObjectName("search_groupBox")
self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.search_groupBox)
self.verticalLayout_4.setContentsMargins(0, 0, 0, 0)
self.verticalLayout_4.setSpacing(0)
self.verticalLayout_4.setObjectName("verticalLayout_4")
self.search_listWidget = QtWidgets.QListWidget(self.search_groupBox)
self.search_listWidget.setObjectName("search_listWidget")
self.verticalLayout_4.addWidget(self.search_listWidget)
self.splitter = QtWidgets.QSplitter(self.splitter_2)
self.splitter.setOrientation(QtCore.Qt.Vertical)
self.splitter.setObjectName("splitter")
self.iinstruments_groupBox = QtWidgets.QGroupBox(self.splitter)
self.iinstruments_groupBox.setObjectName("iinstruments_groupBox")
self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.iinstruments_groupBox)
self.verticalLayout_2.setContentsMargins(0, 0, 0, 0)
self.verticalLayout_2.setSpacing(0)
self.verticalLayout_2.setObjectName("verticalLayout_2")
self.instruments_treeWidget = QtWidgets.QTreeWidget(self.iinstruments_groupBox)
self.instruments_treeWidget.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
self.instruments_treeWidget.setProperty("showDropIndicator", False)
self.instruments_treeWidget.setAlternatingRowColors(True)
self.instruments_treeWidget.setSelectionMode(QtWidgets.QAbstractItemView.NoSelection)
self.instruments_treeWidget.setVerticalScrollMode(QtWidgets.QAbstractItemView.ScrollPerPixel)
self.instruments_treeWidget.setHorizontalScrollMode(QtWidgets.QAbstractItemView.ScrollPerPixel)
self.instruments_treeWidget.setObjectName("instruments_treeWidget")
self.verticalLayout_2.addWidget(self.instruments_treeWidget)
self.details_groupBox = QtWidgets.QGroupBox(self.splitter)
self.details_groupBox.setObjectName("details_groupBox")
self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.details_groupBox)
self.verticalLayout_3.setContentsMargins(0, 0, 0, 0)
self.verticalLayout_3.setSpacing(0)
self.verticalLayout_3.setObjectName("verticalLayout_3")
self.details_scrollArea = QtWidgets.QScrollArea(self.details_groupBox)
self.details_scrollArea.setWidgetResizable(True)
self.details_scrollArea.setObjectName("details_scrollArea")
self.scrollAreaWidgetContents = QtWidgets.QWidget()
self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(0, 0, 428, 208))
self.scrollAreaWidgetContents.setObjectName("scrollAreaWidgetContents")
self.details_scrollArea.setWidget(self.scrollAreaWidgetContents)
self.verticalLayout_3.addWidget(self.details_scrollArea)
self.verticalLayout.addWidget(self.splitter_2)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 894, 20))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.actionRofl = QtWidgets.QAction(MainWindow)
self.actionRofl.setObjectName("actionRofl")

self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)

def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.search_groupBox.setTitle(_translate("MainWindow", "Search"))
self.iinstruments_groupBox.setTitle(_translate("MainWindow", "Instruments"))
self.instruments_treeWidget.headerItem().setText(0, _translate("MainWindow", " "))
self.instruments_treeWidget.headerItem().setText(1, _translate("MainWindow", "ID"))
self.instruments_treeWidget.headerItem().setText(2, _translate("MainWindow", "Name"))
self.instruments_treeWidget.headerItem().setText(3, _translate("MainWindow", "Version"))
self.instruments_treeWidget.headerItem().setText(4, _translate("MainWindow", "Vendor"))
self.instruments_treeWidget.headerItem().setText(5, _translate("MainWindow", "Logo"))
self.details_groupBox.setTitle(_translate("MainWindow", "NamePlaceholder"))
self.actionRofl.setText(_translate("MainWindow", "Rofl!"))

+ 189
- 0
qtgui/designer/mainwindow.ui View File

@@ -0,0 +1,189 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>894</width>
<height>836</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QSplitter" name="splitter_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<widget class="QGroupBox" name="search_groupBox">
<property name="title">
<string>Search</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_4">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QListWidget" name="search_listWidget"/>
</item>
</layout>
</widget>
<widget class="QSplitter" name="splitter">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<widget class="QGroupBox" name="iinstruments_groupBox">
<property name="title">
<string>Instruments</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QTreeWidget" name="instruments_treeWidget">
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="showDropIndicator" stdset="0">
<bool>false</bool>
</property>
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::NoSelection</enum>
</property>
<property name="verticalScrollMode">
<enum>QAbstractItemView::ScrollPerPixel</enum>
</property>
<property name="horizontalScrollMode">
<enum>QAbstractItemView::ScrollPerPixel</enum>
</property>
<column>
<property name="text">
<string> </string>
</property>
</column>
<column>
<property name="text">
<string>ID</string>
</property>
</column>
<column>
<property name="text">
<string>Name</string>
</property>
</column>
<column>
<property name="text">
<string>Version</string>
</property>
</column>
<column>
<property name="text">
<string>Vendor</string>
</property>
</column>
<column>
<property name="text">
<string>Logo</string>
</property>
</column>
</widget>
</item>
</layout>
</widget>
<widget class="QGroupBox" name="details_groupBox">
<property name="title">
<string>NamePlaceholder</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QScrollArea" name="details_scrollArea">
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="scrollAreaWidgetContents">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>428</width>
<height>208</height>
</rect>
</property>
</widget>
</widget>
</item>
</layout>
</widget>
</widget>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>894</width>
<height>20</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
<action name="actionRofl">
<property name="text">
<string>Rofl!</string>
</property>
</action>
</widget>
<resources/>
<connections/>
</ui>

+ 165
- 0
qtgui/instrument.py View File

@@ -0,0 +1,165 @@
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Copyright 2021, Nils Hilbricht, Germany ( https://www.hilbricht.net )

This file is part of the Laborejo Software Suite ( https://www.laborejo.org ),

This application 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, either version 3 of the License, or
(at your option) any later version.

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, see <http://www.gnu.org/licenses/>.
"""

import logging; logger = logging.getLogger(__name__); logger.info("import")

#Standard Library

#Third Party
from PyQt5 import QtCore, QtGui, QtWidgets

#Our Qt
from template.qtgui.helper import ToggleSwitch

#Engine
import engine.api as api

class InstrumentTreeController(object):
"""Not a qt class. We externally controls the QTreeWidget

Why is this not a QTableWidget? As in Agordejo, a TableWidget is a complex item, and inconvenient
to use. You need to add an Item to each cell. While in TreeWidget you just create one item.

And we might use the TreeView to group by manufacturer etc. Eventhough we have a Filter.
"""

def __init__(self, parentMainWindow):
self.parentMainWindow = parentMainWindow
self.treeWidget = self.parentMainWindow.ui.instruments_treeWidget

self.sortByColumnValue = 1 #by instrId
self.sortDescendingValue = 0 # Qt::SortOrder which is 0 for ascending and 1 for descending

self._testData()

def newInstrument(self, instrumentDict):
gi = GuiInstrument(parentTreeController=self, instrumentDict=instrumentDict)
self.treeWidget.addTopLevelItem(gi)
gi.injectToggleSwitch() #only possible after gi.init was done and item inserted.
self._adjustColumnSize()

def _testData(self):
exampleInstrumentDict1 = {
"instrId" : 123,
"state": False,
"prettyName" : "My Instrument 2000",
"vendor" : "Nils Productions",
"version" : "1.0.3",
"logo" : None,
}
exampleInstrumentDict2 = {
"instrId" : 124,
"state": False,
"prettyName" : "Untuned Guitar",
"vendor" : "Merle Instrument Design",
"version" : "0.4.1",
"logo" : None,
}

self.newInstrument(exampleInstrumentDict1)
self.newInstrument(exampleInstrumentDict2)

def _adjustColumnSize(self):
self.treeWidget.sortItems(self.sortByColumnValue, self.sortDescendingValue)
for index in range(self.treeWidget.columnCount()):
self.treeWidget.resizeColumnToContents(index)


class GuiInstrument(QtWidgets.QTreeWidgetItem):
"""
Why is this not a QTableWidget? As in Agordejo, a TableWidget is a complex item, and inconvenient
to use. You need to add an Item to each cell. While in TreeWidget you just create one item.

All data is received at program start. No new items will be created, none will get deleted.
All instruments in Tembro are static.

By default all instruments are switched off. The user can switch them on/off here or
a loaded save state will send the state on program start.

Most parameters we receive are read only, like instrId, prettyName and version"""

allItems = {} # instrId : GuiInstrument

def __init__(self, parentTreeController, instrumentDict):
GuiInstrument.allItems[instrumentDict["instrId"]] = self
self.parentTreeController = parentTreeController

#Start with empty columns. We fill in later in _writeColumns
super().__init__([], type=1000) #type 0 is default qt type. 1000 is subclassed user type)


self.columns = ("state" , "instrId", "prettyName", "version", "vendor", "logo") #Same keys as instrumentDict. Keep in sync manually with Qt Designer. All code must use this, never number directly.
#Use with:
#nameColumnIndex = self.columns.index("prettyName")
#self.setText(nameColumnIndex, "hello")

self.state = None #by self.switch()
self.instrumentDict = None
self._writeColumns(instrumentDict)

self.toggleSwitch = ToggleSwitch()
self.toggleSwitch.setAutoFillBackground(True) #otherwise conflicts with setItemWidget
self.toggleSwitch.toggled.connect(lambda c: print('toggled', c))
self.toggleSwitch.clicked.connect(lambda c: print('clicked', c))
self.toggleSwitch.pressed.connect(lambda: print('pressed'))
self.toggleSwitch.released.connect(lambda: print('released'))

#We cannot add the ToggleSwitch Widget here.
#It must be inserted after self was added to the Tree. Use self.injectToggleSwitch from parent


def injectToggleSwitch(self):
"""Call this after the item was added to the tree"""
stateColumnIndex = self.columns.index("state")
self.parentTreeController.treeWidget.setItemWidget(self, stateColumnIndex, self.toggleSwitch)

def _writeColumns(self, instrumentDict):
self.instrumentDict = instrumentDict

for index, key in enumerate(self.columns):
value = instrumentDict[key]
QtCore.QCoreApplication.translate("OpenSession", "not saved")

if type(instrumentDict[key]) is str or key == "instrId":
self.setText(index, str(instrumentDict[key]))

elif key == "logo":
pass

elif key == "state": #use parameter for initial value. loaded from file or default = False.
state = instrumentDict[key]
assert type(state) is bool, state
self.switch(state)





def switch(self, state:bool):
"""This is not the Qt function but if an instrument is enabled, loaded to RAM and ready to
receive midi data.

Function will mimic Qt disabled behaviour by greying things out and deactivating individual
sub-widgets. But some, like the GUI switch itself, will always stay enabled."""
self.state = state

def toggleSwitchState(self):
self.switch(not self.state)

+ 85
- 0
qtgui/mainwindow.py View File

@@ -0,0 +1,85 @@
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Copyright 2021, Nils Hilbricht, Germany ( https://www.hilbricht.net )

This file is part of the Laborejo Software Suite ( https://www.laborejo.org ),

This application 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, either version 3 of the License, or
(at your option) any later version.

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, see <http://www.gnu.org/licenses/>.
"""
import logging; logging.info("import {}".format(__file__))

#Standard Library Modules
import os.path

#Third Party Modules
from PyQt5 import QtWidgets, QtCore, QtGui

#Template Modules
from template.qtgui.mainwindow import MainWindow as TemplateMainWindow
from template.qtgui.menu import Menu
from template.qtgui.about import About

#Our modules
import engine.api as api

from .instrument import InstrumentTreeController


class MainWindow(TemplateMainWindow):

def __init__(self):
"""The order of calls is very important.
The split ploint is calling the super.__init. Some functions need to be called before,
some after.
For example:

The about dialog is created in the template main window init. So we need to set additional
help texts before that init.
"""

#Inject more help texts in the templates About "Did You Know" field.
#About.didYouKnow is a class variable.
#Make the first three words matter!
#Do not start them all with "You can..." or "...that you can", in response to the Did you know? title.
#We use injection into the class and not a parameter because this dialog gets shown by creating an object. We can't give the parameters when this is shown via the mainWindow menu.
About.didYouKnow = [
QtCore.QCoreApplication.translate("About", "There is no way to load your own instruments into this program. If you create your own instruments and would like them to be included please contact the developers for a collaboration.")
] + About.didYouKnow

super().__init__()

#make the search bar smaller
self.ui.search_groupBox.setMinimumSize(30, 1)
self.ui.splitter_2.setSizes([1,1])

self.setupMenu()

self.instrumentTreeController = InstrumentTreeController(parentMainWindow=self)

self.start() #This shows the GUI, or not, depends on the NSM gui save setting. We need to call that after the menu, otherwise the about dialog will block and then we get new menu entries, which looks strange.


def setupMenu(self):
"""In its own function purely for readability"""
#New menu entries and template-menu overrides
#self.menu.connectMenuEntry("actionAbout", lambda: print("About Dialog Menu deactivated")) #deactivates the original function
self.menu.addMenuEntry("menuEdit", "actionNils", "Nils", lambda: print("Merle"))
#self.menu.connectMenuEntry("actionNils", lambda: print("Override"))

def zoom(self, scaleFactor:float):
pass
def stretchXCoordinates(self, factor):
pass


+ 884
- 0
qtgui/resources.py View File

@@ -0,0 +1,884 @@
# -*- coding: utf-8 -*-

# Resource object code
#
# Created by: The Resource Compiler for PyQt5 (Qt v5.15.2)
#
# WARNING! All changes made in this file will be lost!

from PyQt5 import QtCore

qt_resource_data = b"\
\x00\x00\x03\xae\
\x89\
\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
\x00\x00\x20\x00\x00\x00\x20\x08\x06\x00\x00\x00\x73\x7a\x7a\xf4\
\x00\x00\x00\x04\x73\x42\x49\x54\x08\x08\x08\x08\x7c\x08\x64\x88\
\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x01\xd8\x00\x00\x01\xd8\
\x01\xfa\x5c\xa6\x72\x00\x00\x00\x19\x74\x45\x58\x74\x53\x6f\x66\
\x74\x77\x61\x72\x65\x00\x77\x77\x77\x2e\x69\x6e\x6b\x73\x63\x61\
\x70\x65\x2e\x6f\x72\x67\x9b\xee\x3c\x1a\x00\x00\x03\x2b\x49\x44\
\x41\x54\x58\x85\xc5\x96\xcd\x4b\xdb\x60\x1c\xc7\x13\x67\xd3\x17\
\x74\x50\x68\x91\xc1\x0e\xc3\xe3\x84\x61\xb4\x87\xd2\x26\xc2\x60\
\xfb\x1b\x1c\xeb\xb2\x2e\x85\xa6\xf6\xb4\x81\xa7\xc1\x04\xcb\x76\
\x69\xbb\x31\xb0\x30\xbb\xe9\x36\xf7\xc2\x8e\x8e\x79\x55\xac\x2f\
\xa1\x5e\x84\xa5\x35\xf4\x50\xa6\xb2\x5a\xa5\x52\xa5\x5b\x34\x6d\
\xed\xcb\xb2\xcb\x22\x69\x9a\xd6\xa7\x1a\xba\xdf\x35\xdf\x3c\x9f\
\x4f\x9e\xe7\x97\x5f\x02\x41\xe7\x2f\x98\xa2\xa8\xd7\x1e\x8f\xe7\
\x03\x04\x41\x1d\x17\x58\xe7\x7c\x70\xb7\xdb\x1d\xde\xdd\xdd\xad\
\xee\xef\xef\xff\xf1\x7a\xbd\x1f\xdb\x29\x71\x0a\xe7\x38\x4e\xe0\
\x38\x4e\x68\xa7\x44\x1d\xbc\xad\x12\x14\x45\xbd\x52\x82\x4b\x25\
\x46\x46\x46\xde\xb7\xb2\x26\xa8\x2d\x6c\xb5\x5a\x1d\x3c\xcf\x27\
\x0f\x0e\x0e\x0a\x8d\x42\x87\x87\x87\x27\xb9\x5c\x2e\x85\xe3\xf8\
\x03\xd0\xb5\x41\x42\xb0\xdb\xed\x9e\x9c\x9e\x9e\x9e\xd1\x6a\xb5\
\xbd\x81\x40\xe0\xc9\xf6\xf6\x36\x2f\x0f\xa5\xd3\xe9\xa2\xcf\xe7\
\x0b\x18\x0c\x06\x43\x38\x1c\x9e\xf2\x7a\xbd\x33\xa0\x12\x67\xc1\
\x4f\xcf\x3c\x95\x4a\x55\x5c\x2e\xd7\x84\xc3\xe1\x78\x14\x8b\xc5\
\x8e\xc5\xad\x4f\x24\x12\x85\xe1\xe1\x61\x1f\x49\x92\xc1\xad\xad\
\xad\x92\x5a\x3d\xa1\xd8\x70\x72\x09\x25\x78\x2b\x8d\x79\xa9\x09\
\x7c\x72\x7c\x7c\xdc\xdd\xdd\xdd\x5d\x73\xb3\x4e\xa7\xeb\xb0\x5a\
\xad\x16\x9a\xa6\x7f\xac\xae\xae\x7e\x5d\x5b\x5b\x8b\x22\x08\x72\
\x79\x6c\x6c\xec\xa1\xc9\x64\xd2\x48\xb3\x1a\x8d\x06\xc6\x30\xec\
\x06\xcf\xf3\xbd\xeb\xeb\xeb\xdf\x20\x08\x12\x80\x1e\x1d\xc7\xf1\
\x3b\x0c\xc3\x9c\x34\xea\x76\x8e\xe3\x04\x9a\xa6\x8f\x2d\x16\xcb\
\x6d\x14\x45\x87\x16\x17\x17\x7f\x37\xcb\x6e\x6c\x6c\x94\x30\x0c\
\xbb\x0f\xbc\x03\xa9\x54\x8a\x2d\x14\x0a\xda\x81\x81\x01\x6b\x57\
\x57\x57\x5d\x26\x9d\x4e\x17\x03\x81\xc0\xf3\xf9\xf9\xf9\xb7\x99\
\x4c\xe6\x67\xa5\x52\x29\xf6\xf5\xf5\xe1\x46\xa3\x11\x91\x67\xb3\
\xd9\x6c\xd9\xef\xf7\xbf\x9c\x9b\x9b\x7b\x01\xf4\xf4\xd2\x72\x3a\
\x9d\x4f\x93\xc9\x64\xcd\x4e\x88\x67\x2e\xcf\xca\x1b\x93\xe3\x38\
\x61\x73\x73\xb3\x44\x92\xa4\xbf\x65\x70\x23\x89\x46\x70\x25\x09\
\x55\xe0\x52\x89\x48\x24\xc2\x35\x83\x4b\x25\x16\x16\x16\x7e\xa9\
\x06\x17\x0b\x45\xd1\x5b\xa0\xd9\xfe\xfe\x7e\x3b\x68\x16\x78\x48\
\x74\x76\x76\x96\x41\xb3\x30\x0c\xeb\x41\xb3\x40\x45\x92\x64\x70\
\x79\x79\xf9\xc8\xe9\x74\x3e\x3e\x2b\x4b\x10\xc4\xe8\xca\xca\xca\
\x91\xcb\xe5\x9a\x50\x0d\x2e\x4e\xb8\x44\x22\x91\x6f\x26\x41\x10\
\xc4\x28\xcb\xb2\xc7\xd2\x89\xa9\x1a\x5c\xf2\x1a\x2a\x4a\x48\xe1\
\xf2\xb1\xad\x1a\xbc\x91\x84\x12\xfc\x42\x12\x76\xbb\xdd\xc9\xb2\
\x6c\xb9\xd9\x78\x8d\x44\x22\x1c\x8a\xa2\x43\x83\x83\x83\x37\x97\
\x96\x96\x8e\x9a\x65\xe3\xf1\x78\x09\xc3\x30\x42\x89\xa5\x38\x8a\
\x77\x76\x76\xe2\xd5\x6a\xf5\xaa\xcd\x66\x43\x11\x04\x81\xe5\xd7\
\xb3\xd9\x6c\x39\x14\x0a\x85\x7a\x7a\x7a\xcc\x66\xb3\xf9\x0a\xc3\
\x30\xdf\x1b\x8d\xed\x7c\x3e\x2f\x04\x83\xc1\x4f\xb3\xb3\xb3\xcf\
\x20\xd0\x8f\xd1\xbf\x82\x3d\x1e\xcf\x9b\xbd\xbd\xbd\x9a\xcf\xb1\
\x38\xe1\xc4\x6d\x17\x8f\x43\x69\x6c\x67\x32\x19\xf1\x17\xed\xfc\
\xff\x04\x52\x09\x39\x5c\xde\x13\x52\x09\x35\xe0\x35\x12\xb1\x58\
\xec\x44\x09\xae\x24\xc1\x30\x4c\x51\x2d\xf8\xa9\x84\xcd\x66\xbb\
\xd7\xac\xdb\xa5\x12\x18\x86\xdd\x85\x20\xa8\xae\x77\x94\x0a\xd4\
\x50\x88\x46\xa3\x9f\xf5\x7a\xfd\x75\x93\xc9\x64\x68\x14\x32\x1a\
\x8d\x3a\xad\x56\x7b\x8d\xa6\xe9\x2f\x50\x8b\x0d\x07\x5a\x8a\x8d\
\xa9\xf6\x99\xb7\x2c\xd1\x4e\x78\x9d\xc4\xff\x80\x4b\x25\xde\x51\
\x14\x35\x05\x01\x36\x9c\x52\xfd\x05\xed\x5a\xa6\x43\x90\x43\xd4\
\xd6\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\
\x00\x00\x2d\x28\
\x89\
\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
\x00\x01\x2c\x00\x00\x00\x97\x08\x06\x00\x00\x00\xaf\x07\x66\x77\
\x00\x00\x00\x06\x62\x4b\x47\x44\x00\x80\x00\x78\x00\x73\xdb\x4b\
\x12\x83\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x2e\x23\x00\x00\
\x2e\x23\x01\x78\xa5\x3f\x76\x00\x00\x00\x07\x74\x49\x4d\x45\x07\
\xe2\x08\x18\x12\x27\x11\x9d\x52\xc1\x11\x00\x00\x00\x19\x74\x45\
\x58\x74\x43\x6f\x6d\x6d\x65\x6e\x74\x00\x43\x72\x65\x61\x74\x65\
\x64\x20\x77\x69\x74\x68\x20\x47\x49\x4d\x50\x57\x81\x0e\x17\x00\
\x00\x20\x00\x49\x44\x41\x54\x78\xda\xed\x9d\xe9\x73\x9c\xd7\x75\
\xe6\x7f\x8d\xc6\x0e\x90\xe0\xbe\x89\xa4\xa8\x8d\xd4\x42\xed\x96\
\x6c\xcb\x92\x05\xdb\x34\x93\x78\xbc\x4d\x32\x53\x53\x9e\x9a\xa9\
\x9a\xaa\xa4\x6a\xe6\x7b\xf0\x21\xf8\xd4\xc1\xa7\xfe\xd2\xff\x43\
\xaa\x52\x93\x99\xcc\x4c\x32\x71\x9c\xd8\x13\xd3\xa6\x6d\xda\x96\
\x17\x2d\x96\x65\x85\x5a\x28\x51\x24\x25\x2e\xe0\x06\x92\x00\xb1\
\xf6\x36\x1f\xee\x73\xfc\x5e\xbc\x7c\xdf\x46\x03\x04\xd0\xdd\xc0\
\x3d\x55\x6f\x75\x63\x6b\xbc\xcb\xbd\xcf\x7d\xce\x39\xcf\x3d\x27\
\xf3\x97\x7f\xf1\xe7\x04\x0b\x16\x2c\x58\x2b\x58\x5b\xb8\x05\xc1\
\x82\x05\x0b\x80\x15\x2c\x58\xb0\x60\x01\xb0\x82\x05\x0b\x16\x00\
\x2b\x58\xb0\x60\xc1\x02\x60\x05\x0b\x16\x2c\x58\x00\xac\x60\xc1\
\x82\x05\xc0\x0a\x16\x2c\x58\xb0\x00\x58\xc1\x82\x05\x0b\x16\x00\
\x2b\x58\xb0\x60\x01\xb0\x82\x05\x0b\x16\x2c\x00\x56\xb0\x60\xc1\
\x82\x05\xc0\x0a\x16\x2c\x58\x00\xac\xb8\xe5\xf2\x85\x4c\x2e\x5f\
\xc8\x84\xdb\x17\x2c\x58\xb0\xd5\xb4\x4c\xbd\xd5\x1a\x04\x50\xed\
\x40\x0f\xd0\x07\x64\x80\x22\x30\x01\x14\x47\x86\x87\xca\xe1\x76\
\x06\x0b\x16\xac\xe1\x0c\x4b\x60\xd5\x03\xec\x03\x9e\x06\xbe\x04\
\x7c\x19\x18\x04\x1e\x05\xb6\xe6\xf2\x85\xf6\x70\x3b\x83\x05\x0b\
\xb6\x92\x96\x1d\x7c\xf1\x85\x7a\xc1\x6a\x3f\xf0\x59\xe0\x0b\xc0\
\x67\x80\xc7\x81\x07\x80\x1d\x40\x05\x18\x1f\x3c\x72\x74\xe6\xc4\
\xf1\x63\x95\x70\x5b\x83\x05\x0b\xd6\x28\x86\xd5\x06\x0c\x00\x87\
\xc5\xaa\xfe\x10\xf8\x3c\xf0\x92\x18\xd6\x1f\x01\x47\x80\x87\x80\
\xde\x10\xdb\x0a\x16\x2c\xd8\x4a\x59\x3d\x6e\x5c\x27\xb0\x5b\xae\
\xdf\x23\x62\x5a\xdd\xb8\x18\x56\xbf\xde\xdf\x06\xce\x01\xe7\x81\
\x49\x20\xc4\xb3\x82\xb5\xbc\xe5\xf2\x85\x36\x20\xab\xb1\x0e\x50\
\x95\x37\x51\x19\x19\x1e\xaa\x86\x3b\xd4\x9c\x80\xd5\x26\x60\xba\
\x47\xee\x5f\x97\xc7\xcc\xb2\xfa\xd9\x5e\xe0\x00\xb0\x45\xa0\x15\
\x00\x2b\x58\xab\x82\x54\x56\x63\xbc\x47\x63\xbb\x4f\xf3\x24\x03\
\xcc\x6a\x41\x1e\xcf\xe5\x0b\x53\x40\x29\x00\x57\xf3\x01\x56\x46\
\x2c\xab\xdb\x7b\x70\x71\x40\xdb\x00\xec\x94\xeb\x98\x0d\xb7\x35\
\x58\x8b\x02\xd5\x46\x60\xbb\x16\xdf\x5d\x3a\x7a\x34\xf6\x4b\x02\
\xab\x2b\xf2\x26\x3e\x02\xae\xe4\xf2\x85\xa9\x00\x5a\xcd\x05\x58\
\x73\x38\xe9\xc2\xac\x98\x53\x35\x01\xd0\x3a\xf4\x60\x3b\x09\x62\
\xd4\x60\xad\xe7\xf6\xf5\x03\xf7\xe2\x32\xe0\x87\x71\xf1\xd8\x6d\
\x02\xb0\x0e\x2d\xc2\x25\x60\x06\xb8\x0a\x9c\x01\xde\x04\x5e\x05\
\x4e\xe7\xf2\x85\xdb\x01\xb4\x9a\x07\xb0\xca\xc0\x38\x70\x0d\x98\
\x96\x0f\x1f\x67\x51\x59\x7d\x56\xb7\x1e\x70\xb0\x60\xad\x02\x56\
\xdb\x81\xa7\x70\x09\xa5\x4f\x89\x5d\x6d\xd4\x58\xce\x7a\x0b\x70\
\x55\x73\x61\x16\xb8\x1f\x27\xf1\xe9\xd7\xcf\x4e\x01\x53\xe1\x8e\
\x36\x07\x60\x55\x70\x41\xf5\xcb\xc0\x4d\x3d\xb4\xb8\x6b\x98\xf1\
\xfc\xfe\xa0\xc7\x5a\x5b\x93\x3a\xa3\x49\x6b\xcf\xbb\x32\x32\x3c\
\x54\x59\x03\xd7\xd5\x06\x6c\x16\x48\x7d\x1d\x78\x19\xd8\x03\xf4\
\xc6\xae\x37\x3e\x5f\x2c\x3c\x62\x1e\x45\x19\x98\xcb\xe5\x0b\x1f\
\x8d\x0c\x0f\xcd\x84\x11\xd3\x60\xc0\x1a\x19\x1e\xaa\xe6\xf2\x85\
\x19\xe0\xba\x00\x6b\x4e\xe0\x14\x67\x58\xdd\xb8\x58\x56\x67\xb8\
\xad\x89\x13\xde\xcf\x38\x65\x34\xd0\x2b\x5a\xb9\x9b\x0e\x04\xbc\
\x9d\x0d\xdd\xb8\xc0\xb3\x25\x5b\xe6\x72\xf9\xc2\xb4\xd8\xf6\x1c\
\xad\x9b\x31\x6b\xc7\x65\xbc\x5f\x12\x58\xdd\xab\x6b\xac\x25\xcb\
\xb1\x67\xd7\x89\x4b\x40\x55\xe5\x2a\xce\x02\xe5\x5c\xbe\x70\x2e\
\x80\x56\xe3\x19\x16\x1a\x98\xb7\x74\xcc\x8a\x0a\x67\x62\x80\xd5\
\x87\xcb\x12\xf6\xe4\xf2\x85\xb6\xb5\xb0\x0a\x2f\xc3\x0a\xde\xab\
\x7b\xb5\x5d\x2b\x72\x2f\x51\x06\xb5\x28\xc0\x9a\x01\x26\x73\xf9\
\xc2\x2d\xa2\x6d\x4e\x95\x26\x00\xab\x4e\x5c\x12\x65\x0f\xf3\x33\
\xc4\x55\x8d\x83\x31\xe0\x12\x70\x2d\x97\x2f\xdc\x00\xe6\x5a\xec\
\x99\x6f\xc4\xc5\xaa\x1e\xd1\xf3\x59\x08\xac\xe2\xc0\xd5\xa1\xbf\
\x7b\x54\xa0\x05\xf0\xe3\x5c\xbe\xf0\xf1\xc8\xf0\xd0\x74\x80\x96\
\xc6\x02\x56\x51\xec\xca\x00\x2b\xbe\xa2\x5a\xe0\x72\xb3\x58\x56\
\xbb\x40\x6e\xbd\x82\x55\x37\xb0\x15\x78\x0c\x78\x50\x13\xa3\x5f\
\x80\x55\xd4\xfd\x2b\x0a\xbc\xa6\x71\x81\xdc\xb3\xc0\xfb\xc0\xd9\
\x5c\xbe\x70\xab\xc1\x7b\x33\xdb\x05\x56\x0f\x01\x4f\x6a\x52\xee\
\xd5\xb3\xcd\xea\xd9\xde\xc4\x65\xcb\x3e\x00\xde\xc2\x05\x9f\x6f\
\x8e\x0c\x0f\x95\x5a\x64\x31\xe9\xd2\x35\x6e\xd0\x62\x52\x0b\xac\
\xaa\x31\xb0\xf2\xc3\x20\x3b\x75\x8f\x2c\xf1\xf4\xc3\x5c\xbe\x70\
\x7a\x64\x78\x28\xc4\xb4\x1a\x08\x58\x25\x5c\x1c\x6b\x0c\x17\x5c\
\xf4\x03\xef\xe6\xf2\xf4\x08\xb0\x2c\xb3\x32\xb7\x8e\xc1\xea\x7e\
\xe0\xd3\xc0\x17\x81\x87\x71\x19\x27\x8b\x8d\xfc\x5e\x7c\x68\xf1\
\x0f\x31\xab\x8b\xc0\x3b\xc0\x4f\x81\x37\x72\xf9\xc2\x95\x91\xe1\
\xa1\xe2\x2a\xba\x7e\x1d\xde\x6b\xaf\x00\xea\x29\xdc\x6e\x86\x27\
\x74\x0d\x9d\x9e\x3b\x3b\x8b\x4b\xc6\x9c\xd7\xcf\x4f\x00\xaf\xe5\
\xf2\x85\x4b\x23\xc3\x43\xb3\x2d\xf0\xa8\xb2\x5e\xac\xca\x5c\xf3\
\x4c\x02\x50\x55\x34\xfe\xab\xba\x3f\xd9\x04\xd0\xda\x25\xd7\x79\
\xb3\xbc\x8c\x7f\xca\xe5\x0b\xef\x8c\x0c\x0f\xdd\x0e\x10\xd3\x18\
\xc0\x2a\x0b\xb0\x6e\x0a\xb0\xe2\x81\xf7\x36\x2f\x86\x65\x80\xb5\
\x1e\xc1\xaa\x53\x2e\xd4\xf3\xc0\xbf\xd5\xca\xbb\x9d\x3b\xe5\x1e\
\xd5\xd8\xfb\x32\x70\x9f\x80\xee\x1e\xb1\xb1\x9f\xe5\xf2\x85\xd1\
\x95\x04\x2d\x9d\xef\x06\xdc\x4e\x86\xad\x7a\x76\x5d\x44\x42\xe1\
\xc7\x70\x7b\x46\xf7\x25\xb8\x4c\xc6\xa8\x77\xea\x77\x77\xe9\xb3\
\x7e\x91\xcb\x17\x3e\x06\xa6\x9b\x31\xb6\x25\xbd\x55\x2f\xb0\xc9\
\x73\xd1\x8b\xb1\x45\xb8\xea\x3d\x97\x39\xb1\x60\xf4\x1c\x7b\x62\
\x63\xdf\xdc\xc3\xad\x9a\x03\x03\x0a\x8f\x7c\x3b\x97\x2f\xbc\x31\
\x32\x3c\x34\x19\x60\x66\xf5\x01\xcb\x62\x2d\x13\x7a\x2d\x27\xf8\
\xf4\xed\x1a\x00\xbd\xac\xdf\x4c\x61\x37\x2e\x78\xfb\x39\x81\xd5\
\x6e\x92\xc5\xb6\x99\x84\xd5\xbe\x43\xa0\xd0\xa7\xa3\x13\x38\x2e\
\xc6\x52\x5a\xe6\x49\xdb\xa6\xff\x71\xd0\x03\xa5\xed\x9a\xc4\x6d\
\x3a\x97\x3e\xc5\xad\x76\x31\x7f\x77\x03\x31\x66\xdd\x27\x40\xb3\
\xc9\xba\x15\x78\x05\x78\x2f\x97\x2f\x8c\x37\x83\x8b\x28\x90\x32\
\xe5\xfa\x1e\xb1\xc7\x43\x62\x90\xdb\x3d\x70\x4a\x7a\x4e\x59\x3d\
\x8b\x19\x1d\x55\x5d\x73\x9c\x69\x65\x05\xd8\x07\x80\xaf\xe9\xfb\
\x93\x62\x5a\x21\xa6\xb5\x5c\xb4\x78\xa1\x6a\x0d\x00\x27\x8e\x1f\
\x63\xf0\xc8\xd1\x5e\x3d\x8c\xc7\x34\x11\x3b\x63\x0f\x78\x0e\x18\
\x95\x5b\xf3\xd1\x89\xe3\xc7\xd6\xd5\xca\x22\x10\xd8\x06\x3c\x03\
\x3c\x8b\x0b\xe6\x2e\x14\x1b\x49\x9a\x1c\x3d\x02\x8e\x01\xb1\xd9\
\xab\x83\x47\x8e\x4e\x2f\x57\x15\x0c\x9d\xe7\x56\x5c\x3a\xff\x1b\
\xc0\xbf\x11\x23\x3c\x8c\xab\xbe\x71\x40\x00\xb4\x4b\xe7\xd1\x45\
\x7a\x9a\xdf\x3f\x6f\x63\x2d\xbb\x35\xa1\xe7\x80\xdb\xcb\x79\xee\
\x4b\xb8\xd6\xf6\xc1\x23\x47\x37\xe2\xb2\x81\xcf\xe1\x36\xed\xff\
\xa1\xdc\xdc\x17\x04\x5a\xbb\x75\xee\xbe\x8b\x98\xf1\x00\x39\xeb\
\xb9\x82\x33\xba\xae\x36\x7d\xaf\x2d\xe5\x5e\x58\x02\x6a\x06\x38\
\x3f\x78\xe4\xe8\xc4\x89\xe3\xc7\xc2\x76\xb5\x65\xb0\xc5\xa8\xd2\
\x2d\x6e\x91\x14\x74\xc7\x7b\x88\xed\x8b\x98\xa4\x6b\xd5\xfa\x97\
\x78\x1f\xfc\xec\xd3\xd3\xc0\x57\x04\x26\x5b\xc4\x12\x96\x83\x69\
\x6c\xc5\x95\x07\xfa\x96\x98\xc0\xb3\x02\xa9\xed\x02\xc9\x8d\x3a\
\x2c\x49\xd0\xa1\xf3\xaa\x2e\x70\xde\xed\x72\x11\x0f\xe2\xea\xa5\
\x7d\x4d\x0c\x66\x59\xce\x7d\x91\xd7\xd9\x91\xcb\x17\x36\x6b\x71\
\xfd\x0a\xf0\x67\xc0\x7f\x03\xfe\x54\xe7\xf5\x92\x62\x8b\xe6\x7e\
\x77\x30\x5f\x72\x92\x04\x5a\x5d\x7a\xbd\x8e\x4b\x92\xcc\xa4\xdc\
\x13\x8b\x6b\xed\xf5\xc0\x71\x4f\xa8\x17\xb7\xba\x2e\xa1\xb9\x85\
\x73\x9e\xbf\x9f\x06\x58\xd9\xf5\x04\x58\x0a\x5a\x9b\xdb\x60\xfb\
\x2d\x6f\x28\xee\xd1\x9d\xb0\x28\x54\xbd\x81\x9e\x49\x71\x43\xda\
\xc5\xd6\x9e\xc6\x05\xb6\x67\x70\x01\xed\x1b\x4b\xcd\x1e\xea\x3c\
\xfb\x05\x50\x7f\x82\x4b\x08\xec\x48\x60\xca\x69\x6e\x6b\xd5\x3b\
\x6a\x9d\xf7\x80\x62\x71\x25\x31\xee\xf3\xb8\xec\x72\x79\x15\x9e\
\x85\xed\x6b\xbd\x4f\x60\xf9\x3c\x2e\xc3\x79\x9f\xd8\x5f\x4f\x82\
\x2b\x57\xaf\x59\xe2\xe9\x1c\x91\xae\x6e\x0f\xc9\xba\x43\xbb\xd7\
\x0f\xe3\xca\x2f\xdd\x94\x7b\x78\x7d\xbd\xcb\x7d\x56\x1b\xb0\x4a\
\x44\xe9\xf8\x78\x56\xc5\xd8\x41\x37\xd0\x9e\xcb\x17\x32\x6b\x75\
\x7f\x95\x26\xbf\xc5\x9c\x36\x6a\x92\x0e\x08\x64\x06\x34\x98\x6f\
\xe9\x5e\x74\x79\x0c\xc5\x58\xea\x0c\x51\xb9\xe9\xb4\xf8\x90\x65\
\x9f\x9e\x91\x6b\x58\x04\xde\xca\xe5\x0b\x63\x8b\x05\x2d\x9d\x6f\
\xb7\xdc\xd4\x3f\x10\xc3\xaa\x05\x56\x69\x2c\xca\x9e\x3f\x35\xd8\
\xb4\xe9\xcf\x76\x28\x9e\xf7\x10\x70\x59\x59\xcf\xea\x0a\x3e\x8f\
\x4e\xdd\xaf\x67\xe5\xfa\x3d\xa7\xff\xbf\xb9\x0e\xb7\x36\x0e\xcc\
\xfe\xfb\x0a\x91\xac\xe7\x1c\xf0\xb6\x58\xd6\x9c\xe7\xfa\x25\x31\
\xc8\xac\xc6\xc2\x33\x62\x64\x97\x81\xd7\x08\x5b\x78\x56\xd5\x25\
\x34\x75\x73\x39\xe5\xb3\x6c\x7b\x4e\xc7\x5a\x65\x59\xa2\xf6\x1b\
\x35\x19\x9e\x93\xcb\xf1\xef\x81\xff\x04\xfc\x07\x73\x01\x34\xd8\
\x6f\x6b\x80\x4e\xe9\xfd\x35\xdc\x2e\xff\xd7\x81\x5f\xe9\xfd\x38\
\x91\xf0\x30\x7e\x3f\xfb\xc4\x56\x3e\x23\x57\xe6\xd3\xc0\xf6\x25\
\xb8\x17\x19\x31\x8c\x27\xc5\x3a\xf6\x2e\x00\x56\xd5\xd8\x61\x93\
\xf6\x96\x18\xd3\x47\x62\x4f\x13\x44\x29\xff\x24\xd0\xda\x49\x24\
\x3c\xed\x5f\x09\xb7\xc8\xab\xb2\xf0\x98\xee\xd1\x7f\x01\xbe\x29\
\x86\xb5\x2b\x81\x55\xa5\x5d\xaf\x2d\xc8\x73\x7a\x5e\x13\x62\xca\
\xa3\xc0\x87\xc0\x1b\xc0\xcf\x81\x5f\x03\x3f\x01\xbe\x83\xdb\x00\
\x3d\x91\xe2\x71\x18\xa8\xef\x10\x53\x7e\x02\xd8\x14\x0a\x5c\xae\
\x1e\xc3\x2a\x8b\x19\x4c\x27\x0c\xd2\x8c\x07\x58\xfd\x44\x69\xfc\
\xca\x1a\x02\x2a\x2b\x15\xbd\x0b\x17\xac\x3d\xac\xd7\xfd\x1a\x94\
\x03\x44\x9b\xbf\xb3\xde\x91\xf1\x18\x2a\xb8\x12\x25\x9f\x68\x12\
\x6c\xc5\x65\x14\x1f\x16\xa0\xc4\x19\x8b\x65\x9e\x0e\x0a\x00\x06\
\x74\x7f\x5f\x59\x64\xf6\xb0\x4b\xe7\x79\x58\x60\xd5\x5d\x63\x02\
\x9b\x3e\xac\x14\x03\xab\x09\x31\x8c\xf7\xc4\x16\x76\x69\x12\xee\
\x13\x8b\xb1\x67\x6e\x7f\x53\x15\x60\x3d\xef\xb9\xcb\xa7\xe5\x16\
\x95\x96\xe9\x79\x74\xea\x7f\x3c\xa2\xb8\xd4\xe7\xf5\x7e\xd3\x22\
\x42\x13\x76\x7d\x93\xba\xc6\x71\xbd\xda\x42\x73\x03\x57\x52\xe6\
\x23\xdc\x26\xe7\x33\x38\x3d\xe2\x55\xdd\xd7\x2e\x2d\x04\x1b\x12\
\x98\x96\xcf\xfc\x0e\x6b\x91\xba\xea\xb1\xd4\x60\x2b\x08\x58\x25\
\x8f\x29\xcc\x91\x5c\x66\xa6\x4b\x0f\xae\x97\x35\x54\x66\x46\x93\
\x63\x03\x2e\x8b\xf6\x1c\x2e\xc3\x74\x50\x93\xdf\xdf\xd9\x9f\x49\
\x70\x93\x6d\x05\xef\x24\xda\x83\x79\x0b\xa7\x10\xff\x95\x26\xff\
\x97\xc5\x10\xb6\x79\x71\xaf\x4c\x2c\x2e\x64\x92\x07\xbb\xb7\x3f\
\x5b\x04\x68\x75\xe8\xb3\xf7\x7b\x2e\x6b\x12\xcb\xb0\x9a\x4f\x57\
\x89\xf6\x8d\x96\x34\x81\xaf\xe2\x94\xf8\xef\x02\x1f\xeb\xba\x9f\
\xc5\xd5\xf8\x8f\x6f\x6f\x29\xeb\x7a\xf7\x11\xe9\xbc\x76\x00\x3f\
\x02\x5e\x97\x22\xbe\x7c\x17\xcf\xc3\x76\x56\x1c\x90\xcb\xf5\x79\
\xbd\xde\x4b\x94\xf0\xa8\xc7\xf5\x33\x7d\xe1\x28\x6e\xa7\x81\x31\
\xc7\x1b\xba\xe6\x49\x22\xc1\xf4\x98\xee\x89\x8d\xff\x49\xe0\x7b\
\xde\x73\x32\xd0\x6a\x4b\x89\x67\x6d\xf3\x16\xa5\x00\x58\xab\x14\
\xc3\x9a\xd1\x03\x9b\x49\x71\x03\x8c\x61\xd9\xa0\x99\x5b\x23\x60\
\xd5\x27\xb0\xfa\x92\x37\x41\xb7\xd5\x00\xaa\x24\x97\xcc\xee\xd1\
\x16\xb9\x48\x5b\xb4\x00\xbc\xa2\x09\x72\x84\x48\xa4\xb9\xc1\x63\
\x5b\xbe\x6c\x60\xaf\x37\xe0\xc7\x81\x29\x05\xe2\x17\x62\xb2\xdd\
\x44\xe2\xd0\x8e\x1a\x0b\xd2\x75\xdc\x36\x9b\xd7\x04\x50\xa6\xc8\
\x9f\x13\xcb\xb0\x20\xfa\x4d\x9d\xd3\x15\xb9\xb9\x2f\x28\x56\xb5\
\x47\xd7\x65\x19\xc6\x7e\x7d\xbd\x4b\xaf\x25\xfd\xfe\x49\x96\x18\
\x84\xcf\xe5\x0b\x1d\x9a\xf8\x8f\xe3\x9a\xa2\xd8\xe2\xe1\xbb\x7f\
\x0b\x01\x55\x45\x9e\xc2\x75\x81\xf0\x5b\x72\xef\xce\xea\x7b\x16\
\x33\x2c\xc5\x5e\xcb\x40\x55\xb1\xb8\x4a\x2e\x5f\xb8\x08\xfc\x50\
\xd7\xb6\x55\x63\xa4\x3b\x65\x9e\x59\x9c\xb3\x83\x48\x88\x1a\x6c\
\x85\x5d\xc2\x49\xb1\x03\x13\x8f\xc6\x15\xbf\xbe\xf0\x71\xad\xa4\
\x71\xb3\x1a\x90\xcf\xe0\x32\x6b\x4f\x79\x13\x3f\xb3\xc4\xcf\x33\
\x17\xa9\x2c\x00\x18\xd5\x44\x1e\x05\x5e\x54\xdc\x6a\x73\xc2\xfd\
\xed\xf4\x62\x22\x97\x04\x18\xbf\xd3\xf3\xa8\x05\xb8\xdd\x62\x44\
\x7d\x29\xae\x52\x45\xcf\xf5\x75\xe0\x7f\xea\x75\xd2\x73\xf5\xab\
\x9a\x64\x96\x30\x28\xa9\x8a\xc7\x69\xfd\xdd\x05\x01\xc7\xcb\xba\
\x57\x5d\xde\xff\x31\xb7\xf6\x7e\x9d\xf7\x49\xb9\x96\x33\x4b\x00\
\x2b\xeb\x2f\xf0\x2c\x70\x54\xaf\xfb\x04\x04\x0b\x15\x8f\xac\x78\
\x5e\xc2\x0d\x81\xd3\x49\x5c\x11\xbe\xb7\xc5\x1a\x0d\xa8\xaa\x1e\
\xb8\x91\x96\x2c\x18\x19\x1e\x2a\x49\xd5\x7f\x42\xee\xf1\xee\x84\
\xf3\xc8\x78\xe1\x81\x4e\x42\xbd\xb8\xd5\x01\xac\x91\xe1\xa1\x4a\
\x2e\x5f\x98\xf5\x18\x56\x25\xe5\xf3\x4c\xed\xbe\x56\x1e\x8c\xa9\
\xd7\x4d\x58\x59\x0b\xac\xe2\x19\xa6\xb8\x7e\xc9\x5c\x90\x6b\x02\
\x9b\x29\xdd\xcb\x29\x05\x73\x6f\x7b\xee\xc2\xc3\x02\x99\xa4\xba\
\x63\xbb\xc5\x30\xde\x05\xce\x6b\x0b\x4f\xa5\x06\x40\xf6\x79\x31\
\xb6\x24\x99\xc5\x9c\x26\xec\x4f\xc4\xf8\x3e\x49\xbb\x36\x7f\xf2\
\x8e\x0c\x0f\x15\x73\xf9\xc2\x15\x8d\x85\xed\xb8\xe4\x40\x77\x02\
\x28\x5a\x02\xe1\x5e\x73\xdb\x94\xed\xac\x2c\x02\xac\xec\x39\xbc\
\x84\x93\x0a\x1c\x16\xab\xea\x5d\x20\x5e\x55\xf1\x5c\xdd\xf3\xc0\
\x69\x31\xaa\x0f\x05\x54\x97\x04\x60\x4b\xad\xcf\x3e\x27\xb7\xfe\
\x7d\x9c\x18\x77\x63\x8a\x5b\xd8\x4d\xa4\xf9\x0a\xb6\x0a\x0c\xcb\
\xdc\x06\x53\xfb\x56\x12\x1e\x4a\x9b\x17\xab\x59\x2b\x31\xac\x4e\
\xb1\x86\xbd\x02\xab\xa4\x54\xbe\xb9\x19\x16\xac\xae\xc4\x5c\x9e\
\xaa\xb7\xba\x5f\xd4\xca\x7e\x56\xa0\x65\x99\xd7\x31\xb1\xa5\x76\
\xb9\x3c\x9b\x98\x2f\x8b\xf0\x27\x7f\x2f\x4e\x5b\xf4\x88\x26\xdf\
\x75\xb1\x9f\x5a\x80\xb5\x21\x05\x68\xab\x9a\xcc\x67\x34\xe9\x16\
\x05\x24\x23\xc3\x43\xe5\x5c\xbe\x60\x99\xe3\x5e\xd2\xcb\xb4\x58\
\x36\x6f\x33\x8b\x2b\xe5\x62\x60\xb5\x5f\x6e\xf3\x57\xc5\x66\xb6\
\xd4\x60\x55\x16\x9f\x2a\x12\x15\x9f\x3c\xa9\x45\xe1\x77\x02\x2b\
\x8b\x51\xcd\xdd\x8d\xdc\x42\x4c\xd3\xe2\x5c\x93\x29\x0b\xb9\xbf\
\x75\x2d\xd4\x8b\x5b\x45\xc0\xb2\xd5\xb8\x58\xe3\xc1\xf8\x5b\x1c\
\xd6\x82\x75\x10\x95\x21\x49\x03\xab\x39\x4d\x0c\x2b\x72\x68\x20\
\xe4\xbb\x16\xd3\x5a\xc9\xcf\xe0\x32\x6d\xef\x6a\x90\xdb\xca\x5e\
\x55\x4d\xac\xdf\x6a\x62\x6f\xd5\x8a\xbc\x23\x01\x68\x4c\x55\xfe\
\x80\x5c\xad\x8f\x6a\x00\x96\x09\x7a\x3b\x53\xce\xdf\x2a\xca\x5e\
\x92\x6b\xb7\x94\x02\x74\x16\xbf\xec\x5e\x60\xa1\xea\xf4\x62\x3c\
\x95\x3a\xc1\xaa\x4b\x6e\xdf\x17\x71\xb2\x05\xab\x1c\x91\xf6\x2c\
\x4a\xba\xd7\xb7\xe4\x62\x7f\xa0\xf8\xd4\x6b\x02\xe4\x9b\x76\xaf\
\x96\x51\x17\x96\x59\xe0\xba\x7d\xc5\x7c\x66\x2d\x6b\x14\x9b\x0d\
\xb0\x2a\xcc\x2f\xb7\x41\x0d\xb7\x68\xad\x3c\x10\xbb\xe6\xb6\x94\
\x41\x69\x35\xef\xdf\xd5\xc4\x38\xa7\x49\x51\xf2\xe2\x7c\xc6\x4e\
\x2d\xdb\x36\x2a\xb0\x9a\xf2\xb3\x7c\x72\xbb\x6f\xe1\x34\x3f\xb6\
\x4d\xe6\x69\x8f\xd9\xf9\x13\xa0\x17\x17\xbc\xbf\x1f\xd8\xba\xc0\
\x46\x63\x13\x79\xb6\xa5\x30\x43\x8b\x4d\x4e\xb3\x34\x29\x4a\x49\
\x47\x3d\xc9\x07\x63\xa1\xf5\x80\x95\xe9\x98\x9e\x57\xcc\xea\xb1\
\x05\x58\xee\xac\x16\x0d\x8b\x4f\xbd\xa9\xe7\xf2\xa1\xee\xf7\xcc\
\x72\x03\x85\x62\x84\x5d\x44\xd5\x1f\xd2\x18\x9f\x25\x2f\x4a\x01\
\x76\x56\x97\x61\x95\x63\xa0\xe4\xa7\xee\xab\xde\x24\x5f\x4b\x80\
\x55\xf4\x5c\xbd\xa4\x81\x78\x1d\x17\xa8\xfe\x8e\xd8\xce\x9c\xf7\
\x33\x03\x3a\xbf\x5c\x89\x05\xae\x2b\x09\x2e\x46\x29\x97\x2f\x5c\
\x02\x7e\x41\xd4\xb9\xc5\x4a\xf7\xb4\x79\x13\xdf\xf6\x1c\xde\xab\
\x49\x7d\x21\x65\x32\x54\x3d\x16\xb4\x90\x9c\x61\x76\x89\xcf\xcd\
\xc0\x79\xa1\x3d\x87\xe6\x2a\x57\x17\x02\x0e\x01\xc1\x46\xc5\xea\
\xbe\xe4\x31\xab\x8e\x1a\x60\x35\xaa\xb8\xd4\x4f\xc4\xa8\x3e\x14\
\xab\x9d\x5d\x41\x46\x63\x49\x99\x7d\x29\xf1\x2b\xbb\x6e\xab\x76\
\x32\x1b\xd8\xd5\xea\x01\x56\x3d\xd4\x78\xad\x99\x0d\x36\x5f\x30\
\x9b\x49\x98\x2c\xd7\x70\x41\xdd\x4b\x24\x97\x2a\xf9\xfd\xef\x2f\
\x34\x60\x15\xcc\x3e\x87\x53\x56\xdf\x87\x13\x47\xc6\x57\x6f\x8b\
\x09\xdd\xa3\x9f\x77\x93\xbc\xed\x23\x53\x03\xac\x88\x2d\x30\x99\
\xbb\xb8\x47\x99\x3a\x42\x01\x25\xef\x3e\x2e\x64\x5d\xb8\x6a\xad\
\x2f\xe2\x32\xb4\x3b\x49\x56\xe7\x9b\x4b\x3e\x2a\x66\xfa\xcf\xc0\
\x2f\xf5\x2c\x56\xa3\x67\x60\x1f\x2e\x41\x72\xbf\x9e\x51\xd2\xf9\
\x15\xf5\x6c\xc6\x96\xe8\x72\x07\x5b\x22\x60\xc5\x07\x65\x92\x48\
\xb2\x9e\x81\xdb\x4a\x66\xc1\x72\x4b\x79\x27\xdd\x0f\x13\x06\xf6\
\x7b\xb1\x91\xbb\x9d\x28\x73\xb8\x6c\xdd\xfb\x72\x89\xf6\x70\xa7\
\xcc\xa1\x47\x2e\xd2\x1e\xa0\x57\x9a\xac\x24\x41\x6f\xad\xf3\x99\
\x17\x5f\x59\xe2\xb9\xda\x79\xd4\x2a\xa7\x63\x4c\x6e\x66\xa1\x7b\
\xa3\xed\x36\x3b\x70\x59\xb7\x4f\x8b\xbd\xf4\xa4\xb8\xb4\xb3\xb8\
\xa0\xfa\xeb\xc0\x3f\xe2\x2a\xb6\x8e\x8e\x0c\x0f\xad\xb8\x06\xd0\
\x2b\x29\x74\x88\xe4\x22\x87\xfe\xb3\x1c\x15\x13\x0f\xa2\xd1\x55\
\x06\xac\x7a\xe2\x14\x99\x35\x06\x58\x13\x44\x92\x83\x6a\x82\x4b\
\x60\x75\xb0\x4e\x03\xa5\x5c\xbe\x70\xdd\x73\x9d\x2d\x83\x56\xf1\
\x5c\xb3\xb4\xca\x07\x49\xdf\x9b\x22\x59\x80\xeb\x97\x74\xf1\x33\
\x6f\xd5\x1a\x71\xb8\x4a\x0a\x23\xb6\xa0\xfc\xa2\x41\x4b\xda\xa8\
\x7b\x88\xb6\xc4\xb4\xd5\x00\xac\xd9\x3a\xe3\x38\x3d\xb8\x84\xc2\
\xb3\x38\x41\x6a\xd2\xb6\x17\x13\x7f\x8e\xe2\xb4\x54\xff\x0c\xfc\
\x0c\xb8\xb4\x8a\x45\x03\x7b\x70\xa2\xd5\x27\x88\xb6\x03\x25\xdd\
\x7b\x93\xb2\x8c\x85\x18\xd6\xea\xbb\x84\xb5\x4a\x73\x2c\xa5\x6c\
\x47\x2b\x00\xd6\x24\x2e\x90\x9e\xa6\xf0\xef\x53\xac\xa5\xa2\xc9\
\xfb\x89\x40\xce\x5c\x81\x59\xa2\xcc\x6a\x26\x16\xeb\xb3\xaf\xdb\
\x62\x9f\x6d\x82\x4b\xdb\xf6\x92\x04\x26\x56\x1d\x74\x20\xc5\x1d\
\x81\x28\xbd\x5f\xab\x73\xb7\x55\x9d\xe8\x65\x71\x72\x83\x2c\x4e\
\x13\xf6\x39\x01\xf6\xa6\x05\x18\x96\x6d\x2c\x5e\x28\xb0\x6f\x1d\
\x6d\x1e\x52\x7c\xa8\x3d\x05\xfc\x2e\xe0\xb6\x37\xfd\xa3\x62\x56\
\xab\x06\x56\x62\x57\x5b\x74\x8e\xfb\x6a\xb0\x4b\xdb\x41\xf0\x01\
\x70\xad\xc1\xcd\x45\xd6\x25\x60\xd5\xca\x02\xae\xb5\x0c\xa1\x4d\
\xf8\xdb\x68\x2b\x0c\xf3\x33\x7f\xfe\x7d\x1c\x90\x0b\xb3\x8f\x48\
\x14\x3a\xeb\x81\xd5\xac\x37\x51\xab\x09\xb1\xa3\x38\xd8\x5b\x6d\
\xa7\x07\x14\xbf\x69\x4f\x59\x20\x3a\x88\xb6\x8e\x54\x6b\xc4\xe0\
\x6a\x6d\xa9\xea\xf1\x98\x5a\x67\x3d\x2c\x40\x5b\x64\xf6\xe0\xb2\
\x77\xdf\x90\x5b\x54\x8f\x4b\x58\x33\x56\x26\x10\xdc\x8c\x4b\x26\
\x6c\x4b\x89\x5b\x95\x71\xc1\xf4\xdf\xe2\x12\x1d\xbf\x00\xae\xae\
\x32\x18\xf4\x28\x6e\xf5\x6c\x8d\xe7\x53\xd1\xc2\x75\x16\x97\x8c\
\x09\x4d\x29\x56\x19\xb0\x2a\xd4\xce\x12\xda\x6b\x99\x35\x52\xa9\
\x41\x52\x83\x71\x9c\x12\xfc\xba\x26\x5d\xd2\x24\x6a\x57\x0c\xab\
\x47\x2c\xab\xe4\xdd\x87\x12\x77\x66\x4e\xe3\xe0\x9e\x89\xc5\x9c\
\x0c\x8c\xfc\x26\xa6\x69\x6e\x56\x2d\x99\x89\x01\xee\x0d\xbd\x26\
\x6d\xa9\xea\x25\x2a\x03\xd3\x47\x8d\x9a\x4d\x5e\xd5\x8a\xfb\x70\
\x9b\xb6\xbf\x2e\x76\x99\xe6\x12\x11\x73\x77\x3b\x80\xce\x1a\x5a\
\x24\xbf\xdc\x72\x7f\xc2\x67\x5a\x10\x7b\x14\x27\x04\x7d\x7d\xb5\
\xc1\x4a\x72\x8b\xfd\x38\x65\xff\x23\x5a\xac\xd2\xce\xf3\x92\xce\
\xf1\x5d\x42\xc0\xbd\x21\x31\x2c\x3f\x06\x93\x36\x28\xd7\x52\xd0\
\x1d\x0d\xb4\x8b\x72\x41\x26\x6a\x30\x09\xcb\xc6\xb5\x27\x30\xcd\
\xa5\xb0\xce\x85\xe2\x81\x26\x93\xb8\x0c\xdc\x4c\x91\x49\x54\x72\
\xf9\xc2\xa4\x58\xdf\x0d\x01\x5c\x67\x0c\xb0\xba\xc5\x0c\x9f\x01\
\x3e\xc8\xe5\x0b\xb7\xad\x71\x82\xd7\xb9\xda\xca\x04\x0f\xe0\xb2\