pax_global_header00006660000000000000000000000064151407054300014511gustar00rootroot0000000000000052 comment=38afacb0f80448a3e96d555955cad43b825cc98f drum-machine-2.2.0/000077500000000000000000000000001514070543000140635ustar00rootroot00000000000000drum-machine-2.2.0/.flake8000066400000000000000000000001151514070543000152330ustar00rootroot00000000000000[flake8] max-line-length = 88 ignore = E402, W503 exclude = .flatpak-builder drum-machine-2.2.0/.github/000077500000000000000000000000001514070543000154235ustar00rootroot00000000000000drum-machine-2.2.0/.github/FUNDING.yml000066400000000000000000000013371514070543000172440ustar00rootroot00000000000000# These are supported funding model platforms # github: Revisto patreon: Revisto open_collective: # Replace with a single Open Collective username ko_fi: # Replace with a single Ko-fi username tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry liberapay: # Replace with a single Liberapay username issuehunt: # Replace with a single IssueHunt username lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry polar: # Replace with a single Polar username buy_me_a_coffee: thanks_dev: # Replace with a single thanks.dev username custom: ['https://www.coffeete.ir/revisto'] drum-machine-2.2.0/.github/ISSUE_TEMPLATE/000077500000000000000000000000001514070543000176065ustar00rootroot00000000000000drum-machine-2.2.0/.github/ISSUE_TEMPLATE/bug_report.md000066400000000000000000000010531514070543000222770ustar00rootroot00000000000000--- name: Bug report about: Create a report to help us improve title: '' labels: ["bug","needs-triage"] assignees: '' --- **Describe the bug** A clear and concise description of what the bug is. **To Reproduce** Steps to reproduce the behavior: 1. Go to '...' 2. Click on '....' 3. Scroll down to '....' 4. See error **Expected behavior** A clear and concise description of what you expected to happen. **Screenshots** If applicable, add screenshots to help explain your problem. **Additional context** Add any other context about the problem here. drum-machine-2.2.0/.github/ISSUE_TEMPLATE/feature_request.md000066400000000000000000000011571514070543000233370ustar00rootroot00000000000000--- name: Feature request about: Suggest an idea for this project title: '' labels: ["enhancement","needs-triage"] assignees: '' --- **Is your feature request related to a problem? Please describe.** A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] **Describe the solution you'd like** A clear and concise description of what you want to happen. **Describe alternatives you've considered** A clear and concise description of any alternative solutions or features you've considered. **Additional context** Add any other context or screenshots about the feature request here. drum-machine-2.2.0/.github/PULL_REQUEST_TEMPLATE.md000066400000000000000000000005531514070543000212270ustar00rootroot00000000000000# Description Please include a summary of the changes and the related issue. Also include relevant motivation and context. Use "Fixes #" if applicable. # Type of Change - [ ] Bug fix - [ ] New feature - [ ] Breaking change - [ ] Documentation update # Additional Notes Include any additional information that is important to this pull request. drum-machine-2.2.0/.github/workflows/000077500000000000000000000000001514070543000174605ustar00rootroot00000000000000drum-machine-2.2.0/.github/workflows/ci.yml000066400000000000000000000070201514070543000205750ustar00rootroot00000000000000name: Build and Lint on: push: branches: - '**' pull_request: jobs: lint: name: Lint with flake8 runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v5 with: python-version: '3.12' - name: Install dependencies run: | python -m pip install --upgrade pip pip install flake8 - name: Lint run: | # Stop the build if there are Python syntax errors or undefined names flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics --builtins="_" # Exit if any flake8 issue is found (errors or warnings) flake8 . --count --max-complexity=10 --max-line-length=88 --statistics translation-check: name: Check translation template runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v5 with: python-version: '3.12' - name: Install dependencies run: | python -m pip install --upgrade pip pip install meson ninja sudo apt-get update sudo apt-get install -y gettext blueprint-compiler desktop-file-utils libglib2.0-dev - name: Setup build directory run: | meson setup builddir - name: Check if .pot file needs updating run: | # Backup the original .pot file from the checkout cp po/drum-machine.pot po/drum-machine.pot.orig # Regenerate the .pot file meson compile -C builddir drum-machine-pot # Verify the generated .pot file exists if [ ! -f po/drum-machine.pot ]; then echo "::error::Failed to generate .pot file. Build may have failed." exit 1 fi # Normalize both files by: # 1. Replacing timestamp with placeholder # 2. Removing line number references (e.g., ":123" -> "") normalize_pot() { sed -E \ -e 's/POT-Creation-Date: [0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}\+[0-9]{4}/POT-Creation-Date: TIMESTAMP/g' \ -e '/^#:/ s/:[0-9]+//g' \ "$1" } normalize_pot po/drum-machine.pot.orig > po/drum-machine.pot.orig.normalized normalize_pot po/drum-machine.pot > po/drum-machine.pot.normalized # Compare normalized files (ignore whitespace differences) if ! diff -u --ignore-all-space po/drum-machine.pot.orig.normalized po/drum-machine.pot.normalized > /dev/null; then echo "::error file=po/drum-machine.pot::Translation template (.pot file) is out of date. Please run 'meson compile -C builddir drum-machine-pot' and commit the updated po/drum-machine.pot file." echo "" echo "Diff of changes needed:" diff -u po/drum-machine.pot.orig.normalized po/drum-machine.pot.normalized || true exit 1 fi echo "✓ Translation template is up to date" flatpak: name: Flatpak Builder runs-on: ubuntu-latest container: image: bilelmoussaoui/flatpak-github-actions:gnome-nightly options: --privileged steps: - uses: actions/checkout@v4 - uses: flatpak/flatpak-github-actions/flatpak-builder@v6 with: bundle: "drum-machine-devel.flatpak" manifest-path: "io.github.revisto.drum-machine.json" run-tests: "true" cache-key: flatpak-builder-${{ github.sha }} drum-machine-2.2.0/.gitignore000066400000000000000000000044251514070543000160600ustar00rootroot00000000000000# Python __pycache__/ *.py[cod] *$py.class *.so .Python build/ develop-eggs/ dist/ downloads/ eggs/ .eggs/ lib/ lib64/ parts/ sdist/ var/ wheels/ share/python-wheels/ *.egg-info/ .installed.cfg *.egg MANIFEST # PyInstaller *.manifest *.spec # Installer logs pip-log.txt pip-delete-this-directory.txt # Unit test / coverage reports htmlcov/ .tox/ .nox/ .coverage .coverage.* .cache nosetests.xml coverage.xml *.cover *.py,cover .hypothesis/ .pytest_cache/ cover/ # Translations *.mo *.pot # Django stuff: *.log local_settings.py db.sqlite3 db.sqlite3-journal # Flask stuff: instance/ .webassets-cache # Scrapy stuff: .scrapy # Sphinx documentation docs/_build/ # PyBuilder .pybuilder/ target/ # Jupyter Notebook .ipynb_checkpoints # IPython profile_default/ ipython_config.py # pyenv .python-version # pipenv Pipfile.lock # poetry poetry.lock # pdm .pdm.toml # PEP 582 __pypackages__/ # Celery stuff celerybeat-schedule celerybeat.pid # 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/ .dmypy.json dmypy.json # Pyre type checker .pyre/ # pytype static type analyzer .pytype/ # Cython debug symbols cython_debug/ # PyCharm .idea/ # VS Code .vscode/ # GNOME Builder .gnome-builder-devenv # Meson build system _build/ build/ builddir/ meson-logs/ meson-private/ meson-info/ compile_commands.json build.ninja .ninja_log .ninja_deps # Flatpak .flatpak-builder/ # AppStream *.appdata.xml # Desktop files (generated) *.desktop # GSettings schemas (compiled) *.gschema.valid *.gschema.xml.valid # Icon cache icon-theme.cache # GTK+ resources (compiled) *.gresource # GLib *.gir *.typelib # Vala *.c *.h *.vapi # GObject Introspection *.gir *.typelib # System files .DS_Store .DS_Store? ._* .Spotlight-V100 .Trashes ehthumbs.db Thumbs.db # Temporary files *.tmp *.temp *.swp *.swo *~ # Backup files *.bak *.backup *.old # Log files *.log logs/ # Database files *.db *.sqlite *.sqlite3 # Configuration files with sensitive data config.ini settings.json secrets.json # Package files *.deb *.rpm *.tar.gz *.zip # Documentation build docs/build/ docs/_build/ # Local development files local/ dev/ test-data/ drum-machine-2.2.0/COPYING000066400000000000000000001045201514070543000151200ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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, 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 . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . drum-machine-2.2.0/Makefile000066400000000000000000000002611514070543000155220ustar00rootroot00000000000000.PHONY: generate-deps generate-deps: flatpak_pip_generator --build-isolation --requirements-file=requirements.txt -o python-dependencies --runtime=org.gnome.Sdk/x86_64/master drum-machine-2.2.0/README.md000066400000000000000000000120771514070543000153510ustar00rootroot00000000000000[license-url]: https://github.com/revisto/drum-machine/blob/master/COPYING [license-image]: https://img.shields.io/github/license/revisto/drum-machine.svg?style=for-the-badge [flathub-url]: https://flathub.org/apps/io.github.revisto.drum-machine [flathub-image]: https://img.shields.io/flathub/v/io.github.revisto.drum-machine?logo=flathub&style=for-the-badge [installs-image]: https://img.shields.io/flathub/downloads/io.github.revisto.drum-machine?style=for-the-badge [issues-url]: https://github.com/revisto/drum-machine/issues [issues-image]: https://img.shields.io/github/issues/revisto/drum-machine?style=for-the-badge [persian-gnome-badge]: https://gnome-fa.github.io/assets/badges/persian-gnome.svg [persian-gnome-url]: https://gnome_fa.t.me/ [circle-url]: https://apps.gnome.org/DrumMachine/ [circle-image]: https://circle.gnome.org/assets/button/badge.svg
# Drum Machine **Create and play drum beats** [![GNOME Circle][circle-image]][circle-url] [![Persian GNOME][persian-gnome-badge]][persian-gnome-url] [![License][license-image]][license-url] [![Flathub][flathub-image]][flathub-url] [![Issues][issues-image]][issues-url] [![Installs][installs-image]][flathub-url]
## Description Drum Machine is a modern and intuitive application for creating, playing, and managing drum patterns. Perfect for musicians, producers, and anyone interested in rhythm creation, this application provides a simple interface for drum pattern programming. ## Features - Intuitive grid-based pattern editor with **infinite pages** - Navigate through unlimited pattern pages using carousel interface - Create complex drum sequences across multiple pages - **Custom samples with MIDI mapping** - Add your own drum sounds - Map samples to specific MIDI notes for export - Adjustable BPM control - Volume control for overall mix - Save and load patterns - Multiple drum sounds including kick, snare, hi-hat, and more - **Audio & MIDI export** - Export patterns in WAV, FLAC, Ogg Vorbis, and MP3 formats - Export as MIDI files with proper note mapping - Add artist name, song title, and cover art metadata - Configurable pattern repeat count for longer exports - Keyboard shortcuts for quick access to all functions - Modern GTK4 and libadwaita interface ## Install Download on Flathub ### Build from source You can clone and run from GNOME Builder. ## Contribute We need your help to make Drum Machine better! There are lots of features that can be added, and we would love to see your contributions. If you want to contribute to this project, you can fork the repository and submit a pull request. You can also report a bug or request a feature by opening an issue. Your contributions are extremely welcome and appreciated. ## Translations Drum Machine uses [GNOME Damned Lies](https://l10n.gnome.org/) for translation management. If you'd like to contribute translations, please visit the [Drum Machine translation page](https://l10n.gnome.org/module/drum-machine/) on GNOME Damned Lies rather than submitting pull requests with translation files. ## Credits Developed by **[Revisto](https://github.com/revisto)** Special thanks to **[Sepehr](https://github.com/sepehr-rs)** for triaging issues and helping maintain the project. Special thanks to **[Tobias Bernard](https://tobiasbernard.com)** from the GNOME Circle Committee for helping Drum Machine look the way it does now and for all his valuable contributions. Thanks to all contributors who help improve Drum Machine through code, bug reports, and feature requests. Thanks to everyone contributing translations on [GNOME Damned Lies](https://l10n.gnome.org/module/drum-machine/), your work makes Drum Machine accessible to users worldwide.

## ❤️ Sponsor this project Drum Machine is free software. If you like it and would like to support and fund it, you may donate through one of the platforms listed in the GitHub Sponsor section. Any amount will be greatly appreciated 🤩. ## License 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, either version 3 of the License, or (at your option) any later version. ## Code of Conduct We follow the [GNOME Code of Conduct](https://wiki.gnome.org/Foundation/CodeOfConduct) to ensure a welcoming environment for everyone. Be kind, be respectful, and help us build something awesome and fun together. drum-machine-2.2.0/SOUNDS_LICENSING.md000066400000000000000000000023441514070543000170160ustar00rootroot00000000000000# Sounds Licensing | Sound File | Source | License | :-: | :-: | :-: | clap.wav | [99Sounds Drum Samples](https://99sounds.org/drum-samples/) | Royalty-Free | crash.wav | [99Sounds Drum Samples](https://99sounds.org/drum-samples/) | Royalty-Free | hihat.wav | [99Sounds Drum Samples](https://99sounds.org/drum-samples/) | Royalty-Free | hihat-2.wav | [99Sounds Drum Samples](https://99sounds.org/drum-samples/) | Royalty-Free | kick.wav | [99Sounds Drum Samples](https://99sounds.org/drum-samples/) | Royalty-Free | kick-2.wav | [99Sounds Drum Samples](https://99sounds.org/drum-samples/) | Royalty-Free | kick-3.wav | [99Sounds Drum Samples](https://99sounds.org/drum-samples/) | Royalty-Free | snare.wav | [99Sounds Drum Samples](https://99sounds.org/drum-samples/) | Royalty-Free | snare-2.wav | [99Sounds Drum Samples](https://99sounds.org/drum-samples/) | Royalty-Free | tom.wav | [99Sounds Drum Samples](https://99sounds.org/drum-samples/) | Royalty-Free **License Terms:** The drum samples used in this application are from [99Sounds](https://99sounds.org/drum-samples/). All sounds are royalty-free and can be used in free and commercial projects. For more information, please refer to the [99Sounds License](https://99sounds.org/license/).drum-machine-2.2.0/data/000077500000000000000000000000001514070543000147745ustar00rootroot00000000000000drum-machine-2.2.0/data/drumkit/000077500000000000000000000000001514070543000164535ustar00rootroot00000000000000drum-machine-2.2.0/data/drumkit/clap.wav000066400000000000000000004003721514070543000201170ustar00rootroot00000000000000RIFFWAVEfmt D dataFB 8X`pfA}/ |uYV7yU讅 _\nkY,)S'/W."s/##hwg5RD+w%ͳd^W" &ݍO΄4 kk *`.F4GiRyH 3i  b{)%I&CR{7AJ͆C]QcC@ 悘`5A8ڢ s 94#'?$T\'w1wOx3}2" %]t= 4D=C\EʞbD,7٥@]* HKV"K n (FS#V㵭"&595Q"]6z/>13;$?$Y",0U*$T&/F2&å;48$}1d`#& M* s o,NQf* @CE ˛pR3 chK )">_DN} ^B9 6*I0RȎp_#*r+qJCxI{_ΣeMZH `//6+"ب,쩛%W*ր ټ} ,'lvmڼQ$_eTsmK:r)vk&[*+21`0 :s$*%A<.ZkX`'d-$C^9)Pa##:iq5QULLHk í7֪ ̢ؗo,,w7Vt ##v;%-U#!Jm. K_F 8U+Z- " ʰ"JJ+L-*8 KX۶ ՌdsݲLũϢ\"7Afް#. 1 d   i 8-&Rf ݼm{Us-㼿Sh]{G( ! kY-ȢC^9MK EF@ :9 2E$,0*3J ' 9 (#m*%l?, :a  yꖏ"۾/kܚqe#+^RJkO+> I/2/-y NG1f~ ᫿&.==4G?M8M(@ 4"3"e(&Q'M S 4b%.WQ|97hLvP8a)旙#Rk'ыw_ߊe{ʮߞuҌgE=nA+[UĿhLcop?#@:,H+>-0y`2{>gJEa`D%aC3L<8/:{=E~?Oz_=ZP.)?4$4 P,]-@ %-1! )= HPڈ&,>`,^_>3?:Z W%Y M-IilWi"YӰrrazT- ps\icCٍԑ8P#Np?SO=)-/X4,-|J2Wa:^*G>;M%T7K㹆KM߈5rD\jTo &65@ܺB:ՅaAY< >RR=vGgJSWC&a1HMV0) JesDQ15'_$q+}"ت'̢z&VmYT&]'-7 6;< eg"F71p? DҥO-T4?Ye+LdmKR<%9>+'Dèʥ a߂ýL1Wxtt'onь&sǩP&cYs#Ɋ3ث:#Y(d@R=34T2#- Ut$#P{2"n { ԺUTCJ+«˙Mȁ ޖϷPVSrVII%G|?\+$>[Eo=C^"@Vkw/**,GHf?_BHc;TJG&u>"z(XqT1 (8f}15.dsXpĤ"<~ NG& 4I58x'Br!m5%tN*OAc'OAP[&‚lQwp VxY@dՌ (vbHoP~lI F(/q 3`3j"𝁼u!5.bץ7ۅbi- =]FMG%;<]4Zv!>]']`Ҍ#»c22ƑDTʹ ש ٜgm ( ï.1 6@$5="B2I)R=-V8{4Q-n?0AA/3i61'% =: eBv|@ym+ 2{r 09 sVC9fi1B16ug-1 ̋+X 榇à&(MXăݕB x1k$6_&.pFajC,ϧIԐڵ`?9Uk~(L6W*y#-lR4ɫ/3ȏױJ짰t̫X O!,L OnZb N@* Q3#B;O17R3}@6c3HQHXI^,SM[A|?: |]]^&K]֌#o(ylĶo$xUu$5pw#0~p':mM hIk.ܫ 9ԟ kqGޫ hڰ̖1s #  HUhvWB$c 7q@t+ŤQ{:?DO.>/+9I; Y(TI-/!4a+g;/2'%vj1 bll'PfQԇ<CB&/&;& 5P$~ 1<@m"u$ǖ9+>w:X;a+,%'{ B i7D~R4;;WdTQROZ(G"=:D3!)_*-[zȔbEg4?y3؍H _D( 4b/8@6J9)a3P+?$\ ‡6-2Qi_˰ɢ&p\Br🦿7uɹiIמ-ITϠ ̺izR4LP#cn7i{Yە7ɰǸի7 !6&7S'90=V-\07'[ $Q yn 4<혾政:UCswb4 uts#vh2+&NOvcH2m_Y_2^ETU?xAT&&uHSf o\ Dpw Y^$V+i$ 4v ak&032,a!#  Y;ѥ)S2<<&P(,G= 5ԗ ? x[dlT)ܓ>IeކP Y|MI4>(pԋOrLԽBLƱBpZVL/UtOނwͺ|JS@e LyT/NN;FsA߮ 恑Ao;YZ5 )c}l޴jΙU1(э[ {*+!,`+d: I):-H:z-6A8?6DDIi?oBDC$?]R9t5P,JR-+%V.&,iP(1c&#M!aR ClM/StsmT#+2F,W;m* r<4;2=ّ?oCHժG JPKEϕ>I51;#\.H$h()ep&)z ^!3!6N&x#[g* R>R)M: 1?Hu5N`7Ct}91#`hrU/Lm2b?\vLhi +nt|Uez[n?@ j)5aXi#R)Kř_78~ʟ:y bP&cBNQ,IRL"?^RvJWtS }Q51,٬bzfEƟiT< <O7z{[:*43 cz2 =S/*^U$ `dgSb Mh2#v$V2U|23%z1-Q*a5&z# @'>qbe 3we j= R [ lnEz @Y$\QhiaxH v }٦V¦A°VAM_bj@FxCgT8<r٫Σ1:kF"ÌDrrFrBPRprTJi<$hd[ \ ǁ5%] _}#tͼEv|̹]%}m/o!wFǚ3\Ҳ#;Sc{ۦ|ٱ̜âwuj /o4NT|]^a!#`m5p>zp W!%sI$IQ"(%=0Nk6K)*~ t ~TZG?P e #rqd7d9| - VL$Y2Ǖ psյ; QPt5!Đ",z]*lh4h9 AA?vu<x  óaI@@"kT={ x6Q CJш۬ԍOjp!+*#P 9 n+sq1:[mVyx0o_[xmk1oE`Ǘ*<C) <0H{>RnL( 6p#<kRMFɝA n 'UV=C) UoYS6 qu  Gup DzÈ zB mN  i~b `-rc?t Z UM!79#P Jk%C)u%/*.` %@![q2y)2){G!'9**o0). L'-i2%4+aPQD;k qYwV&t6&2=j7h "}/{Q*O M J_ 6>' ,8@ ~bJLHq壇62?ܱXlw8@րwiwCzf鬊_o\&hA%WJ̀' fq&QlQs< NK\נ/j:4яFe14RܕvP'r_M7hS#/ n#r+cuѽ - L tkd6e# U 愀@-aIJۋ 7|l RTܑIs9B?bs oWlD$ 0ET^%yr RhUdf  xx 0~L  c 4.hp1c<m%>MICi + 9 D"S vY{:̿ Cw\uU k/*7P q?V g;-?pjtEl.7 LE T 6D0?R 3 \{8d SjP)ЌQ3"ZR {u+.2>i #'i4*o* s$_{x:$ Kt8f0Sl9B-V-C]-t코Ļһ N z4 #Bw$ c$<q "E /f4/ aM} 6׉^ ދikbOof σ =+6UDA5q{ !$#F Ŭ#M|C# 2r2 2$D ^&" *6e oG  z=x B4@Ҏhў Li x٢AލU0-k W/+r3p3d.,!+5 |C"k9:_!v2́f BXvچ^9l|Oޡ+ :ȡ=mH  eq7Y>Iga%T& I:!>/$5.Q"nx~ȳ BQ5a|x4۞2Je!"j3flni:112JgHmX5\SxQ ]o'dSMste,6: #sc {psDlʽg ~  cN=Zf]$0B5ͪ!'j4r pً TH#ԙY8f5}) F+8~ : <&Y#2?/#Nv—6'wxSf)]tY[!:nY%PNM=7\՞![+J?&[}wYѾTv 9&ԟ )_DxaH Dz24(ɰtQ4CPE!Z LHr4 7g+@X"8"'}9U"9@Q8|R-u{'QV <"/sjĩAw6rG"(u\M뤈 >]Х&Q |ށUe/4fX [3ﰘ[.O } OaN  `{ `( g *j SIJip PVo KH0u nU)`oyA; +6HcNWF ]8L ]o ds ^ slr # 1v }9`z-y|k   *l4G 9odf;/6P+Ʒ [x+ Lx^Ic 2' kճk}䊀YX{Th%$`f>Ze+X @ )'-W$ {i g-]N٫ |'Sm SR"k¯阺*. 1J6n(V0qDz >굏\( %8jw o~s>h$ ( -/-ۀ&m2/bN0&,5Xy VvY2CꠓvOim'UB 3ԛ#33y!":0c!t vڱTmhG/S7$_Mu @sϴĠuhTxk`M V< oK!zf0J>xӵ7mUx)sez7 5nV9zvw$# 4}edOM?>_zm>"% N( G< wQo~96U΋0N!1%A} d,BHS& X'ޝr$Q}>ꙍ랣( ae/  . Kzp G>vSN7{5g뚓U8!G~S!( ^-p]RV&k{! tpWKtVs 2v~x~a]2e Rd vvN 8'#΄+& *ٓ VIhH'4z5ӚE!͑W%W%K {AMOq# w-K!VG șYn!|\tvH(**k݅Vg2ᧇF$/e% /rDhD⬀创T贐qFڶ{ \"y5 hT^-BgU> x D j];Dzr x?UxrC Ď=0P\+yg~ xR 9c)IhlW 4} Mm c? { f * H,* qG R\ V,ltKh/Ed,5e+t7 XSehouuQ^PJXb?_Rk$u>- mgX5+a J-< 4 >zJWm̺EՆd ef a) Tyhq=98 7"+5Nc^6xɶ7w\ }Go  @A ]mÝ 5mHzF]^ K(m23  q FY y: 4v@qq'[ha9"&{찰@ѫ}0LZ(] 6C [9/Orl5N]87biy\. ]~ kq , g f7 uKv>U$m]QQP8 ڧ5qٸQ " xM 4S Y, t.}(oQ e!qoQIn6D i\ & V2 Tz1d" \y@w_̟"so 57>%EW} B6M C] $ ~& 0ҵo }nD~L4dLeĖ$5ӚN,)0 AF]L % 1\*]0j)y7Zn t0B(7ֲh0RRΆlZ8|XsDA"+.֮"N.n0(N23'J? G.I`t k7 YS~!?|n7 joEy?^`ʟ,[z6\Ww*(G)u[5Lb٬ o"pd"[OG fq(~j `y9uDQSk ܉)=Lu%\ _`Oj i,|6\~n.XT IvVp';?-E!)+%}Lj*>' IE DoWW zfqǤ EgS &GZwf= |sN;\Y:0H|+2F@3e?vMQ _6N8 PcOph\e ` 1z tp$8 cZ$b n?U2 N % 7  e 4L F[Blq&yFq;uA)}cX=Dyl,~a% +uv+ Vc6:9dD5| ̖[/%K 뼄Kya3* Fc/__lk w3m ' PB!ͭ/%Z^nO>V 9 ? ӳ  {.[;{~5 6  kS ! @ydt8$LD\>oJ a>Bwa~ -T RL/ ~z$/SyƳ5f .,鸯Pyy`WՃSP{VQS96Eo|!z4F_%(U\RL&%P!uU2Ks3[dJ o+mwh u]V g$ Z{t}? o*JsRq #Fh CK~#p9 g]% 8/ O~/T}1Zt6 /7  ޘ u S,KHм 4Aw?ɮ. ,*}Tcd&=+1 c YV k/y\& *9̘o?.nFmZ˷6cHMlE2wlfZ`tY%Ile} :0 7o Ӳ rNKXQ}ΐU˘hK ?$>7V\;O&I9.rE63 \ yt!Zt2O LW 'rM7* S SF.XN1u+w @`~"LV9   qx'  eEb ^Kob^ ueM)kw)7 } 1Z M d kcI ɹ _]w7k-?@﷚>/e\-~\E:fH%1|OCZ   8  h a~ +)jcnR/olL(< BVD 8 <JQNP g3;Df?/Z x @ |-;"W녴Y#h_kC@V Egbp D UBzoD;ņC j 9 cG1 f=QW .UvR [:%/_\d~8jIi"wϖ nl 7Y5jD^0b]ӳIYbXpwi! r"{Ӽ> U+L  *; BOc <` VPD!Hu(%rn".O&Ċl *hu[Zd @xqV!` RG 8 Tn_|S<솔;6<8r>a屺 4og(^TbMڬ)JHq%;8d#19 |)J>a`9.k, I脷}\ c'5E)&5-&.ؚsQ)@ˣ)!`Gn2{ױ/ M b}?c菔Mf4e%"o1#} "b+ 2)% Xsb^ t'(6+ +P)VTr!2Ht XDB!sZdP%1:a0= Jf\z>g&! pW!$k-*ɬL ݰ4ItQ`BV1hiܨTK/53~8;{7g)$"V7E-& '- .B aZ.]FeCACi qf~ZY.kD1h?%< # ]ٷ*= 0x 89D$5޲q'-# ꀪ|;|qtGzfg/>,n:R'H^b)E4݊88 ~r 5K"F M.N 4`^9uQr˫iҁ 6!( +S'&P*̞Q">T4#N$8D:!5*Q%) {sN lj`>}(=w(x1i%$Ǫ# 17 (Oki` A10Q]*3{*T @x:d!yLU-)Lt WUV  0(1qҐ%gt( s+ &#+ywǭ8+ڱqƵxZ/ƛ&TFe9[][Q} ᷎nޏۙ"ΞNS۫+cOt~_ II!"/l/-$%!cO]C^*L1 #-+P"u +j %^t ) BK5[ m&B¡ %ě =L e  nު`8Ֆu  a(5>D iP K,V޶؞0vn;7S&BQhq=q=~{?gW>fqDb_' c\gc-!hg\'W B [  Ϋ|Cq]Qo@>ު  q>ƓtrAuj}p _dm)kuj}z@QG #0 -K ק aEgtVd (Z EϨدx s! Ro 28lfF_]]6j6q*bQ.j-W ֭jBf6 )xIJ Bo gn=bf!uTS#KT JPv,F3Z^4 ! 0== , H& L> vr $K  a!^V >'^ )L:֫ Ӫg# ԰  `% yb F ?jF yԵ{{ROe}^!.Ї@u9_&z=3X LK5t  UuN J f9 jp 4% r W E]T3N]!"s= k \ l6rXIc&02SݼkC OfՋKZ)4pPqH5i6Sf|nzV A d'O -Zz@@jTu Jq8 vWC,)l\4r,6l_FwU3!@#Y-Pz9\i:i)C i>. RBFc X L *g$ e;c c{GeG*ֽ;D;,R#7 Ҁ /- ٯ*0n~YUV\MY?Gdz^P~r82wbIҁ?H^3WXd\u=/Ѐjد!)qew"͐]c-$J[7-ERD|X&/ O^T q{X %i Z:[Q1TK]BK^  kb "i 3 yd+b K85xXHerqIi $&mk "E=O[Eכl-8_N쪇}Hljl%83_`.o $]eڽ! FCQf]$S F e CK )^ ށ= C y )[ ENw{~S]  wavF |1i _0DeC)akē:~ )ؗCUw Xub?:g\o( p= T̔  ( |7l dOC=6Vըv6[i&x, k@% 3uU -,v r!NaSH Xo%1uQ @nd\yU81=s  +E? f4^cdv!->9t6 j{E[ūb8Nw|fru{^+zfk.   ÙJ8 lX 9sʹ @#m= B caOOxZa{/ + H["I ߛO OB6  _>$|ep=;p\.;0odGX%> ќy =<T20[K?y kmn #rXUD˾gjqRgPRSi)lwAqVwG@9)8JXmdK!B&k#<i5̣5lx|>'![O1/v 9w3P/69`  =[|)Ʃa&͚VT.[-+CEK6 X A f$$NJJ  e,BK&$ChslP(%2$I8_M2ObjbuH33$XZ=F-1ySdbGp Vk,~Zp"pM/7zaR>ګqI}0 ݸ >! ! 6O "|\IW   Z Ƙ J Nm * #[ kn ju . 7@t ϣd7EO/@,R4aU5B !څ:mh6S)S("7s5 : 6D-D>n*|͸*N8C.yE\ s? V=:ˣhL|mzy%JrZ x S_!lհ!,R8) ( $m ] H-#*AF Tp>n @p=X9M)C)͡ɎO>/G1  C1 ,7IFx$25nq/)B0(KM+( mݔ\2$HRP/^zh A޼_Hr7* {~|%Icw<B"0mv KWMdYpS#>V{EsP wW *Y g# oMZ3Q{alٞF_;nn@?$JIskE s 7\0F XJϤ{QW.HWyBo5~Rf@@/tr?sO_ t:IZ,o | D4Q0&e*'Cb TL*DmIg@0uQ~!/9 2YgPMwt<:&5RK:2JWnAp. R+E|Z/}Szv'(1c'7&Yr\d8>k('QGBB|n)lST|d \d EDMuO 5910c1 0-}{ٺ/Dg3IH(T7;Jg=D|5s b)SLy[;IV:' NE>, 4TC HQ] -c ާG4R<$T! ܺvm9SP !nd9 V} 4 B ~| ]5%7b=Jalk~ivw"ma*qtSG{wKB7?0@*6W4n nݤ~t|'ɋ7.j]l. Meho^qAWx ,՛jZc<sbD.Ppx+ mlm<,)BQlr!+ U(ܖ E1@1t|PKx `\Q y= *>v?+:74" !t9a%#} 8F Ҵ\E~%L>`%,s9# S ~HZb}:B-@]j"ZEOS@z5.K-Igt 3@/t ol^ ^ k(2KDQ*ja*vey l,cnNoDI(b1c,P3 d- { fG@l3JrHP*xqB~u_A~nݚ{ 5#?R[&pbh( aO#!ynGkOQ I?. h;3ܘ s x pF+[Cϳn}d&X2Z(+m|X8"'#& 2xb|Y<>rj968J+xe?=2K [Nd>  Lx7>hLR7ea[0wOҟx [}#lO  VvPZ$3.d^G7%EwAi . geRb`"(?/p8y8$|IXs ,EEPaM$Em$Ay@2)i8i3ekL~hL'nA 4i}1!pǠVW^3O`2ƶ>)/ng+Xq2[vFU"9kE0C8`JRJ0l%=_]g~_> `?}(?}Z9 9ܐ]#Q;x:;5 X h "VOhLw#C-Rkk ,(-;%0i7"M*hn9 (bE:Җg!cB`d*ijw62cX|~y(NZ(C_AoKi?$ϼU)q ;+on7e;<p,Vpe@}f[n]jw0PT~ Kɼc\t55<~FltFV!XhLN.jS 7"$^[:Uxi%öy`&#Bs:<MuKj MlYuMD>&c 6P^7)Cv^l\%*n!es+><z@GsNq^zr#?c:2 @;ȟUmpvl\Vb6d%yt$Fr,p@.#:Mx$ 7@ǒ'VfI-UNТx4]8> _D  uT2Y ze ,4T`u`F V CBicbUSFP*xHh?Ƌw Ũ!%7I3wtAntGi/@HTFA UՃs|. "@4jAy[6#  c<QM-UTFO>]fV"xLBIe ܗ"p0YP\à/ ?^m `v >  8%b3sIأ iTC#r\$qLl@ta{,jHLvΩ^jVgD*Olm0v [IL.}-Np2G|pƈ[al\VM-jb|2=EwWc)W,Cگ>/E=P$Kv^jjfJLK8pb˭Q`vE $H6@uN6&`C mm w%ТlHPM5\UoWt/TJj*+ѵHGQ>o<>2(+0:MwwWB[J\o^jTV~jyAGteEuw`9%fIJ[[PZWzT6] bdN7êNq? nBוK+1J> Rhb+K8{wΛLg}p)0G)sF0%{]]Y+ޞbts$?  )*{͗z`fm!MXAXz8Z  in&+z"$sI.o&)/WF3xBs'`;x58VRxkfe@d 7ր2+lOf8,Hagc G)9|U:cGȽG3(X_:^tai*q %ɪgX*u#& YͤX0wxW/^KfMjWc[q )rɲ\GN#Q O ȄA*(b<*ZLJa{pc=+J#J}zQQi[YZW /{{-^;Um p$wc[PiGwۇ7+Jtio sUQ+ %N$/cs~b[i1'1_44xL'$fapL|V\N"@.PZE Ř* YHknNvm&.=m#SKT ]Xk6\.A*//"#7. *Pp4w ]Y`I`t<( P/4^K'27Ik"dlkfWlFe%}4(~H5ǀ^lI%FuI~-N"rlBZbBw$k9 ߉_k$rkBM/=tW<':dI^K`k'Z%G6?}ej1b$VڿjU_;lJI7#K 'g g2rKw$o6"}PePuxU{>.8vWOTLyw3fjހ‰(Ny"lxZvEPMo :7kd{ QJGb&Kf}My 9-2~,N$rQp5})Pi0nI, BSAIgB g8(f8gfKo1-NRrunf%re6d˂?g,(QOR=/ ^.O+XMƃ8dj!4?fJ'/AQ>nX5@$g!9JG|h3߃ɿy:8HY[)` 1bʙ`nJG !m8nrYۗ`>m!D>c/Q0fhuf)0U?MBVXaQuUjW"j&LǏaTQ0V('r1/%zw]K/sPr{FJ29rA@sM^X7F{7Ej{3W0{='n)[а<#}gEW2:.s`jid|(u1Y6E f @?^jC:!0-&u P tw  }$ӽL_w `c~]zB|j,Z_4)#wny `Qc (TXc#;[av&g=mnR~3SC"kK Ia#Nʂ6lnu!M' :U&w~6>IUhk),^Cx'`a 6`gh/e_( lQl}Ͼ"9g1W8b 1/6^Bs3C sM1E97XvzD;zKTv$&LGPk8`<.3Uz-tVGKN\{V}>C^0^;6s43:_`3wYIa.(B,T\A eQm=elO%xNF:PKo#A͍@_IQKy@&ߒIgIRį^SRRN:#]L?2OZ7efQ$8Xno=@e%RtLr_$YRR#3+Xa\\.uG2y&_y{k`V q^vy?EOo#oPUyH4 ENlx?i<pS[+eir|L͕N8 p*lj$ӓt+ ^@ \+DK7HD:9_ݗ^X"1֖U EYw+rq1-Y$O4[ Tz_`EvZ3%t1`#" *8vW5h4\qeSD>v$TIܬ dkP[TQv;u D ȮtdqS&eF/[ZC>8X">@;j0R,y3rwEk;9tPdvD5AA g%Y-7C&4HA@?+2]u0msbb) ,n",.751p;SdzYqNf2f@Tn3+vOfϠI.T`ep!]BV<xX; > JuTsCyA*u$HM>,_7H9X(ё+Q}-q{)j$)s? 5G|~=`kN]V1;43- x`_ H9W[#F1DܚOonv4okvKQJCR*H*NDɰ]w4pD[M $msd-@Tpؠ S, C^ R~Wg ;{:;1 WZaw(9o!\F&\3% "_i=f)*I;H:=b}uLwk"v4w1 {GBGNػgPpI_&k.dIT+MB=<'%X:n F}\D4Sa@m/1=Y#pF߀b9uQ'flKoXV2y>  ke>`9u5AM%4hBj>diHp/Gp,R^C/r Kaz/;LbSI$J(_$M&{rT:7LLh-:_4q/][NM=%*-JEQ7""oʷEK2oR6cVS]BX:`U+Y*iZ Nrf)'QmTA-+2SLUUBm.(EI:llj F7S[?+3b,^KprIUʶ0OH # 9FY| (T93qa4v8߿7Gd*l5hbxImNkWO>%RN2fU~SV@R.%12\+,PQ#?{\lRi_t%e>=yJ҃ ?.aAP6 F2FleM  LHNPMB!xI $H?p V;ĦTj:f; J&[S{VuMAxbQdXzVZ}!ز`|xF9w`Ƙ +9Pr+pP>/Pj6X[k44|fSY]\>dw 4Scşo`.\9oQ$IlK|]~%t~Mnx̍ >v)iS'5`ABP=YJ%g)+:-ny:UҚ#jkQnݒxqu)nRT lF F.i,LsD-Wl]SeSXߦƣ[$'BgKKDK1=פ]7tbKAVsbdqru gY|)V_',]zkq.c!Gc_$u\*CjyV?Vݸp?+’`jH5FIU..P4<jL, v@}?BZSk5GZub7r<d Xikb (ul1j 2<,5v6!Mo[S|ZCi>/ge4^y2AiP;UuR-. bQ*\Ou&eu˩3gZTo#3"}z2sVyT cCGf)kXĘCڴaE4D6vPs\(2-+!5e/G<%vn8 EBNCXfk-JJ9R3aό+J#R3zkvW"LsKS< ! BVDwf',z#`2=PM7 Ѩ.T{eEGc.V{ L|8x+~n:pbMP1p6QdCC~u4V{^KI1` f {urK=O S440.5u<%+J>ar/G`(38?/zQ* h3,zkeJENNs1fp"Vxc‰n6`L)k9IT`VjL b j(:Lv*zl1n. >k[%ʘKIGN!JXt{IJsi/)\So?%1`v(z@HLB^C| ivl_Xt)A89j:P̈@"ap)|| y" {n&E1 ƎkC"il",DhͱřއM1X@pPl]1-kQ^mFؕF;9Hh`Os:3QD4D!No~rnufCsX2OdY.p/:uz)8i [ )d;oP Qj$O d\Yp=jP6 Y`zZc(v! FX#ܠ6*q8+ SCt8ICσVC6H ɩd`Vz!)]@H^ٲs8ҹ;uKa&CD"` ٱZr]m(O G <_A'7R#Tx9)4;xa@$Ti9pXR$7Y@en8`V)!vEfHYqjMҰ:ALO U!5a,U[cg} hlHRjbE0r| xT*NnԬ$JPX+G4yI Zt7bkusOVY:]l["UyR=,7E% gme+V :5V8X>fDpG2.akbfvBA&(~C TǢA:vB\6tMYqb"X Ec ފxG9He G8)Us0;\?Ks-/>{ vz>{pnT1HUfJ w*NOY_ ̡(K, Ƹ|[|=k:;XGao*ĒnZvKu[ǀ) cr4NUval-oKP^QA`E)XiTST_;7X3klsus@C4#@xXyU7hK`<?Zph J2d`>B ~>lbscqi }2"+pW}T^8CFU$BnVQN>lZ!9,*ct[}m`>xB8 JiC=zjXY^FY)r19c#ݬE#=;v"}i]]/6@\oT!l3iʎa0pD)`۔: Pc'7F8 [F;c{ 8YZ EOfPhBY-6o1ֈu]7CB`Jk-=2XԆ>Dp*1I:ϏͮK02qn,4+*RNWYs!٠|iMsz8)e,x5C-kb.IR- S/AhZxX,e|`NL/,00-=Z>(5l aFd5y*czTQ+ex8huS_ĎP/^XMͥ7cG"Y^3PCf``C[Z10 83_va%w%u,\}TQsL=~%%>apK7@kodKNǑLSJB$)neN֠j#ESK?c`׾qa7B}s61D{F 5#KOx}hW~<`E &_ 3ZyqwO¶orI#{4AZ|H] ER'[g@D\bsG7&Ha2zR-5Z#]ٱOQ3UDg0{{?PhR!j. y4Lw%Tc~jaKN)IDK ~I?g>Zw{iU~:BBsCq %%sUp0:n]<$<x9.m]5 ;\>T LD&y59d_Ws |FĂC]2X/hN,3*:!9 ֛I @|2N.lL!1Y^gp 73.>TƂvKK $Wa\]Zi5aa sOXȆi R%j\@F: Q9~vj07(Vfm0z.^Pr zzO@nQ[a6 ?xU9o4U j#5zMU&v(uHO1`6mtS+%  NEAd ^55[Y]'m$"ĺ0w yMq@@|zG2.'7WVw&w]j|FzfG/Khč[8ok$n_k9r1M`CG c4"] CDQA+<C )uɆ-OZ1Yi}^ؙp "CpyZ/{+| 4ERhUMV'NM q,j npLvxo.N <$2Z'VFL96k,G Pʾ/kaPI'L"DŽD-aw2"|wISSh;s>@T|o xݴW5vK:tE vwf2KGDE0 3$w?G?E~y8h3R['/_+p7uBj&CO_f-(\[.<`aLTr^`WlU6[V2&B/;ovAKF]IDOh}| >&3uyKA4xxaMF8S ,`+I~Bn1cy"&zz2[ A5biv`YjQ) %%o Guѥ!k32h. Sşs!g3Fw' ,fv)PS9@Qq!/"62Tpr.x2LNޢ{۶`o Y4W,ON% n}'9TDu"c?&-QO;~,1C&X>tA]isoR'V""&Ug6!:9Ѷ6rt|j;Nt4g=]ckHc|sn!iyZ<]A@x{kj;LW*zWv~gGtQh1e~NƶwG<^;7 O=LLC=U Y)7eXE:V\E oY&d ߊ]n #*+<]*fE'& ]SWk7>f' p~u wJ$NRl?z]8seM vE)bBG 6V'.p0^s߆hǖIg4#o `^g R> :YXiy]9=|1[7:Zw EOomLjI"E .zVw3*4j4*B!qiXؿBOΛ; Ow %|LX&GM: =`[.?=f`qN^+p.ڔ!@Ԏ' l|!ny Fmi`DUSzo6pJ/)Ѥ)=y%K,إՁOK7%wE}`T1r>z[l="SaYnE_&iX/%9+4LRzlӚ}a%Hg٭ =&a{-ʉjc$'1^Dq8 dZw"kR<6\A3dXdE-[62bo#JqçX& ֵcv|Kc?F67zVZׯS?M@!Acf9_p=NPe@Ud/DM8204]Ǚ^9okH{`nn}YIj~,gz<?s.#M)zv #*x1;^W(Uq8X:)]:;9 $}iq?VX~& !ʙ$)jIP`4YU5,tpi]d&],+ceEM;M!#3$)mMV.uD`l2KWHE-LNRjO|]F5<i-,ze0` <Nh@bs EuW `L>_n1}:G]]ns %nUw71@D2m֨m, c\"L =O>U5Ovp vpMZ]RGȓzdi9C(@5m|ЃK?JxdO& \K1X3dKp}S~C/T}o| :%~aT><u2gD9L:1>˘0.2}fThOLaZj{)myLM]*@3}(D7KEC;3pK֪whpw)KN,]2NzA>E(i3TZ ǁP(nx΍ 2ݍRLOi uIgO"'oC̓*nhQzZf`Rxvb@}4;-t%F a8fi_SG{3 >.ObSjSRG\A~)tE5eaIPHNp"ځcg"-t?6/{{QK}c;x1@l1c}~z\D4349#~zEvU/1WUxDw#ܕc{.!HhI`z3[ 5\rF hh]+SDrh#t_DTbCji 3UM\YI^hRn~Rs7FϪ :Tqd}^vQfLkoeSb,Dz/߹uΒW(ws &*2;yDESZ4 fE n!>-1x{PF( S#*(@^-'[W[_UuQjXM)EGcMm EKM/=XN&Ky +=esm]\s%YUkx EtX)qyftP=bHsL4!Gout>[?DVrI^6 0[Pk'ϳb#$Cz)t7R\J/)?zC^{ $,)l,KY{}P]x8׳fN5Gv1ϗRSL8z=G.XFr[p\%v[Y= wȩS *Y|zs̶|6@Fm M5FsXjOa)~"0P5jRn63KI A8K}{JgL73AZH~ Zc Qw8:?qx2p!0iYm+`hjb.{?(@n 3)-Nmr6V$45DxB.)9EZ."|B9ZN- `b7zw@^wkg+ 0~H`jk85Q(B#nR\j׽As-^Ty#6 a=a޽|pf8t<4>%]l;PBtYT~MAf5-{:1x1S/\@эQ+<:D"PXρAZ8K1r(x;1(^` (6bzDt=h ݫ`^҆gGvgOfSuXH,6*Y,b#]GW#&Gc~H)meJu.s>/cvvQqPD]\BlCY0s7WҽΫG p0GD|[dYZdQV z kK$ M2L}01(~Z5wT*s!|u$\MUB ! x P>/[x3y=g7S`e_,%@Pzl_i"Ə^C,|\\r8L˸Q#nV~^/ 5~U`W 1H"h>`Ury:Ͷ &!.y8x<MJ>d8a]ZӔh*0|R f tX/pK5b.\ Co /TO}(<+I?UFLQ4^Yȭ}v05p]/7TsEJM M.uR{[w94LR)Ew&hy>gS# EO0W:LSQ{S|`~W3&|~Q8ay6anMf"]ee!l q-WP*'%(A#R 1OgL7;j2a Kn%+P-[-,-*k+5 fzk*G Lt<Á2.,H|9Yq8OF3ʄ!@r7Tr I+Y"5Au(>u!T 8u!m `6/;<@hERF\:65GlH@8\f8qr>Sv%z]UѨ)QcT +WK$p B>qAI~YO<#؊TOpb]zK>j1$Wu'&V\!*ed5a(Q QT8 fC/`b9Qf#R}o[{yHCeQKY̭NyDo!~CzHOMep \ i8fE% -H:KШN#jWF]4RCeo?`NJu@v GAS(63T?۫.92!;{0ڟ' |!'A׌/XH=ZbEQ 0L!'IZylцsnx>),Zh3s6)gKu8}֝Ar3P0FOp=8DJ f%DcLG`moe's6w"xq1ZKLS98j3MppUAUp0PXbHnbOS Wn \ D<2sgt6esM&Q,}[Ӥ^3 C 1v_ܩ$_):*U% -j$0;(kd"X"^%Fr}0J@Dsv`g. UcxDOn{VX|'cpgՙ>X7)C%/m լgHy!?bR#Ϻ kv$~ #83R/ 0N$Xއ p[hS̒iLLn[}q t!1uSIE~"eE'k2wrsMwϽ7r8hsEAu\>R Eʯ0N"JXSq=qH5wp?( %Q(MC< %,(} .abN%Oid] '^A6Q]Xgn]Cj*uz>}Kv 2"21-%lx4y0L0\"e5\~G&q sg~ y\GFq'Ҕ:`y.BSǚy@zfzt,\D1dS!&=zCҤժI# 7%VUq (]ע^[Yyd>}yVQf mL< +e:KV)a1*:0QQG8ҧE6,>Ǭtğld"$0R,411c/}>> >Op'UwsJC,4%ݵ,دL ǂ2dlW&RbHܜUp  C /  L_Z^ tIKڠ)Y%7-hsD8^"حzY%[<n"&= 2i K(wo ">d^5͜u[GEW,#-<Z3f|]`b_{Έfx:Myu4*7Tz5yQ"@Hk,[T\E43pH_`}yPJjTE{5yHDpagoC E8M/ˤ@~Ծ1_ha+f t[K7*p n&o1wKZt.@q(8UVw'j,5 v>T+&yyߕsCwvgHsL]}L]"|O #ݻHԾ<;zi' Sm0!+HTДW;#4Y^W`[\BqvbisNR6.{PUeӋ%|JˈԎ1stSeA]LV7\xbY oc%SisBmkOh;*dT~lgM17q2܉c2K03L'H > ]KS"9 Rp`;<L*!6,B[ ad:l1b <,^u 8 ?n_Ȫ+lOHXTb+^ 81D˷Yl -gLMo^U.vFyi9't4$XJ2o;}pTB/aCO1s_3q;&M0;6-xFYK8^'ewCXº_u)|XSaH4'~})} ڏ #i'f^t91B.Rp5jn$/c"xL# }K=O_|jf5lLXQa*e4hI8 (4`4X,~!.Q<m?t7>cOkm+~X=Ppg_}BxGGaSJwp/HKAȏLpCi=xFU,YYOD-\,(~#.q :$ehmwy yb)4J kmރvPh"Օ4fE$X8@l!Ɲif%!pE:4hL<5(+DT_XHmM!1!%9 m6u.KtU\BXrٴB5i+P}GQk|nv bbsȾ1:_m8jyw*t41a jl4 FV4Gxԋ)u.R7p&'Da 3/o53i;NH&:7C<a AFO#Q_o`yLI]S'PL a^kBn~h028 pTET"cw%(s1/ #I& L;+3!u#tcCk{.OfT[v:Ͷyd&ur :lF,v<=?!_E{*݆|z\cafAI6h4['!!Jt4hgέG}Ȫ4G17osf C$"4>u^(l*((ZD]H|@>I n!lV*Bl5A^78Kciq1;zNrGu\$}] 0%r` Z<,S= U/9&cluޚ6 ]';xF]O 7x>-5$p)5=1{c`שŒ,Lh Y0&"CMbs:\cP5w &m2[?/dOAE<6D#7Or2EE~7 ;Cͷ2ac<9NlEUPf1g. `Xj {9DtT\P|<(Aj|K Ku& ;):#bE4!OGO-7L*] L:!-8G0oXJ7E|A;E i3 7E>b&ѧy G OOJߞ?WKvrZ+9sC*$ ]%r&`4K*ZZ!9J;:W]PAl@bg*/U#v!+jSO|Yj[ RI3Tw6QQ`a4Ab,%b7}YSc1ͻZ( d c 5! &[ /7teXOo"kE_-ָ\wGoZrhy&*yD8Z %HH/SVS/YS(\(*sI_Ec& }Cs<V ZG&0c݆^_ cG`$dbgTLTSkIshcJ'd$>N)W>Ah;EQ4pf+15YfJ'0QdWyLrnPzwkx*N7H&=7YBvӂu' Y \0 ]`E,,s'efG8iL9[z H QbCgtULo16pq }-C*C !h8Dª]ƧY]S`)Gmf8eg &` CMh>\1#8$#YAIeP}k-0@" tESL~?P#|ݽ;6ҟ3jm6hUiU+sp$SS(yas/tb  I+dltc,ā2myA}%[+%2GYߵLi(Ο(*NAhT aiV9 yd5?dpo v57575vWRxN=RcAR49.xd%C/ Qv?CB.z/R&GsX!H}_* 'Dz ݤ`0XWh?XHKOʛجyt|/5K6 CZ,Y 6t45?2qLH^2D')|-_>a:*%CpP &iGTG8))@aw]?|l>tTwGqJ]Re{&!T--NUA> Vn6)&pBJ Nh2+w4ȷR 6*I579i]>&+µ)nFJf%5! B2JpHv'=L-#e }@ uAQ+`_[zqCX_wf5YoϿ|{R1uEIP2e7 ]d@ rr*kUm< 0;o[Gx&~ CwS.D0W\YXh=C[v G-67${& Uh04&60M]{߲-d;?4 C^htzmB|(J*L18,ínAuVV)d'JO5'4 Pn]g^ZWbV8XV~=C 7QG X>a.5#3)+( z8PrQkHP#}#~ #8ƨfy-8cC:_}N3[= 5%; pD2^V5Uc q4W &h Fs ;/*FJx7T*.QpGo4O6\GQpzȴT)H.a#3C #\;ILIkGJO1Mp>$WIZ ;o m.hT@2g >V ߵ_B$ 8('klKD*u*l{8Ddԣ /K/h*[~"ifVc2HcB, G4rxuqAO4\^b6@I PO;-!OFA9 ?h'W@`b(sF'qD"+ZL|^ 37  d1u'Q[(mT?8ڿ4te&^;zKNE =:@ ?SH-QM6AF 2& 5(CG5$KbA=C%,u B- b:IFU4ĩUY l4_gGTAnThG *Q85fÚc~hY`aX?:ndN%lFKy+ /[E$ rlf+\.+_, -_^ ZHeV pk[S(+C%4bPX$yuP !&&2$ ":7] (?" <Yqc+wmOSo$u~ s[h2?>|W Ok& Od7y ǵiVܰqa;} *L(JJ3"%9V j3s\p+\; "!WX'62^}&GO3L7+nPsjHX( *^P#V. $`8\LګUU%F/ "%e r=( J[ET7r.)6#".gp b> _eh&$Da&9cʫ  p}?0U1_Be/_B{ @;`|htsh[7')@u/9$qn1)Wf/rR_n- [y}]_D!ݠL(@7z=|e%l P&p"r^5O,'%(^ y+ZEgD1!& K!Ŵn["Zv÷IVi ;2y_d=gzVh@B4A1],RG> KR !G = 8!S:xO:8F0 d'ۼ> 1)+[?ex2#Uj&g b 4K 1" !=q H ![-70l%t0' 1cI+R`@8!TSg#H AUkw];% K[L 8' *$4.us;: F   3o /wX4_`H.G?̴NA2Ff" `XBa(Ռƈ9#s0"22(( </ c!/ K!X>(ME5&+?>S[ YP'S(K99"Rr $eDw a{h3TY)9t CasSynN "M,\8+.3S?B "o A.db#i9Qw H&&/!'$FK2 \NL-b }l 'HR;=&6?NX_7[5? 3 ^x:;w3"*(8/.3'9-34iIWnK0ڸ|Z`G%d(EBD' "soIUdW 0/t Ns ^1_2EwJ5?)!*zP@8-q.u%1cK4Clt gP($<.)F1*0j10+\4P98=@2.HOy K@3\ K5e3"(X k9, x#?<4Sbg.PcWBd "Q}zxEqH%uvr&(<w+8T(Z$Y&M0ؾAPZ\ WJ6m z =/'pB{t+'4 6>!AGE~/|-$0&!#M>m`9:YT!&t2(gFZS+OU9TV{ T9V^5P{0F \Y,m?9FrƷuP>`)&1/ 0 )%q -?[IlD0 'r1XSoX=Gb2F 4'J,!8l*-ee3  >!0H/+KHzFE'U}f{jF]VcC g?L*X^-Z D\ >7 ŽF7%V-'-!k R\+~96&&aHнe+x/BED4@3DN;?o4%&Bcf-4>F@91Tu Sm{y6[4B Qjk'0N'! R}#6=(1\*XF&"P&AJv:^+P$!Fn7-j& 'T K /81t9A#B,%3r5O&*T @5dS05&T<"MZze?H_ )@G$Ml- 6@:!-2$6&$,,o,a ~:; g iX mM;(2-.Tc1Z*1(>R?8@(^S{lm Ix7A  *f#g6 @s.Ԭ=1C;'wewl(  =K^ ^_'_p)9)l6 -{sr w0}%'&'IL%t %! s&$f1A ' !Mt* $t+)2'%x'!la  2[wx{2J1GB,=* R ulVe}A c/ $S 4 };,Y|;m/^ A^0  A;O%Rкֵ J"5:/a>"F"HbE:gJtؤ0 c DD# &)' . %&K!4 )s,5)` [$-,1;/-%uT+ % 3:a8#8 73d)| 9fIt5GKJQ|#>!nFL :pS'MK%6; 0aj} 5#5}Cz7[J>0} -(.M F,+-,!m]168 /*^C} G;/+Fm*,$wM+l30:$b "{-v9jX >_>iQq"x2)tFI2[mZ!C=B!`@)4<( #% @6 lX%3f]/):='M=C* J(I8D7A/}:M+< DCky!.0%&7gB@([) Brh^> -%>#yKU/F$/@ g u!F1* %< c/ov."\"v3 -Q \HmM$B B!"</f9--D  D]. G4yES@[$;IL.x^޸+an+i %qfu N> pE'/b46k1DC $<*D(r)K8#9KG{a&m0$7_> vGhPNQVD\'3  "MfC7 F%N7P8$- , 4.W=='# J $ C}s #!bNCl=oA"DP0Wxd'M 7>;i1@"o ]+c;s J  Ew)4R=s 4a#ds*1 h- k"' 7K5K|&u4QR[N) +/&YY r)V&B#!*,"Z:!( E> BjC+` 4^)v6y8IN>XQEb:yE-vc 4# #0*8 58% 3 (,*uRbuI'A) "F 0rmf   s) m W   0B-?=ti%I m)E*@B,^U\3mTB"@/yX \jxnNnmGKx0 @!31n%$@% -Z6Z4%ouB|[ V |b~^?qp[W9h #Jl\k(8QdB1"C$8!3N$U4) 'b"F!.2<*}Q};~%),PEhQJ|92 42/Yg 3 -%DLc< r`WcUzNAIu GwS's!& U] B}Q k86CID<J#*$Z ] G}OD3 G  3eXi)^ 3 PFv(/9#>|&~'UwdH L=t) $k3 2# %w0s8g.+uQ = o2Y.%+] +9+&(K4*k! | W^:zZ&nQ[` Toi)7+ " >I -?   CCN}s0Mu="%j< A @8u)i( v 3 Hb7&\:)f^"F@7 er.h :jg F#Udk0a2-Av~f3^ s`K= 21R{BW>( 2  ; %!@a Kh 97 5L,- 672!K= Sa%Y# v7}gG:g;$! -#FbNMQRM7#+i'z4mE%)N^beVOU']:B1j5Wa%t$ +p1P8\.R8{:r- b/ mتof>}9 v w1wBADg7K $w,c $7xF>x;+"3L6hC$Pj<Bw 3+U%_0 /IlH6g-~ /J  ,"51X!8b %]vnpdW ji-X7 E#@.8ElD|C&5o/,;* 74 QbS!V@ 'k'e#I 6U,ٿIF <($! b\ $t;!U/*Hy@hK!/7b])a J0Q+98V(Z I#6f9K&1" Hk9*{-ZcM+YDK0Al#"im+y6b}UMj#&81kc$$$!E ]LaF.{-7"vI{ }~;l Y 534@@o)93-2!  M &t$+?-4W( $+)Gh!.l *;# iN=: 6 OE۸L޸, K^ x#<pXj`cB+Rwz U49^Jg/5.( u y6T(c %Eo=_Dk  ]vHonP %)5/ E#bH]lG-"9 D"9@C5_ !)$Lt(yY-.(gU @u\Pm2j"j  . $Oq f rV&4 (t+2"{F }Yn)8v.8]O^?#;DV&*)*"N_;&!:l2-QTGeX&n+E!T g'[4UZ764 2,%4 v0P?PX b[ N.c f g":c%K&!  Z&'VMz^hDi_&!&Ya!I& K)''&#w v ) ,Lu"`Q>o3 C Jq%j!Z*yj^U !%GT) #.hm{s*mTu) H l;G(/h+ A z x9e/l' Z1/lf$R#.J%+s}}!*!+% *it27hlV)?V9 C $ !.?:[Yi71m AVjWi<mVm }]"qI%&(.3;'CE;}' N{4 m!.X'3, *, J/R  z4SǾ d #) wL[Z? Yw`!/$=8.*AzB}, r.\|d&< i,&21";$ YEww!_48">;1 ASG*.Q,* j j%:gY_~:xT\s#+s.# ,;l&B>*E-![vzyZ.F* h0zW@;rF 3 w /  yP m !|*&&J  Eh< 6#V Wb*2 9O1@n37PC D+E? > <*8yE _G&m3[ 7O 7S1)%;? 0]`h3_Ne^/.D5!$((%~ -$)c0( Qbq6_~X1 ( *B  ,G+criG W$" ]: 8-}3)-o=(@2>K{8T 3Z  ? f rW+| !N~uq ?[!3oqnh; b! U+'m( 8{ IVUkD7* 4(%` 0 6G($ P^IlYcu(WzH/+"4"%D]wT2N@99b  oQ,B* 8 'o b8M^R$`6v7&41 yQ d W- ,T^ : SO b HjH ni  V@ ?'U 9 9 ;8)* ! ?1c 3qI>  y h 8 E# E nD)i^T[.{%b1w'&# * HSR^tX -Eh} +, !/v#'l"v +)Cd |n|'mTz Wc] %rr8TC C h:x(e ?FWnsA}.lQ.M Jvy$(>!m z H g S  GQ6rk !!y G&"g#*0w0S-=(i#pz#35 1, ?d P>m ! +*%; K[&rW0?ATO [u lH &mP ,~Ks U4V0[\&]z( .a p 0 (z79SNb  >#Bc lrq AiPXOD S: 1R; , 6z~%' +%8Y} H`,ZI%* -w 67o2VC+}%i"B)" j# ~{=.%_N%~L$@Si +o7#xR&+ 7bl0YhX: {QWyr H  mX Fk& oV\<L *`#l  ( P,d\k Lu6tA KLw!!y8 @ S=9_F(I |j\ % !,?<i H hVkUWsF >CCCL$;,IyIf9*\ ' U='/f . V$V+K9(QXqmp$ lg^h >Gj l/ G y W1 R 5DM7 O 3 w3_=}S Uf tV1 _2Gm++q4Tv-fJM N[wP+3- uc  | qK ] LCSLZ5# ~~;Qd /}49 2y Y;F: T0Vd}D <Z#;  1  i um c]> A"I 3%E ,\h?x cS  \I  lq7W m r8t? ' ,-I*$  - DLJ64 uPd%/ }`j*l-#0f"&,+$=,q]('W,!O&&Pw2OsL 4 SSmOXfk+  s7X $x"f$~Q_} DRo 6&-G 4R%K * W ajC q\ *q SW R> U \ X T@e jsn1~,u jE. !d8h^&(CC ZD iB\ @Dp-nu+ , 7 mG , # /  (, G %&)IaBeL/]7~7F - T|  i@vN-F"t!d F _r evA" C$a}jx' l  7>&34S' #;XBoc 7f o &9r,T:"  ^R  m O g%N5u v v  gLl#X!N JD ^<'{H`q l J  :rba7 &"7n:GjTW L+Q  ) Tpj^ C)+1M\1k%OF f2| V p}#Yx/D ]QDpU  q  M  nuN6)@X S *s.g>,' $  DT\!f5]_> w  x _{ &wGws<2%#um]/k@v b ! 2 UC $!waC;Ll0j 0 |vIYZ1 MP|RG[b$_z$a  ~ k#G ~%65U_# T.s  A [k ? 3 1f1Z2],M\n t XG< E J O B_"l |ERD U:x {NK3. H,F0M0h{BaJ7 zYO_y3&A,hxTI {}J   \hH x#;A U R p}C`7c Y3  _pE 2p?`3~To @D O;E2+80-3|q W fv 7 C _vCbs \3CA#J%%O".e B6Qk 5jY  xC3Vx Xi v$V PY6 .!nJ ; w 1?F  Tl-ka ITSSb6zE4b #^$ "3]O~FM'tT5 c^K3 1h c"c +u; +d0M ] DcZ 2o" # WY exS/r   EBYHg    cuU$d o<   `E; {  z Z6f]l:OM RgH7  !_i%}&aN"_2Kp ue[#kC4FW b o -/ Qrr c] Q2 'NOHA{TF+ NQa GPk\j6 #Y _hAy5TFzCDo ;p1) |Z {hxC\" q W4AS Q x w1fy1[g$7M7  d{qu8O} d R & j* l 9 k&PsOhzo=RcH8`bVA@va0(}[@ 5JO } :    =;3MA .beoE> 8C~ P - ,)N_m   $ $@dyt=oD PI 0\7|/!:J%   } oID Zh#{yYeA 2P#SF & 0 !  tm{ g $2  zk [ (Ir>%6 K ^` i2ma L4| N OC  - q  &H}'d  3J[+^z?peg7%m+ Fu Y   n  V zB ~mk $ WF%ut/%)|fS-|]=|"Wt }Eqz-6 gC9(-N#C|0.q0q [ gk ( l +  6B )+ ! *)>s_  r WY+ |V ]QVHB 1  .)b$ bssp>! HPx(|{5 f 5 C#@xc  ' 7 # i Yz! j !? V__}|=Hj 6[9 .zyP  :  V  z=eTdI~:zBy W(*K0{ zi)lh'J%8(K: f 0 31b9/_yw(nd~-?uAv|&NV$1A~ = Lm  z,m Y EE SU2=p.5mw /> 9Jh4Or X M3* V;jlVG  S # Ah ^ eU 8 5LA F.R7x TT C+ Y ye X cCBdfe H L< M jRGap])K  8|b,Z P> K 3(4*g I  -0g\o K{cK y^ GkKaB7\a1 O T ,W)M-fu TG4,nN:}_gz $ + $ M>q * B,8 [jp-: k.$VV 3CJ OUC H{n] `emlm\#ck.  cl1f,WXk2$C-aG /[ LgvtB.e r 8 4 <L83 8} OC -/ ;-L+c Q% b-1<lqMUf ) v^x | jW:Q6   y4  ",#B'&n K {>5,Q p@ *h0     b  ,F D 1- !  "8 < u9c?pNX] \c K Nc"{MS+ Y _/eJQ  ~ 6i0&cWdu,.X< [u`gidC_Y+KC   C1WdJHfI 2?<  %T Qet.- v r2a ' 7*R?R F D.Z7   *J:-)G |& -I  b{.> 5Y(NH YeZT^ = Y1zqFjL 9 cQ " Q  ),a _a -:EyQe1j6;ha4;=B n H^ 7 # x%*nyq3K q)  ^q !0$}k$\~Yr?V  6C:XHx /b ? a.5k@/nQ 4H]FwtR9i h'! rRrjQd)3 c NR|4wYgZ,& p6 : ) ]s w]LsHn V  e? 0$9;cQ[[<aP3ja Mm( os_XxCH [ KO+  . " 2  +B)JvLM  x7G ) _ >= |U?S%+0s?l}B_    CS p*cG k?p_ ,b)eIQ`*LGz e  SI5I H   t _ @m~*Z ?  \ #; -1uPI ErP$pL gF@oM P f` p FD3Ni{B2=GR  7wJ 1c!x1Qe  h  l N UP4xX?{cKAm^U5bs ! p VR V}f60 kxV J X x< !|t. ? R 9$7/$]K- ;+^cl=Mf %   aG@SSw< w8 b z00X M G;J-\yV2   d%sK> ;4QQ # p  uM@c-We}!,4;kg g m cI D $fMt3H\W xXlx %'UR H^>K ( @ S5j WK)yin.7 R X+ 5N | u 9+g?m F   O ^ ! -2g$hD5I^  2 Wo&dg<C h !~ M v^ B)cl) cI^2 R S 7F U)>V 2N '|-R Dqa'(zRz|`V] Zc0DyxA%-p:E nbH@ |>-w2O  hJ|T@ $ Q y 9= F   jEX{_:  1]:[ F&ZtpAsE>d <  .} $L8v$;>rDWL!H9pp]5q!(~)RJio(\uh E5C+ f}|;sSG&^KuX ` SjY  )8 Dt,z2f_. 9"  g { Kw/lRf-e  ic p j PXn 'XIxPi,bJS1w K   2i`H0dXbM<`/lLEBqWOp)E-9N2`<* &  qs!R FGe 2 l= JH ]&WV,*Rp2/eu 0,$qPsw 74 \ '"7DTIwQ?w'hYf!<E IV3i @ mS $ W U [9Af 2"\> s Xg hWsaoH= u GK jR|<k6KR-@r:n \ /iyJwr/u@/  {s9;Mr: ylG&j\Y2c]+6. X .0 s}C>-n/ [i{2xot 9xuAj-4+B|2 uT> DSfi%^  F ? r )f8Hip(+qb'b, mN:ZdsQOxh[~p#VYl_h EGRkQn74;wU PCoau  \K v {ZrXoi$,'8fF9YaBjmx6Ht9b | /to5XdoGygy X&);6R)$ U  vBl"6jos DjHN`Fi+4t^ 26f9Z$p{aH  l ia'} g}}0 ( K  ~{i`N(|W:c$D|eAfVm$DVT[7)hH4hh"D+yQNdA(^zn <WFXk/$yS2?\.ytY "N]zmq8 !wp{kE_vRWdp{0A@e!#4Ed i!(6L{ Q  e CcL y k.#U^.lK;_P.~EP4l.,IDLd)vyubkWT?gR\K I7cr,du}troKD{~; "!xJuh85ENiD$BoxbVPoPPVNJJx`tVJ/4-}~S/'4>Z^bMs$nn22JHnXL`p n _Q$sMK4uG"m RC] ]-+jY H\,WrG 5 (2 H ^.fCl !IGsK $W=h`a;s LA8 B^'g(^{N}p&,P=r)~o%5tMr04.- r w?pqQ-< w6sNWGD0,id9y'wA, <4{aFkvZ>7_ t = 8br3: D$ s]<yzd}vu  l%4#k 7 YKJI(^f,~?o No  t!Kl]~Q!.' xf( P-A/e"_bl;S e%n+##NE8"s_APNpkVQBR { B{B=  /B$c?Dw/w /1b B0(FZqq!I;P=a*EpGIz%Z/P8h /:0]K^*7H-V%VF let|"&mj$Vw{?^ /hTXwZHG l Sx ROyRp *xOaBFWTW5@91Az2G >wpc[f ly_%1+A~?'Q.)<Cu#cuJpDD ]( /{IybC\PYm*/d!zb3kER:{f|vG d 9 K: 4Y  HpA.6WX'#A`Y% LA + :7  DY+T>a=N2hL_U|Vh 1D5Y5m7zy-kqkwt^KTZ|s3je2=72vA\ZA**Pk5? ;-Xyl| K]=gtIPg) Y_a @&J2.jl09KC;DC {1]7}T\K3e..1b0`*d! XPZq2z\`+$8&NmPo!7F/2c0/Lx#P^.sh.HgF c"+Jq X 61]C,+6+H# h< G76Gm.n{"oh {0Fo6k3.ZStusp$}*+x - YiIwq:PNMI2 J";hSq+cNt?\O 1"UwD% .h;{/$3 #X:ahCI1A40!e-i8j";1Pz:NU4`uA_Vg]+@5tI!q{*P*ShP{Pd{k>^FQD.vQkx4^;DL2lzL>N*Q~z.K(6wR ~XRTymZu!]n0 Ai49nx9M&Cf[k >X]D7x|j#lXALJ;B-1TPVBb2:"++#nV~%lLMuM0 ZnG|@ w,eu-#X;`1 Nq"_nSwtqOvE%M xhL@j@]$6 4Y9Kr57\KX;*-Jj~w7~'ka8U` yW}F G/^'-0[khx8Gdw;e}N>EZj}}eZHd %!o]C],ky*^rjj /F{zY i H@8P60P5&_ V( ,)<e7&@iF zT8^-Gt\c -0`g`4}X iEqQ*}=/-@9?JK&YCrM"V4MP,lR<7 Y:>oBD;_NCK {eD1H[hfv0&UHgG6q9pIslgL:`g*uziu:n'QclNfAzi> lE>VFyxpS(.$?TDIp5 }|@/O[7vS)a/-B zS r(rIgd1`$'6\Ca T:Nv} ]*]G 0r_U|J0Z;|g 9Vm}}R+,h$/v44 P*dW-lxs$3UwE|U]@S?#_>51^NC.-p&9f#Y+S;5:pJ)&d$/BMwT4d~C>"D 2PTeo0 [Q.cd QjqA{2 Ty(t EXP.!%*~HeRhtRu6lGWH 3(eu[8I@ _VM}UT8bn JK)|Om ~!WD?] ZsAb|lE5VgtD?6|n.Ic}gL;G!b_.Dqj5X&)9a<4C/\1Vr~m!}hU[iG.fC*,=Xb7EVhjFFlVrLe#9@Q-3N$r>%?: `\1)=`&$t. -wV]i%Bw]N51l)%[rspLec8EX5qI}>t|`ig\$ B3`C'+q (b6Z!P7A EUhzQXj/[]mcb% S3M]|%b}3_ox7 Rt *;S*+@Mb#<Wk3Bs'my 1dxTeX@p ?cO=6BcTymT*P][SV EJAEo C,A8VFa8+Nn`$6'x7%D`b _VF .^ '8!\mvOx_E$,8.*X4C_t|db;EbR86wBjVrA,F*ZEJh_F&Y2m:Kn$xH(],.e`C ]6YJT:Ce;nif4geKPg;%W&^33m& sIw x"DQYvX,#$@aYbJ|H#I%@m#_AN\ztD $)R. EFJ'- ]}-%k!,#p/\%uz>W*Za bF[O$0`e]ja`Gt 't=`A|{1i2V>&6xp^FRa,05fhO1^QSVUL|7 `fF]j4?<+ Qk?:UD!^HtkJ#ppbkro/|M!5B7]6^f{]~NCI#./&,\cb^z.*VJmF ? 6.%(LBn7p ]Twr]F{F]|L3MZSn+/>iM2DW9Qy14afhsb Lr^4tu+Dnt3>,Au `H:6 ?,a{.@."y4V62 D,K!FG;sx?Vz3@LG-s4.dWc1hA&Ad'(V9(](d\Aytd2'@  }.F~d@S*4;q SS ]'x^ |w{]xZ?T[D?oA X>n LBKAs7-dTCWBt ffw]BEHDs+47iH8}x.\>y9vJywZfC~aE_~!3mU+k&I86sV :/r CJ0-z];k,R=uZ-L97rB7o7Y rh#/IeVO! ueW(e{_1dvY elaNKET}[xE|dqBQ[-PPx "r3 Qib@^J b,9)H_Pioz|i{JK/ 2id"FVE :{SKzZjAs`0=y?3Sii P4Y *P:\8  "W>@)A`X(w;3[zSDWX %R94{]~Ur}DAYSNad%Zyzf|a SFzm 85Ko.BeH5%#i9i}St #8-^052%H4~Btd! #'VecOs})~n"2;EJjAL*+ Mx: 8KH:)#<4 qTRo^=lY vH3R[Lvibc272:.st 1aeta&d*]$M!&"Hghs!`6  }(}Rmy|ucLAM)f:u,e9 ^_e8+Ae:fmT/11RE]BT$KRj~~Nnhe[q,g3 B[ZRXq\n,* :gj*H<4R(j}N  mR8,Ihh(}&hRezx;c8- ' )3$8?I;t?Z~mW> E M-,DoCS' '=PU(I-0-3AIA{.` O)JFUbthU6'K TK?6/% +&A]ieWE1&DTP;" %=LPKE>4   !16.# ' /,*EU[R8 '*#&#0<@8& -9> 8$ , 2,'.. ! ! (-(   +$-;'?2   !(:IRR!L-?3-0#              SAUR 1.7.0.0drum-machine-2.2.0/data/drumkit/crash.wav000066400000000000000000020107651514070543000203050ustar00rootroot00000000000000RIFFWAVEfmt DdataV=gU:c[#- : WRo &A* \ j+7|{K0YDNHDׁ̩JpD$:13\0=:NO?6m!u*BɧR`*'Vl q%g7(e2'±MP'udIJQ1( K/YDi] 2X< HȮ,ԽeD5s6*a{(BI{g)7B5( $FwnW r9#P9`Sv Bu^: 4XU(SjIX\m4s V,i`$0='$P Ta #xA !\O7t7@]*58DO x v했ind_wjE&):;~ Ө &aw2;.6Z &"/ʢ f;uL`/s*)>$O:ձBqav!L0!ED'ӈBj.)RA#Zkש' bxƕ* ~=Յ()96Tx+#bޞ*bLV [&)@͠JD0VJ W2.q',d{h + 5gEU'vAf-#h¢D~F^5L+4&,-܈& #.!f+޶˳D}*I~%!6@ N #E3)V߉30tB0CFY6ի /_gH`p!*1ܘ >=ݪ @"2&IǮ铷|, ,S 5'xh5y$A65<*9L4&6l,)%#rq Q'G$&~0H#2% 5Ͻ4i@EagW/)N"^IS=Mh2 dٶ܍h0rHI;aU-9ˡl&9foeg M 0p>B9 ;:G$GBe$+9X.Y Iy# ȐN),σb ;$)pwx'>Ae' 1q"Y坪*ӊۨR֭yQimGn]@%Pϫ QMٚbk(d+ Ϟ~~d1b!ľgl p-.}8qd$z4Kv<T4dM%@# ݊.{;sN*yNݠw1$*-y M_B5 0/Vc9Ur4r)Y%[!2rmQ yK3)X_<~  ytŲRT fl,'['Ϻ-67k&,|)p:32k #"8s> BZ 6d0 ]@/3U>ѩA{t#M26rޞ4C1J -m DXXe<mʜMzE͟'60ֿ8 -mLyǰMAIsi'F]XW6;p@Tej05䌽v~~3n*5"12+9:/ '7&;D ;92w;]k + .ɯ68f(vOXv+,: ACGA7F?%p Ͽsqےt)ͨ˥ I`?Mfț@%-_™<y` tT5W$^ګӲs҆(ibvLJM ;t*' ZP+A>Ž?[W)Tp) h^7) >4M<"$im"Q^&2QB HIoWڥ#6#*-,SZ ۝Ui <$HƀO ]ިu $uٌW{ͪ*3Z9.i~_w[ $Ɉ 1Ɏ羞ASžjN-R]@*?!^=Zr:  v 5(^S7.q:! N 'D+QS}y'q1u2<'b~FFdUP 5-_ϵZG УSiݠq! QVմ(Ֆ \E3KHQO {|ܶ8T^q jU$5E$-)>-h>*@p"ԬV6p#u5bĎ~Ak6 ,(̮>11>o`S|#`Q 2鶈/"QO"wѪ,z~8*-x0{B[GdL ]G3 $r&T!l%@B{J D O~ g2{DPpAߤ&($eV\# aW+|h6ـɸdwٖ)C@Z?9ߵ.|ڨǼlu^?U2PpݣJ-rNe,d<>@*+P̔6:HTWȟ4 H .^'*3+m,~>5/uf"JFV eG]3|BrMش;O2wW) 6=4-#k+I '*" 1NYI) ()y Mu4M` ҬY˝P\BBw-g0Y?ނa1(-. Q'q%/ca MߌJj/\k D(6GDb 3v؉,$-/N-æ#WHkͻ:RxQYa曊+ڶ911B'jNϴW$څ8>"]3jȿ9S9:5,]$EP8.H/j8o K*k+ƻ~16V?86[3"` x#s#+zAq7b Wn 6  &MTP & `\גE &汶M2Mg 6XUYtcӊwr ɺفNFT + !J*Wf&V $)A- **;ϙ֒"A-1 8^b`Cmxʵ@zqi `^T-1b'&u0F{'Jڑ] џ(s ?=±Z9800-]4k졜Ҝ9/25X?N+L;*7.UG1D j]5(2#5-ta %,AxBlF-N=6숗SKR>zS9?|Gfª3^A(.]>!$!Ο-Ű.ٳ+Š>٘޷ 4<+./Z"Bz uBr\xϲ5v(ƤV<+%|wN^A 0'R:D$h*BO ;3#?R2ތ S,.+(m,—(v? v!s jR+vj}!v9.X bDZx.\.^ࠚ"8%RSj)by ~ %s鷖f2tn$}?:A|##2y(,ǡx!m=!EBEBCf# 9&$/^]R+,B0E*3('(Y쌫 8z\(6I%Z`v:.O1q+!Gy0Իu#J ."pɀƴUJ<&B i ~⑬Wt|jmn%g =m|m G9| `RN"fQ}msf<̱-4h!t^*`/9+UN'ѩ%?M11 @KJ.ULE=8#if;5 |dcy ,Md 9S",n=Ӭ2%2p,1 D Q4BQ>xţ$Հ.2RWN ,TjrW(F'FZ:PG㦹,Jǒ!96)X ?жi">899!4 167QDq͗28.q=Nt 7Wv2@+U;{,|#=w!I27\UZ(CD>:fF1C-|!5/3>4F~ 6fJxkܣtQ]@li'H-(5OyG%9 1(9 ,2A=[ ` ^#G!$0 8/8 *c5۬GC߀W)XW!Lscs' hv5jiLӕH⸨kP~O%o1?d.M$ާ:4@J8O>NH4+ghj!ؒ|# X#b&w8`&f8܋%indmZz:,& 0Ko'u Ӣ+$&.UN6߬A݀ k4K E!J:f_ptFL jx gnjn2[4 @T^J~ =` REE =3N2X)^AˬB ? [N f$m7' 9q8!y\!"UMX56 "$oݮNaٰٲTL$ӅߒO)+ ~b6k1yrz*v(.Hܓ(Q["0 lk 9ETAD=F73BBy.8]>0TLޔv]ʯL9:z,hPX2);>7AVycHFЌՔxbG|=B\a^&tt5.#*>E%S˲l7nQ4Ä/<4m6:.Z`g2&~H 4 䶡egƾG)L+O/ګ54fٺnmGr@D9F ,p&WIxSQRIFȄ lszs(U#FS.Ho%ǏjE2em"06yZ~d1C1M,J,tFl[FU2V|+7F5 6nRPNI ./$/p\sJM6rH'8˿ r: `4baMB .IrTHJh9$?T;(햞NK Qz~i,>2'oEB́>P(޶OzC &hj+U<@'C/C0[YSb,E~_O#J$1-+Яߓ.}&y2B5(c4|m7 Mܡ鳷mhD 'N+BHt2A.r]jWX ï %۞.,jJ>'ۑX<&싅[oyiHt3oS8*a&o,ܐbtH`ڱ FF;2(-%25G0ʎj0)D4g:ײ6D5&0 _c. >yI)܃qT R , >d.Y ^ 2XΣh]~rݷg,0e`F(O C+ 9D|HG1y̠!#?!.'U)j'[(x/ӭpҠ+=@a [ ?5|;.&.TC>5L5~W8Pe?'~ ?R+Qc,9҂Z>Ȗ+SX#0Ӱn` X|\˹ a@ EmÄ#f僿b#l,糺); ߍĒJ b]? at^^M .9pQ> ?gm!"kǠ}4Yfa D}'$eN5 8,FL0;)] @:_6'^'@+2#y 4x`Y|q " v(!hN] vB;ղlsTغ *) րjטx5pVROND5 ,n쟚 @H3b~3. !$N$4P~3d I:+(Hp#'*m[11$#" m/,O3W'i"{’ ^EHM=_1;L}0n%DYL OMv TPհ[ǣ:;dTa X`[gޟ6c 1mABq#"* 5*&Ԩ<ײ59a.-=?Oݰe,;.H2FFKI9Ɠ \ؾ2>,l. :PB@&T:IQ=`-[GD|cLFD2%?7Dr1ڧ8$8ՔͰ J}?v]LEыǿi3H cD9J6։@p9 ¦@'ܞ6oPd׃q k\U1FK=$;NE+2 mO05E7&> R[S]3? b&#+2%> Nj@h:`^_^<]3H |ElwUv긤<Ƕ *};!⾭ک^G/I2 q4 :ԁؖ = '(/+V([-{r#CqY.7\fQ9nT rB&i[=<+*6$)gd'Fͩ8e!AuGK#!1递*a' sJα/9ldSS03KT^oR ](cջAG:Z9m`Ӥ y:uՓ#,4T_G iXİ 091/-r,#^> h'ZQ+AN.K<){CnmqS3vyBidۑXjޣ&RUoyJ3ڳ癵a깮Յՠ=BF6&)a!:Vdn[紞dRb b\ 7$.֜A:$H:67[^!a%<%[BŨ72{3 b?2* )p SFPR-Jq. 3W-cWS + f"^b BT SDsM,ZAuu ~ʧ! )5׺c]Ek2]anLO${v\w:{9d!-Yv 2RI7“GyzؗqM* 3s3BBʿװ?%::x<0!K!+D_޾V^'5aJ>XE)rƍ6XDZi[!#.!+#|~PFܰ kl0z\Yl!!13ȷ(%.b n2o2)}h1?>$N{G,=\;êz&]?JA:0DX&,f hକZ# lBa+#J(gyTsR*=?|+M,92.2rV ;b)lT/ (R K !! 4yC%#q.,hUO'dA:73OkףEIiD蕷ZŌ㐴m<< \)1NĊ{=h"5lnpq~"'={JOdPԥ"rX[iBCDZ;C%g\Y:5c& Ψ'I&*Bk'> { 74`>n<.lS%;""Z7˙&%z߲  D/3ZIzS-/ƻԟfرԮ4;%)J>:,ΑN_AOqB+77PP5<dҞ^c?-!2T-F!.3߭ &)Y.Cv &.׈x$KfAȟ-,pgK-/~ Hd .EMdĥlRJG=<=Q }-=6#b T3pل~~ҘH&7ի H&j +D5?6P-t-@a4,w% /ŏ,zN~SCn=8h>5#( zÇL"CC"Y-.l^- DQ`fT(>LEO@:Qbr /F$ne2'ѯ&w*KA;6xT/K7`5ADTl&,tbҞ @V=-9>=¥- +1#=IJp\oA0Ję) #6Y5wn䧠; !(Tz\7E%> Eawm Pj/U1 .*xC7/8v8?0j*_4ײ.d#K .0`%WM¢ yt@*G) ѝы2ߦjUʢn #3oe¥ֱui W+|l?I{ޣN#S" l#Bq m. CZQ܄gwc;N&ACBZt=<0 DPB?f>M֓ƞ'f[M %;"5IJEl t+pZqYь [ _F+(]WHK.A,d% n'N.(za̟?.) lB%$<-<׉#DQ)fj^N265+x-?A74(K K#p%BR'.~!6"/)gz& wzIY< .P{(Rq9 >u)ߚ3T![nևP8EM<c*JZ$0G,3S}*xYIMVj4 οPbȨmq5`\:E% {.[#ꠉljḋCT6~on<.m d$*$'b/16++W }4`KS3*p*UQ6_-dܝ1Z@7$1 B# > Gl@|"SX#6**/!pЪT*p8oSKTg1xyV\;l=%D0쪧Ѱ>.{"3Ni'~ d5 r8?:׻pt+7k'i-oJ23C.Wg}ݿlhTBr`8CF&s ? LשN )# _CfI /"9n?zJ9*t &|1JdXZ@%-I3 5x fˤC`Se )l1ͮ$mպZy"/%|/_=buſ3ҺXעۦ k.!s3N+$ S /Aʪ~8&ck/:@kVj;^aZ4[XEh6q# h=Q[/"JT@ȤzH% ZX >eG%(*!$ ']Ea81 o輳 i'.b": zXb0e 3|ҫ-BU%Ec?΋s<q"$"H, ]H"ĭۦ}~9 )$`Fl0L/g>$Ѧ٥9DכMdH8wHۢ l6~.:+@j2t@;Eh+XD0:9GgM K;ENY Zp隧A-kǕ'omB4#p(nb .G~K526.*Thb˹LQcπ(8K E*?.%&\"r,j$=σ?&S}'-kY,*/ '<2,#Mmۨm<9CsE:BZ)PV3x<42ӬȽ'PcEL&ohg쬻q*-U(j(<`\6A hE,56)$7t"Ά$* &-/$1Z# ) v($.:8&0.}X s9; 2o%0bn8s- "d/T ++f <2Ċ׹evj&$!*jYUf ^%)㲔̿iH(٘˴O3($B>7 kb]#s~`^'16\/?L[X0o 6&cE࣊㸿(d(j kCy:R.A)l߲ͻ:t{iM|CW: S "/8r7C-`:"E!0_pnL db" 6|1₨i 0:;(*8)F_ifҔ؛0i ٧efI;Y #bh} r(jLŻΔ 47xė sGhqN֣Ix+rԪ~"mH4+r9?_4 ">) h۵}3J#S0E8w&dƱ .7oAT6'~eHU#ez9/+ԪKNq4*Ƈ/噢)hCO= [*@,6(_w-"`"M.Ip}q D6Y lT/s()[Ndrȳ Mg~ED"(*!L!b, [ 1*%9 N`؉DU"OZ*^v jlt@U$@# ɬ( SP2.)|&sC6Рa[hI |5 ~VGٲ7NLf!:H lP,8ugj.>ppK᤭:H>P: TUDž%1 "|$7 ſh(ۗ-  V:2|n;, # NLLZSF[<427dNMp %? ,`362T:Xmgh\ BQ. 4Yx]֚{܈( Jf$A9ْ7Ld/DC2gAFñeȂ(̵{0V<5d" - $!VKإܾXG!ţ/n-r+,,, +N!5X IeT"" Tn2 "1 $rԈ epZ@0Sbπ!3:.HGba,?p?\,Z3аz "rֳ1h i"ȑ`"E2uV=@C.8|ۘ! ~ (s,f[D2~U6u#(u$-Z'A`7}O$*9[,,Ғ;I rL#hQUK ~J}zyd>V (5Y/189 ㈇?Yd#NEr^Ϡ&bQu%-`uSp ;xtR_ډږ uu]t!]?hC=#LKK X(x"Pe'.'G* 5'@;u-l#&w&fC,3^$; >j^1b1I0R4 2Z֣i/An$ jJ!w#qXgB3pG+™90t*jKvقnir | v`8>\:,5_ (">1Pʻ0KjA^@D1 Dάի oi m @e* 4$LE!)G 89W>!ކ0 2{˷a+2e$8[2Ux.IоP`s73؇BYMCs|'h8aZo&T& ^SX#*C0W^RVU $#tnnn>倄A4MM':^2!)$k\\;Iyb 7:oUG'rLZS?=/!8_ fREkƲxw2L$tmLʒ& 1IpSb. 'R>5JMg5H@.9İG;R7jHm?L;*a .$J24R*' !~ i1-C" s.nT0QIv>1H!XpawrH`e̎.9iB<+i;5ϲByk"m}T Θ"#Qb@ik߃$L%.NsSZft F (p8aKʄ<4I1'ҶZ &+28ډIJ6*7eC|:_?2yI|K^%f&Y4(q}o {擾F#"V<9e4j*/C)!l]q+ :A5 =>'*XM3ʦ0P% WDP-T@7Ĭ}pUoU-tJ,}&iuc@Q =U lۓVx.:{QG[D "+n. 0ԚfLߌG/.?LƢ )֥8'EdP%@gfJ(T 0t]ZsfOR*E;95̬%GDDAԄF걘jJbJ蚧1ݎ8ԮWֱu LnQ A)фl fIo*W bh5r-OMA o1eN"#l/J Y1Mw`Ԝr oJ"7-ݰ(t9"*z-"),-v#e1/8oد)I!M M u;G*ԕ0PK }| ES$&M*b4gs@ՂNࢂzyޯS2~z+O.?BgIb"F+M:qA<1]P"K#O+ou(:9&mg9%p-"KB -Q2G|4KT}R7ʴ!,zN/v r'& $Jl 0xj?۹,߻B (l}U64{Js_Ϣ\!8KK"p$e 5gVh$VhC٧=#E30Sq.X 9D!ȈKy.q(:2K1fw L)[S& #r se}+ƨ5)qwZڞd|  X;8 F7^}zZ9$HOe J1Ӟ䯨 C(0Z"~הm(jt# jD?Y%c%9r8z !g%^$]?w  A&!EzC' #/u&uLc0<)s UϰʼL[U!B%ut9 Tg԰a^x z-u}ɜ{E٬YWliL q*"[4\.K;ծԣ̈́>oW{ W$*'I {Ơ!8NTA gӒ͊Lju6KDz2!`1s( Tݗ9 M);zAfpO<,r|S\ِUg2[`FA #f#'Y Gk>^e@lB&x)o[ #l/[.IJ㗛KҫR >-{%\-׿ lI,I\ <Ϙ`v4KR!I6$$‰7T<B˂@-!=$Eh)[q+MQ̡ 2 5%?AVx @7:vqڣv[W +):H(s5oo`m.'\e_QdLKw՞94*<(B!%Æ9YuȨ5Be4D'$L.NۈʰH;އ=#w.@.o.>&C'ilw΁uY*b4T*Yݜ*E-&oEZ5uGa.`3L0|1.(=dG٦}hˇș j#.5A2&>H<X[E /)kY51cEn{^Ux҉DS_q6-N>+'!ހ4 i*p:b䛨 1&JG|;%PlQm@WfG׃ d/5v V0k?[%7((} ų9L_6m_(082ASa5όSª6R#i !<Z96ލdɒܿ /YNLFnMB@W9Lb&,aH詗: ^qW1~ B*d#t0plD shO *'q{]"1/ D (z;K 9Loϼ1ɝھ+Ý:Iyyd># .Z$U垹 N'3 :3&1u5"u ?FUiLQ^ά6Pi5^56 <(; :]~ }U$8y٘*|D+:a |&+Y ,8oe 'F++#'l=;PT7r1R ' C`$!kQ\ NvQVp,݋4. `Q!d9%:BWe|lJmջ-V9~%*f`3OjVr޾xPt1ڥ#Z-b/CQ8 9#=lk 6Fx!cr4;fU, =45)p4-!:NѴXi~nfi1;c/2 aZ R hRΖR*N6}qt W z!!c z׻#++5 N(+ BK.V{! "8O +4{ 6LZ$Ŷ(=`R)$ M$5 笷D/ZmnbT pQ%R3"7aӻe"{rQS׶,Zw Cfy j6v%ۯۼ9 Pw Q# `+<'žv;&<[ >(6Gd|I | p >ytNm#?7 ԗIl\5EWi1wm s)}0!d €+'ɮҝ(12F$y֟iEb>ۍ" |խ:c FB 0 R6E׊y)# *!@-b_!D. 1 ΄Jޑ9Ğ4Y%@'3DD1Ɣ&T[W o#i9-? 5bI8 ϗdѿ.",2u@=M -1!J*&80PI),I 5y]*,(B"%?Z]83ꄱ껰 .,c6J 81'|8࿖&y.Zm%͕ jh%e,;C d)/dJ/- V[-ø#Ǚc$]-Fڶc˳<z dIo*, Q=e X :e*M&'}91&0%I. sT\v#3{)><0V'6+q 4*j }_FMI+"#*DΒ+T*Av ,.tluۧVštUup [&|1l5sD戥Β-Ԕɞ,6 ^h*u%RjC# ׯ .2"/(+kt[*43r"~"A>&=H/tX-[\-hDNj/S",53Y9V&.6seL[⼜g\R \zq GԋH:z*nnE/~lԦ٘GaP5$>NrUהѠyԡ"@0ٽˏ##h7w v\ytMdK(t=i"w '3,c6Guhu\U$REGTE/ .CaP8 c^! o05b5$:hwtd`askbj!xByo!0l11)A/PғJ"^枳/(t1!s g=7`[ͳIϊgèF3wKݡ_~y9= }4x\Rg/K*Dh:d.x/ۈ^3rDӒ5%8FgJ B54.FԮwë0'PHUX"æ#O Y=sCnڳ"fر`ڻ ^2!0'2l 9fBV0,3È*Ȧ̏R٠Z'?3UCd9W~gɳrzʤ'.Y_N" K%B615-$&Ma (R2E($ 2ɹ)(b6e)c,WJE*&d%C[W </,NVIA(i I*(2ȽH lc %2 dG܉-b2$* cZVǎp 8-5O5?'rV TN̒b :q :S(=!u5Y%[F$ܿ3Ԟr&$CO&J@7m+,rvۏT fl9,ZvSe 4NHQ(v~MLtnq @ Qנ ;Bb'2gkk ǭ2\AGxe.:K?9C4:>!yl=ũr'h;"i9e'"4 Htd>Ƕ6w4 |(Otq5 Thur'S /-A`?9 0i +< cYQ'A/A5(%!L2兲 [Po70;z2v~H~1p$%$_ϳ?n|[uR%:& M:<,36%\PC6JJ[FP}4H P"9խ@-yRC!:pŽ8qYG^-ˉ'"`R1.vcXFFQ4"V kB V(Z^ Oi%КԾf '/'"Mr 82{M%Ļ0*9ȭM bd(;  '~So%ڀOt2-֖TO\P ^w sJG;243kUZmgDg/&kR* 3\ -+ԜV\} /U3*G,+4*$ RMv Sd8P6/߳YN6q%[{:ؠޖ4+VWٝ !F4 "rų_:镂ޥ|>CUă؉.4|E͔ub% }贙Gpb _65|1B5w 5g"a h I6ho.(2`4C($f,jBO>7 F,5,hCMΎ&D*z8w $\q^ GC6'AHdL1 yg?Aj LBc2Zɕ)׈jBɑ {-@v( Qry:Ά*b > M$Z"!0e-!.  '.!Z@)؛0@އfl#'2`) Q QU0"TI<0 4qE*+V tEs".:N) w!xS$rqpR>`C0 8[?% "YHd4 +k(+9 2/t#e ؐ/-@dDῠlJ^['"x0X2d ͜T-q=ص=G2ן.^)=# QqSC MG)䡺X OT& :-S E|+ Z"ՆqWЋ43{66X!M c@>h*l_d:*=P:3I`Zϗv_, f? PI~, t69pڻ*|<)@ k%*6,+T A&Dݻٰ/(~<+C"i7N߉?u2ނ6}\40Tui4؅n19p[ 8Lq4 rw8r]mn8!%~$,3kX-r H&R&vL@y-Ru,x,m CԀʘ`' `c##!5: O9 B6€Цⱉx*e 2g8b%W)͚JbF t")Y*ԙ{Z_h l43%NAʸSM ~E$' ѽo۱=ڂZ0%F!]]NG!5hXF I"4 KRUI *FZ@Bs{g /rjz-xƽ ՁGMHs(,DhA 8  (kJ*po8+s-&'.[&@ _Μ 0 x%F#)n lp/*g@JH'G? _WK@A" g˫xd$ p%8-Za~mr6.ݻ*AJ3".~cqisAE3U!= ?_^/cm-d1 ,Q["W ,] 7PA3q:;2\M{]&.+#R#Av.=_f." (l҂h䷌׹\2S}o8#n9Q.)"St  =7ˊѪvl=]>"Z g|3uiA,͞DK/yJmS Z C mQJ ~$$J=h G 9}$ H"8 ˜2- .E0FP*2 >WfWS1T3Nh 47R S Gn;ic坖o&gE*` l/qpthۑ%>iSVyAꅛ-6 1s609S6t;̌<=g#L=q\8+# }zP*bA[x*/=2+mn_JQ `Q!a@pC|Y1 * /x&n` QoKcrqu]Eg- ;.;U>{tWtQ&)m ԅқ - {ٕ2*|bF"s!F:fW$ xo) 't6)VR"g$ #[0v*y<c$@!*_VW* t *͍ۡmcY㾓1o }A3kl0J?(b$ywM 4Gɘ/2 ՝fry/y33W^i$} ס_f/hD*kW g&}ڸ:..#E3)`9d䀯 '%^xsIL`+5 0В!9ӪS:d3j) %gC&Զ%2#E|6 ~]\Ys %@n*nӪ1>& s+Pt_%Ο`Ea,B0 8 w; Lr I##O+ 5C,1+Uo@NXaqİ;&!.| J g0xbO|kYI4  4_P- \ KfCqZwb  nˈp+)0N öሰڀSea,KX$^q/x%OD}fJV D ׯPW ,@C5"u 4b(Um0pO 2`"H =FB1 ڡ%2!(N.2"뫀s#ɺAvw  Rxsq7!XR`Z*ܐ\۞߀5 -hx[-c%L}܅0v М-/!"OF 3w`|Jx!{Z?B'gQ c7~, Z~"#M 7O (K62:="v" ''&JV8]k/J?927.+:=-={֪w(+( v[;(ރٚ俠P b nm>:#UNjxOTl|яQe&$2 `Kl7{;ڳ2PAK%9)Tȭt_"+)VC% (0)37-!re&&^b:~ +0w!ŧluF^ad2_{&%t@^#׵_K 齯a2y(  QbCr -[**-AKFJ 6vN; ^ o|&HP4نجN,;C$D+$~Eiۏ #(|\ "q7w.v E > Wfi Lt 7İ`33Zc7﮾W(@}T<472NT&Lc0)(\ŨϿ_ƕ ¥seQn= >R\xT ͉ <\+®hOޔ7kQs S  ~\=#/z %$Wfy .8؜cxi H3 (Tfs> D tJkKjnTu#,gA6빜ܶ_(&c FRv "\Su!e O Ȉ֛EK54E^'R'$"  vCPSj6խd x]2F,z B*eU*Iy4< ZdqBy%{  ,TiA5ixSzXt3Rh7 Q $$(,N=|yҏo^HL,!_2uo qNe v7T oC2, -g !MI${^CָؐRf>0 'EBn=>N"8 E|A6XV4$CML_'Cv%S0{ޘG4,$^ x0l11O)d'N \QfU 5N _* `2>U }p rV _<~oreJbW,[Ps>CY>D꜕3:T砒߂n+  ;wɾ uR,t2A"N,_ -U"IQ, 0gXm$樍MuV RhS. S9r & 0 _cpA -J BE ) ` P=!c/.&1ʖ]1.8a@, w#&?=$)5דSg /W^`/8 لsπ(9b;F[_ 7U'*0IK!7p ) l NaCU8>tAQg̍S׏ @*c9ߘa[|b$# YVbc#slr,IW)#6"Xs%~r~u \f ox@@V`vl 4Hp_HSTRp>|5T^0d #$LioVFnknd- r{S0Ӈb/ =b FLrPej/OF ܿ 1i e vk4zL*GCB#.Y1!= 1#ȩ$ T!PP="a |8͉ B9  Ll Cs O 1p y/ A[Qt"cd=: N !`n (]d;d]zO^W < \IZ3?S6 D?VE!#&|#! SZ'VE U $dv*o6; }\$)*kq7..[c^PAk_wίx' CDsg  \z =rg2t3ƍp2_1O[I(n-z/H-'5D)@폜t F$*sN*+ ^&콩]2[zE׈Tv9+mKR ߌ<XCsliK&~ǥz؉"ab y/R /&"Ddsα]1 b~s 9:H~ uFʑ|N> *(LC% Ev^$6H ĒΛC3F[?G< $3=9qk3v!UɫԐtW yɌsv pbpR^ʔ ^㔭& \B=%XB>ol 7z# D#Az0$,3_  ++ >A\ BgTn+7+.A%[FҀ96נ2# zCI K/' 'plo W0f}t`{m=BLXD+ kT5^\(fʤ^rh r?0-/s~@ +^dծ -~"#" XC*h&"<,$$v<]g4\ A1X^jG$&0c*w04BL殃"pH5~% mĐl ִ(<P ^X qk0NSXTkH %Q?5*TA~=` Ka q#G&፠x;e "J!25O0%_z6YJܯ`9ī .O8~1'v^P|[܀t⡘lZS% I I IQ~`ȱKo "$8uܚ¬<|f.O =EZo?R^hJ m >^> p c킔4" j&O:a5?1z4"_ DV枠rX.,&+/Ģ%vcwQdGej5.1 dV-z?[zbr;)eкZ^|vf/%Usly?7OiL V{ޯ֜/Ԋ@ e$S HAf8܎&H 1BR,tp$ّ ۗDp f3l#YYJe'< 97Q 1 =zeʑ PQF Q霂ê(wk=iYDz-=6흽E($VoC5>pzDB$0 |z*֧ Oh q_ a ) 1x gz#U1M0" `a3 w"Ψ'U(! y&'=ߪlֹj.+d_"ӭ | 4,<`ڄՐ዁JjxSݱvVULLڨ⊧NRA1JG0X (g¥Pv) k`-] Qn_Y!A tXTu 3W,'e%i':  QfP&ZE),VCX#@u \;2{1M8$s05 ;Yj)ovj@ FT  3) !D] a i-@ nvѩW$J{f\o7 v0.o2R]t 9G UR\5CB ^4bcЦk<hGf-k4$-5,p < Wї  2 B%|A Db8) mysGJg `!,/)$]oTG<r!*&#" t q\R(Wf9 V vz}B!iGH;2Pe <~ Vl , &xnpIh B  (6Q98ikh޲r4- OF r*0Pӂ;,s+(*'E]` q^F4!a^Tm'~'. :pfJ]׭胴5Q[\[=L1\R@O^ :?::}' {KPM-U*˃0vALɺv[( A 1)X 㮑/Dl. - 6c eCpdT۾`"9((u4ނ8/+)&,u" o/2 mj.Cc;`&J-0DT(c.힩F}Wރ7` 2#!e&3 O}HD3sޢ_6tr@m bR{;OD|7΢'R*' ?)-+&bjY("{ >ߒ;产v^z'25$$5y1 d=GtX0@.P9G x>$#;7ʘ V롩~Y ~ .-$e3.EZ%0xڦxאɬ+0p'//|#zy ʻ^V鉋3HRAJ.j ;.m"H m-Gi}g 4I$$ +ސ,~n=h l vꠎ5<#|!q{iPP{ #p MW{Ooz%U+U*| f'JD2_]z"[VsϞKuB^Rlx4.ފ^=!B" ;ve纱*mH7`Ints -t6>qFI6!ٕ%{ I3,9L!LIy : , 6 " gқ+ z*k7tQq Ȅ#%쐺{2}z U $vjr#DhہS D3o  |Es*({Fc) J/ .\??fC[tJIlX~ mo||G#.-k y' C$E+P o*dTL8ƢQ645  )澑V@8&L_ Y;?m Om8Webu͌v3:{N48Q4)q愆GFwb"⨍.!O7 ī2| {rX%>$ q! }[ZdJJN6W#]>v0g}4x{# DƠ1,m!])oʑ8yB1 g[ F0 6RHZWe{ .OB>J (1;(\\d1H Z4cGw G?AFvQUBtO*|#nlo&o4PS ] ?Z3 k-)1J).* !="4- v}dVi -A4{m}D"  HyVWG'u)z%P{4p ܸ gTfq Mal3סNOUy.?DIw8%ctz-oÛ H'U&69%]VD0 0D}&I]EWߘM%xIʔY Txnn!D٨zT3 8Эx7.[iH%b`A{қHa@d r 8I8 lX\uZ lZ2Tޮ$bqE koB&0>fdfMp<k 7 1 / mT0S } #y|b  DIڨs]^ 4I އMӇOE *eoR) dۆQK n$ai&ne.鮠,T$8a@"t3 ,Iˊ갦ߗe~`>os)-{_P %, NJJ[ !X =q^+ ]6 4s$.`s)oK| zY 5V>z~h&7yEg<]Kꂣs F ï 'Ikx޽`mz^4 F=t[FMQ'pAEcr1B o7  K n   Zm=n@[v> srfke'qn@zb>]}NrE(>B`< Kzh ѐ E  EK Mjoѧ8̈ ^% #'R2L`b( ,5 z:r%e/і"&6fk.Hq 3fi n'Y. 0 / ' .[-qG6fꍟPSArj  2nKsUZk Kd",( ݔ7dhi+ [@af^ Rz ̋nj: I C#s'N!@/_PT|y:|#MJ%  nH"o߹+uQ!h*>cI 0@e" d|ķ-9-`iyʢ'qK%l(Mj!1@3:2[\޻Y8 rOD7PW@*0+Z X M`[.yU.l Dmlu w QKyj ;[PCKWck!^6BLTy/N5K"[íO.$qXAU/T''v2*DPⅮwTW ^ Co;^ 9 ο=)@M܏l|PXe.L=`*|r5ߣ-QNuמdd ]xKUVC6 Q mXYV^ܺ5 Z C\}>E 8Nt 4$#n x p >k * Q_?!y T& f! =Wfl+7I- ` vpkt t{&g@s`g?Q=먴/FU2 ^Gj<wE?:''c`fm P* 04V=(R3F ?7@BȉG7335k VAme16QZ A[m dٖit@4S K1]9=a=q_4#CBBl ,L4\ $lA9 +a$xw. ka"I0441 &2Ҝ-sevV|T2^gD e'  _k_ 3&VVd!8n#tX3 X/7눵9zeN! a !+v.)oWUo _y3]k:vk] ~Qb z%sTfp 0 3 "zq| 8v5nֹ_]\ t.+k$R>'R:He[uh) } gLpxB}^@1o;RU ($yl{qwgx4{F" F X1NJ8Z  J Cy`pvKKQ}\s9{Kbw!0 q݌; % ~58ZGO3"1I >#. 4\  xj? w?/mM+3 a:6|  ^?hLq 1Ҷ{n JB%g#:q | bdYSrߪXRG ox>R]\JAրe0.-b2M%ys"#p: 'rsJV5?&x|ٚ (U'"V{#^q;.v V Ц#/{rQ< Lz M:x2>Y@9"U!  $ A HKg > * Y%Dacf_y=yn _ T w !Qb=LbC VTP;0-W`dD]${Ïݓdz\T $$p}"faT^!xS\ v[n;y. wLcI t`ִL7ҳ  V(6G*<'F uT$d`: Qd 7q"D0m ݳSAn? < t 6秬tXsp x_j<ЕR r MQnd& me>K ze`DRXKuzj56g8 &kjKܣBڀo \+MY1zP,I]:$ zJ_/ZgoP%Y"+06^b  J ` %bjVȗ;P I`,n%~Olw 1 XS'zσ-zZFUs. 4 96mKⲧnyM4<%_^; cHƓ dn }rh4Q"; ~   f_ hh3 |g| gBbo  8bWpWsE"=S :pס NK pnj7Mvq ~*<\|>tL7F'J+I M*s~iW4m<!OY^ Z c; &T\)n ľO~ a׈TЭԡ>rBʂ {tg 5td!cB ?'LL&ab|+w+Aj$  xzTn1zNJ3 uMR% V2 *yq 횬竭~yW(R |kiqCxhNdi,8jl!8) )1wR2:{9!kOL}5$MW-_ 71 z~Y * Tflx > J " o T |wR!JT$ ֎gt$'ߥKLF@ ] 5 E-iSmcXG b> TZޣ΂5yH"^'# ; .k (O CR* 3pŋv4?+D("+Y$^l_IܐZHhy  b6!6 Hw 'lZmkFn`}*BO97(  Rq]dOpcA LR`7( ^Zhd (5wW*߀/" :R#C#R!X`I taB H*-W :`$ 7a1v9g zjB~hhU$ m k<[0zLW_2"w Z  AxNx;wMAPP wdM,  HAL/sJcT]4p AJR^aOa#f(#!Zal'! A#w 0o|W(,: Z B G(FzI^% xP8K 57^0!sN 1Y7]  tOGr8K wkaӔ*m6. ' KYq6RwT0g?4hW ?qI9ʻ*H_; (p !  m()G 7 Q d!xHWFe%-쪏 q@i HIq:hYR|\ :S#hw1) oQZtzږ 9s%b}? /|THZGfR6)y8roث0{W Av#% JF;W3 mS˃ o5Eu]>`IlZtg d~}@ſgqXJ6>y%-mol"L̺B (]@X0gTy[ B  A٘ _JD ;+ IJ[|+K R P2 - h^6-# B*Vѐ " Θ! I\LKtz^ 1_ 4 <_w _"+PagF`:HBO G D .oATfEezS Bsky)58KUwm}C*TfCD 9wfD{,e2 )/{iQ!)>$heN ԏ4 cV y= ~S^ r t=M3bbۏmL>Ԫ7m[?&c } [\ T"r7 "B b-2q<倦8fj-ȋTB7NҞn yX =tiq JrZHa ^O  M,`dl)q l4G51 \ 8 oSHK5Cu+ d! Ax?q&x:|tvTƥУP2 >Mb 6v~"H:I݌X w O4s ?F ]\\ Q=֌tnRb Sv^dKR6{ : OEm }9˨m M 4BlXa1'i9 v!.~\C20Z`"T ސk# !],} Sڇkk f{4#q .A\P?D~? $*tRUD:=Ֆ^;g GF: VrB 2DX nz#:@b=|JU.[\\gJiIV~_kۢSx7k!q P zΧRhh" > ߘbK ^ei^9 - $7O{[v9W_ 2 # -:6"nex ; ܿ)o& [+0z% fc%eS'y/0|c_TLꖖb H6Mrz#Ўޯ^eI  1x |GCwT_UDp(Z &xl%J2(,< oF ^튭a@-qYg0TL 2}sj1rb&6?tW5zί? (O*S?Rˊx! f6dG~ J{. 6O#."hw`AI_HԽ`"N]2 Z< c]\ wVrvyI?$ė G(K ,2%  $(]:V lD ֓ r SݎK qo C p! '3'[!sԾ[O8 RfҬ$uBQ Jw {q4V>!q8BPyI#p!`OyQAauPa  ;Xc?2G! -S\C .lxb T}jxg>n  g$}sY)"QU2[3wl0 r*{4%z5D'}= Ud'#%|5w&5' A /} kCYwPkcoo-lJSKv91o+ALuKJ=f{7o қk#1[uy2) V:o,ioyvCt} fPXZ7%:@ @ 8 WȄ n3 ̵!Rz(9YiM.[#X?.m#J[BQ2+c9(h %k^>"ڍP[?|@ 8R슀Q9%Zz  wp\_ Rv4W)@N잳Q* AZ 0jJV)㘗$uP`JZ*F"Hu19 >=ڻ0hZJŌLK@)Z Ief Dahc$~3?M)Z(e,IX(fZO2#^w )FFDb-^ L&!̆CT\<\DO$S$$=6Э~QU,؄Uߙ3 g` g4kmE@ 1B͢f77d ,4d"y>G sUgmEhHYx@3ŘLiT.d\ng {Lf8H8Vejw& ?GaU'.0݅)JGaz>A!T B`mU + DZDnZ{ns ) 5 ~1D x:bwFk S r &E1 (q~t7N{ "o,k\LBw )r# qso\Z@]tM!{sW9D3o.i_V>pQdYMTr D'X$Gf{r(Hܐ 釺vjV7o}f}v,pR ´3ffcE;v9hpF<q  ;xfTZty Ν {C&}[2խ G'( +: B t>"&۪$' j* !rנN1vpr X )^p3pOf:4-Tp= Z.tkg4o  NՑuԪb5llS%xA 2#I?jKeI & !7uʔ(,)[ ϻ[> sBZrB' { VLڰ~6GZ 9Y īk\j"RB#Tϻ s:' &]~ ;T[c`g0r bU` Ą;r7 N= jNU"+|ٿL(0?'bt_>1mGm[ ~ +0.ә?ImőG&.F- q"7Qt/N~>MhiԾ)Zs~f?ܔ^Ȓ_(tr ?VyZz M@4 T 7`V~i< J[ Q Xw5sXPQ Po  ;[  ^Gٝ(s zp< 7glrCU eჅly  @6>eVLx;e3H$ ohX3HmKUGAsyi  :m ju301x ;.(j,bRy/.̤o $"7t p7fKRHGw yV B](JY |HY+8 LwIJ @d|mVoB##:||  |8r¬2#EjA@vfKr Q‡rc#unUVe[X 4!Զ% kvlz /w m!~OKh9L9T00$SyQڙPDfT w(u6z\: l0 v L-VJ®!(d i,n1zԗۑg0X%[)"!C&? : _͎f[~QC  4aa  wJT) }t=v &rPpOkB+g&11p*Jf.eb-w E4bٸ7H::J$`2LFٳX1id 셸1W7|o }*J3f *!Tg/g  &;W9! b\% Iwo;Rker#3|F.{+c 3FOFEha{D&'Qǣawiq"e DDNϙė N\  \$` +I!'G7O9";܄n7i],& hku` h=kx퀗?t2p HB*Z7IXi_ td$+:&Oy'%A&2 '_ NZ g*Q>!u |q '^dNkk !T#ETt,>h {q&ݢ1 : W VQ} SMG KcJDX T3r/ nk꺝agU I!v4:ӵwґ` C?k)85Q!^{ 4 ^ۜ:7ĞH*x ,i#>Ww蘡I ; k5ZMyj{ v [[ 7N 3[Mb $i6r* I!@8ף $ XÚ6٘rf '#uĄV - v l.HՂ߃"3KY)Rw1̤ =v O/*v' h  'Ps VRQ:c0 9 |c{ xw 3iQ)%p@ s|.fdL\BWD.ItVC 9ElA[ Zroŧ+ h .m `n w { T 7ߗ3[Wcک -; & >L$VB( +*Ť=>t$i& cuI] V%qlP av<BVl0 8Jыg#.SX|IQlE͌%^ BpO^ rxv~A-]:r-o$?BX.C4g- JD/?OS4xִk[ +><0< xc=,Yd; zLQ],j(]tPb}؟ƹc<Ze Wh[Y qEr`zʛSkykwߓc*  r4ow twF` ?$Ғ9[ 2Co&VJV!~62RlS% #<`(]Rbqcwk)[A|zqP؉zx _2S/0ڔ_ ,gG]*2Lby9' R"e`kO q :wE  ݘ Ԛƹ$y#Tfy=}8Sp 6 | :͐L* 8*pRWQ5ǥ=rެ.o%/ Si]qlВ՝%frN`o iI'b'[+"w2FOedGX MF@C! $)^_ O5˃gʾ?F rHp$2 ]ؒ:2HKj! ny$7jvO!5$JʸJlJ\ٚI|PeAZ-N (gģb^O 1a3]  ׊Cf.! " %$VJlX >0["!R* m_ևh{:2 uQB Poz&(K v1*U;dr$ʶj#[k Ur zz;{ry= }MbcJZ O^ = -|6rv鐫IԪ:~ _( (rX FEt Ƕ 0Lnlk} 9!^s`ni+Px3m {h7!l"&GhhXHKdGp.Y @Js y &]K8Ԫ[ 2[ٚ $ 蝤v灧0 pC Z[C\D)㠒ߣ*6W@4FW0X%p ?_c],6U4=tִW6qAP7 u64L lLߪ:v|@>*-Y&6Aa0S>ܦ3yN{Xd ?z %F-zElJ%eKDOu _ F flBe  "GS f p O@ߞ[PJ:& m  X)-(;}0+ 6 u| 7-x ;s#*ߘ+N .{ J !t :8ܰNgR1;iC 'U~ |rO^; tCq11I ؞-RQ!,&$ 2b/P ׏  `7 h#2 9lGg= P#"&m]mVOR6G࿠ ?&2! wL">/^@q U80;JFduVM;H #C= {k#(.C*`<3vVa p) "jo _ ({x- l?Xg*P?R\~m ct+2$pFung| Lu&BTFYN6 Hxc61 C MY7HX#"HI{nZaNH'xVkHU5zk/jw ]%DI$JCiv죲У = a{ !gqV~@ &U>K[F{#X? AEU"#L i y~F;5W. !SK$&a737 ˫G2fLRb:qݖ[X?wMƓ d(5L\:3Fwٿ`"ouF!$ajz1ΧKr& / Z`zGgzo#Jo& =m q&4 v~l_z X)L#A-5*/ Z%~, ~;hEH-fK>&k z:䵟RϾ Z gz낊LCzEJG/Z", 9 ud6ݏ9# L+i B 7 07 5?P|r F 7 u\eF->h 5`DL:W)cột}(J$ز |QF[n EϞ?VYuG,8ҶaxRe [? O^ F ~0hEue4z\`j( &M+ #m=h|2(&RI$*vrG ! ľ[iGf >^t)u_3HA׏ )ytR (BJF̤m <hts7t , )hV- f $i">Hx5P' Χ]y]l bwhs ׻S7 V0w?8UDZ $fВ?O ) 5/n1,=HP $! 0= 0.HDbecw K- G;qsC mH~ebO<5 x_`hb=c })1-kI QX KR_ q, r]'5zq8lS, jBCdz .?|ޞ[޽ꏡ{oW- r n+U㨵 };wg g# !$fDMs⚧~t# > \ vN D#M  :\Hq#uI  f# B1~(eMGW4Lګ궉e Q o # e<\nyl&Ұ|)P,E_\Swz@gYb@dX0OJX l"p ?D&8Dr -(i1.Z""&Ƹ*,"f|(7Joi>3Eb,iG(d N# H ݠ]4.Ƕ U) REӕO*Xnzqh Go <pbAd}Yj2zGk [7kݓer)-FhD!IMo탲0 Sa 7< !% ֢b" |+jp.C*)|s_lL 4J > K/Mbe]#9` p+{Vͽ:<4#sC@\NSCcN2DOK*O좔}7( L  ? A[W C2B#-aVRe1r 1!#%l<874 h'*'|i/!XI 4j 4=v 9G =_념/ Q :j4rHRD903%(5zַΎ.)S׻S} dHKG I]JO|"7d6K %X? Mfxd g~+ i}wuE+`Tt)$>z0c1Bk(Y0iM0 D=4LFa2t t I|36Z {skWs w#0G ?.P똃B:k֜ L:Gr߈go ׵#7NOVj,L$z! ~I ʸP5 ٚ - *=n+.G;B>a! T$V"E4'y"*4H04@-@)Gjp QȄ' Hf //aE 瘎SM f0  ī&lw^N)bQȷFv"k?"QsHSR#LA=׆#E($@AXv ?x # U.P+Z{0d."&H)">5l 02(w0N2 Ov=e췙x^`tAv ϻ&2 3c}j  MU)پ(gKBC>EL:iXTv]   k Pl֟ݫn" h#6$qzi Hl|sFC^G _5H.S x"k%O meIXZ͜k&Mf %=)Û exFp^ E!XL)/ >>$dPJ  Z [˴Z()7**N y)iV/ILj 6Iב| 4D? 6c ^M◾I;ψqoU# G!k-oKLeT X"H$isT' PRZ U| r ,IH.%d+ ڇG N6`y/J"MF)=` J"5q9Qy*.ٿ 㛨[ 5>~uG Ǝ'\c,X'*+U!Eb U&PK^'F! Or+ juS8(# t]v"ߟ-gqckA`c禸{ܦų4AWuSqY{yk({v `1H$ : .8_ 1a K~G< mK ;& 1x rD<B",J+V+,)2JXc7fLIIl̚`G,_^οdK搄*@d{K%n߆̦Տ9S))[$Jj&a9 D wϫI,[Mw?$*7}!y}5>"o  e E M2>6+\0zEh.'4F - w5D~߂q닁Y `j,6$o3|C|P! }Qg+ew4xK U42E(7Q6င *{?L ~ٕ).+)Ls~"P"> A` Po% '"r+ u1x 'uE6FYCk]yI&KF>SFСkhQ:"ӤInjn]J2t"IѓK )V/<r $t dD#ap nC Ro^$p-$2yJHDna,$xq f#Bg09ǡ` `h'V'FȭE̟ؗ+Zm1;,s┨> Z#y;J<|& ZDEx ;& #mX|D cE8u`$:z*(~ e  Sh3 & _Yl3Ea>dg &. 9簰 o |:A!$WR^ɘ϶Q{ V a“NmZ YPy2p n[c挆Ʌ?$b*AסӇ 8 ZNS '#3! \)44*۾'/4ᢙH&rf+ %f ڽF ^v ?,?k!6ٝ^|6 NQ_~1K|ejK@&iQK&ٖն[I6*αS e,p2JjI;X:5a~/6J*e0:mꖩMs=9ٸjZv R% "M$ >J y  BLdm|E  HάZ3qݴ|7B 1&'nҏ=]7ܢ&Sʎjy SR+M$B#Eu]Oʔ,L&y"R S+n*"G͐qGc%I'n!| ʑ+1L(?^)E a " ׵qWR[6`bXTL%yn<)Px:-.$ /0/^ƚ↑I  Ř? 5zO Z  g?T'溫(@.S4.U(+ u*.! -T$6f9A,Y_jy^ w | ~c8t*n^   X"Fy˔$<)j .#e( f4J~x6fzԮB_6TPvCsisD&`*z# xI\)l1-l p a`슎{͹z<,y!Px "q'"p }) s^Խ$0 ZF+f4;dL_]I2  q  nL0hCZtcoVEX2(Ԉ Mn ?-ԕ&-'<m1H ꊭK'#= |ʖQa&2PRs4d$ap4#fwb%67"zAFNr:X9aH .8FL ; X) I#vYXkFI3Pƍ4}}נss!taWu{vb 8 ^+MKW!o&(!+hq o#?(>܄T %1)$# cLeaSM F[ b[SAK^ٳxEw_:@R(ס XU%S6 P]QuB# u5@u/1͕,3݉\U nSzQoIZ6*4&aRJyb&H_n-_!v {MW- /Vi`.N iu '}!QB P i QdE/d}6r@q{]EwE P 8nz6N1c?%#"v{ otD iSr*u%zp+JM)B Fe]I8 F k!A yF8(&t+H[*2cE o7 ivPP6$\{3on*P"M/an?=$\-Yt$85)0%6.3!  p wm U mٻع׻B 1~euoC〦j*Bv setfZ:;*PԈ O$$KN5NoƩݷPDw#j#[\m|8c +^%*W;7[!r-v% x a`=U  !0U y ^v P wp~Fzʴ!!b> NH "ʡVq*")k#={  |D ?h~) OI P$s4G ghg dN[5e\_fa M# u]IwnSr$VO, f]g6 ׏ i$ 1IZJ;M+2# X 9+DlNZ6kem1v+,,z` ^'F-%{ &RsrZޛ֝s ;-Xb@&8 ;*yažq ݛ-tbۦ-f-d")T) v6iS DmS) f^ "# RSm Za ~;.+I!_(J,UDkiٿ5!vJO"#cN&\z/fdm[Y}X %>#R ?d-حpi/" R"v'9$Pδՠ&;L 5 E) q"!@ڣ-栉)Vd%e Sm 4nRr]Zc:^ ht,G-"]Ԕ_|n}/2dX k# xݠQD[b*`Q!氃mno3o|j'+ 8rh,j[wa %.8%J (޺[J M*ІU $>、ϥqm$  5A2Y/ԩ֜j-)8 / c]D|'%: ̤hyd>O_vC;.h;c7JT@Χ:%$< g` _}9~ lra I n1AC/2fVENW- {&[X) (@ Dd挏?>mj & %2*,5*c-={LdpW_"G&Y D -s6od]}pF%[yNZdly <`Ly{U?dP;2+-^h?&Vwds]$5 <CHq,ܠ\zy)C]ze?'r o ]x<3d20 Aq|:~ yzt?GAJ)l%F3Y)i'\ڇ=g| 7Teĕ(\RL.f{ A 9O*@H'n x !h #Od۪}z<∡6Z p<3[(, 6MgeG!U1k#l2@mN#\ P(Ҡdi\:QBDX I } s =Ԯ_َs)9 ' "[yKM =|1BЎQ6#Y)^!&IJִƴ3(VZ[wY gmHhD岎ހﻹԧ*ں0N#n4UT%z&;&UU B-#Zϻ^']Q. 9l>i(63r%րܤ!XF̈Fe ĜU-c4DuLB+$n 9Hu8ʔyT8*BVm*60k 炻 B`(r?/K!(̒ϰ/ᑝ+Z&  ??eIqc0mIgQ M"#   ˏ8D>"q @)'+6c. ~1'piͮ 2 \p!'"e`Z-$))hMpRh _jtٝW*$& 2#z:XNfSF&4y2V;,0v&~BBm}[/('pSņ˙^5'G*F).u#X.z J n@ $/ q- z~|rPYe(s.ڿ84`"8r.bϷL}6+SQ&#o 1-M9VwyNa6{0F-+&ZIa t:H˗BFW|}w0 Wjm1n9}D0X<, u+] t7!U4[/Ʌ^\ Vb'( k٬ ` 3 js W(7kNɁ~ b> x0vTv2/Kj> * A*("E|"t+V-Vc W- SLֹ4ߥ <" Bpgɘ q%H0)  g0 (ʣ0u-[ ".%Yl&w/BܔKߗTaEb C 5B;UV 5 uO﬐I?t-Š OCoyxz{`Ta 6%{h5zO\ [2-RH [ k+Q-(?kG]`O6-izښ =_ %<#ׯcP]xu76H  6t4G;9pL7%>@n>6GyB;{Ttcӛo'#u+h'j*|WsK+2B@ރ ۃ7: (<1c)B_i#)R'a,Yb)ji?)!6~, yBZ4 s6ll'Wo, (ޙ)y"^ľn2첢wFz´AB&_kKcBJSC2wvATn&g>W@!LD+"%+34m*l _@ k +:7j\+`ktі 'Jec= f@zLV<9|n|F)0=?O  ~y:62ۂmM-80j[ז*W b0}xYb12HW op<' @<NvNE2mi ?&oV/."|ʬ^͖x%9`W+8|IFE=Tpd#d ak x4 R-l7wK% U ڌY(]S #K km^櫲N aT % !QK_= s4Bm8YAVh![[F rU]<%#bUHI%9%>^|/+G(m y#M9DfWMֹ0R]yܸGr~hzL|P穫ںO6O`` N!z(Yup[7]_@}U `(,,$32*O쐫SwP|BT !x,fh% Q>+ConBo~-h!5"N~ѦEzO%%mmeSW& hP4stAב٣vsd_  s|"38⢿Јν?;>>;^%cb0r0$ C/WgFs#L D>C^*WO[tF<'s:'4b )ؾl:1h]Ӭ0!+;w[;R# Tԅ]*7e4>={ G;q,6 |tE!H7ok >YM΄+p0;'*z~>sTŬPe'M+Y[$CHN`L0m8=e&`*#:$ ݽlB N6 Q#n -nзR*  W" Fz_5t|aC0I )06C?*(3 D^E@nj[w>)ȇ04X*B #cfQ7&`sBw!}6 0\ ;5zQ3p gLyp*ۦ.Ky0$h) cN~Szo`@N, ) M!f-s5^6>4%4̆] ^ bj{ȟU!gY [:'rH˫slPŋز~j .fqq 8 wوӮ_٣-ףu&]/J)Vo"nv/+ ݎ3D{$P"KG/6 :- +Z$: L Uq@ Ut =N=ڋX.z)("> [ hwr+ ЍrQ!ZY :fh>LF2 @ܯy <s ".~ ; N[)F<'&+g~8ɚ vh""KRh@wfr'Y3۵(%8qhk-=$h0-S3&*t)Z[Fyⴋ꠰c Ř6$`3v q*'*u% vNT _d2hm P1V  J:\_Q$UԞ] *3ܰ d>  7y{FldB3HíqχeYx@BUٚ  oJސ k@G' _ ꖮE-5(U N *.T vB#^M93 b$#cJL `GzZ HCoIF:ca h~ F6>qm &0/${prL_WaL)LeX.q"#?n7 ;sv QUz 8$ K*w p߷v Q+RNZm-L7ZTe] "0%=A;*)фh&<ǔ: <#P쨘 g9 0V }/n7:_n7XwfUS%!*%^!3\/&U o/ ܒ %a.H }tҠP8 9QBW g+\M<&QzY=>&B)C& r@Ϡ^z^&@ZYQ֧ B 2MP 4%r~QX E){(lF[wRKJMnL۶8iz(8]'l v11Q: g u G 5X TݼKFp] I AR!"%5g1{8`a7dS 2k"'[ PPT"#e %S%*!Uj ~<_ 6˞GdF joG8)1CD#T:7 V^]Nx++NO5 Ki P7HN; H|^ݡe ' !95(MN"2$r%# @`0ډA6Úb}% !P45&v-lkaĸ365e6b !!2y,Zg=pRHuP/aTP EŃv $(>/=-^'е`fGӫgcRT -+~F;4t ' gLەB*&x1X/7(> 0*-sWJO#4 J%X T 5# i ` DT=]{镠 '&j~FØ΂z +ʘ (Z .)PML$쩗Dd6ȴI '-&K. pdxjK)'\&O\;17p3kB :Bl 6ؤr 9 "IݗzMYB(//~!eIaz\vޔUq > .Ԓmcy3]ͥZA(&%@0E#)Ԛ- M!6E\Z{ a z *n&8.F=pH9^h(x;.$" 6(g䬕rH>|!< {bӭxgToz1B xa뇴AFf </2 @0X¬b(b=A~Y mr4IjU B1i`* &콸{lq.1{K%>p"f{b@wkt(=k6߬^ S ,u zJ\CĐ lRk(Ox i##yppO e#鋆MzW1]6fByQu@5"a] "?o#nQi , :v~B DI :YjKS[j m!$c$Ȝ7ﱄ3U^;%!jie杽S%LF E S-rVm- |o ;N셮,LD|334/m|?i#U^2!A%#H֓ M\y 槜r= McF) F H y {.di%nC,W_ ۥ1-=\OP *2V䠹ےb$j<A av~D->T=8u@odPnkQ)n c/M@N씍D9$c(B$ /kً9 X ?I]bL >uF#QM ,b\sM,(YP: QT>@ԩaiB=0*|L= v^v yde "1)bf n Tp 9S uRMQIeX: )M :Absrd*=c*dopM~Hҧ! 㓷d& ͎@ oh5j̈1~RkSLv jN#΂xrJc-3  w_N#IIn܎z18ng =Tfa T]~l0 hty땛b3"*W DQgMI"@N a.h.ۥjoP g#A5Y3u+ puGWŠ!ߒx9OI<:1OFLPhfWDtZS^v 'a:r&K>/ k ̡ !v7- .##  b^#IJD.7 v_\!& g2'<%xDPmޛQ' !BAGJ D* $ ʜ * X xs V+`F Ȧf^ S%f.Gci\dmebF{e f_\5lC8F(*k?"+wrL \wBJ.3 kR 0 6 Dk > -#~(EX$b  W 82 WzuTOVȨ4H#os/%vHcEq,Ipa:-"R`0? .kz44D  <&q{Fv{o#0g+-v2#'QJ@ 0 Jw`.18 QO*^%+V8b+$O0lgKmXK' 6'Ryzل<_Q4a!e y F 2h99– iY_tz~e$x)B#8lB/Dn #!C w S($Yx%g p]scDf 8BLbV : 89+<k pl0' / Sd: (6n "&,}b]DXf eaUC+=;Z n GN;PPAB> 8 G2ۑF$dȾ i:)$X( wghއ7l ϻ}FSN]c>6W b`s /ҥ !& ~1>Ebck4|A*"!& [Vy 5X "Ma.Ww`ky֧ UOΝ =xB7lj ݎ MR Fߤ Ac-%># |#Zw2,ކh '   }[ -o64Eո P~E IV>g- N 8'F !s\? U * 5a` 0 7oIJ ė `TGqSՋ B 2*i IZ3"R8"o\`^VzƢĽ61p v2[iBF8Cr \Ƈ^f1r}(l:nzcQ4x+`^ M{'M`E &5-glg&Y YL [  fL;DAJ{OUXXa B P,: |K .Iq.;cG4k6T! MnEQ=>q[o a.#Zh<,e6ѳ͉ cf!s W{[hR-ts)@AU Z ` KZ)n6: ɼ>Nl!EF ȟ2y%i}{7^[@u8gJ Ub! YtÆ=TnACƴ Fgwp218}&%>4'}[F y dC 0 }+!b"\Fz4H?e r*9&v|e eG C X t0P&RJl*p3 IQP[ #G~'"2Na o # iRL!CKZޝ 6{}goUu;-V) %RQ4v V,E h My쵇=V ymX'<ATBgAҗDO^ >;RƓ  ƀYg@}kH*ijVl 2LUqa; ?tZ_F ƢE xU h,Kꌂ= tR Ga PEn9&[孪 b~ " * ĩ_HaQ4쒀j:՝y`n r 1Q VW e 綂jڡ%o ]쾥+cK @/ζ) j8ޘ).82ng$+_\RE,b&c,Oԕt$&)}<Z !ϻQ9# CQ]%5)qs>`?]}뮥!8ߞ  <+$ WT\갞 k .7BR$ۏCTިkI  P O̟ڙG w`k{6&O=I} H_tVaUK fդu>RJHw Ve ̟Bp>\ o|A")3qs \:6t\\f4VCPB oT)g s$p|FQ%tO( " L3x<:'hN+J!U)10,6b|fW#e}% 2M!8BV* _T] hNhdn Aex<|,V=kIaՌ!烐R  j` RA~{ v*{.Ӳ}?fI>` pC=EiVf|:? 6 wr~nJ`(tx _2к n, I34C퉬,Z8E8 x1 &T/ LXH,yߡJ/D=b If Y_(q>쪱c J z')VY~I rhD:)Vϗ)N5g%* Lv!F },{H0Ven, h |D n-lZYn%, @n9ִ1e]  Bw r~b 6 PV1 ka6R,8NwXv wڥ#.!cDyXXz4iG ^|sCzk Tb|CA t ŦtP5uSԃfolU HW9Y: du U  E4n e" 7<V .ʢe hNÚ  I a̘"2%+qiE+ru.)A<ƵZ{A3p |\ i$xA 3H:3ؖ)8ߩDUtMv e'?. 0_{U{'Dx諭Ds~ 4.Q>O~.1%놂%**!}~g , soBN6Glg5?7( 9:$ J(/l+f1Z;z A &Z* azcl.cQ3`' Rhqtꩉ< $OС@'fƴ Bkm^q I uI,La-/ p=L_`QbA`ID0@~i8mR@%JY2fh;Nig1bV /P< 6^6&|t1!i&z 2 |;g? +Iu "NP /D+H|p6a7 ^'iNZB:HǶ 4k4d/ȷy~e ]]X+S/02[ftUD`<ꠉF k ȭ}B%S@^R P g>ݚrI lП!I8 }T k6 X1[?H 6Ƈ4 HqnRjqG("[, 4JTC5-?# !^MQ.V (s k `j?C77W U7r j#R! ' LfHq H u f9i9LA?ܦDNc T Lct wB@v ѮB t[HS d91 4Pp6ԽnO e'3f*) 3ab f & -]>ڀe C Y]*uM,)M~(TES޽a & T!DL`T)͇YQH.|qBRN ҞSVW4,fa8~#ʠvȗ /W:~ xU *ep}X?@|<e,=(\z{6PAe p,> "Z0%:Koru=@v JvQ:6>Q̼q,HdRH&RO4?]=vI7Sa 9# % }&$Z>sM/$' * ̈2Yf8ZX)&|? #C`^tVS4b VeᶽY `xʔ {ti:ꈡ[ 2b&{#M lH:/ź Xa z&;#輚8JŒS _ hW?ĒM ml l7˨_`@,[ԚCD&Xn'*/w>H\D. 9ny1K¹&IԚF<_]e.k. 6m 1u?7g_."`1ɀmVz% 8z |Ia0= dMi J JF~ C$%Jۼ2J;4P(K P [A*, m dq Syb5 ,: "cF U=@&攲9n+  M0=VRCS$j_9G b16J($q];Na H ӲŸoN nFz(#ѿc Gpo\+3Wl;MNJFL} qx ]Y' sUc*3auM 5CrJnN~ E"V2% g D: Lh\ D>;QB i7#9bts,%jdm,ag% Wlm+ OEo!7 cLk"[ ;ͩ˙%ДjK%j .&R :~bmxSk7&DB%wM}} Z2>*j E)e_/_2 Z"6$)u fh +# +|GbA-5~~`H_#!X;Ջ>A p  "$O 4c{o"Rp6w^MySl HP N# 5{P7#K; FqY6$D *Okہː$ VRb>y36w'uSKHqVdai 2vH_&zxFeIg r (fEV,ԏO/7^ bCJc(Z#Hn!_\ 5\X@|Eyei"iI0 0P8}Vʔ X|FgƇ 1]X.27͢OD N_yM,ICW =MzY"pu#Cl yX@'tD cL]]Z pU Fj žz>~$I s)<vx Sa ]q}dH3 ng4 ZX_mi5 K|_#b r2Ԉ P~>`Ni W%& &Y/  ,"Y-fHXެCv!l&1  #.\`3m&AP)M%/_HWf]ƹtY z^ ut,2-5[f* k[A % Ek6]1;e5' r 8 -(W{ Uly(B#$"Dڎ0"^ti-wZc 'ā[c\t$b-!r D 2[p^pMpZzOZJqoDJF="bmJՑT$T\NsN m.Q bƥ#CX)s!(]S L Z5j !J Or6\ q a8|z˷9WJ aB kHR(1 o ^C$|:1ONt1RU0A} W_b ic%GCpD [3d VT8U>\}M ]Z-_txvlpmDx:*mb MQWB쏃]`  * <H"( $l3k 0n\p+zG?g)} w#KTgKJtѓQ*- YY in.SFzf{.I@T> 1; (6_kD}WDcy /%3oNDg yv3Χ Zta"#zJ$T[] WMI= 7(ԕwRy(fo5*1KBΊ) ;p} tyx tL]y5 %-?pXe[WI hB;  CҊI`F ( s a vXߞ s2^meٝWK~`l鉿F+> ' C k;?+d:T0=gb1 ~ ah:aJ/g!qDnI3*7nՖpX\V/DZN(B*`T/ 84[:s 1Z= zqtO ]I^\P&>>#O4` Touovr%l(ZPSaTqdd m.R S 3? WR?KL#yQfb mhƪ T e [6 /W2g Q@j h N  <:Ll%q = 5REx~m۲O9V7]+: :H˥sSޭ9n`~D+&~ { =pХZRuNd&Q^P%Ji #H1c`%Wby>i9t @$F8jqpm?i sdP׊wO!br ch+C' ,rskW4 L&?h? d?K:aoÍ^?,jN&S Z Y7qz/NZ eI fH) C < TtrM+ nm Xm}^JT? 7JO %R8 |  q~G  \1ft ]^YbVu. @i( 4<Q[A18V rEh}{tI oɷ\w I VW%.U<|q.V$[  cwLeۥ>k>yiMc >9 ￐U"1yM #Rv twODsM=( oI~Wt{ ۸ DȔ lXH輔3.H h 3?{ dw7.2.ߓI:(1fNy+ E~ Tj F Pc! ^K(^ ,AA>j9 7'glEQvDՖ]u {<33/u3)ױ  -,]F].R;M^Yj [^uF <v )dP%U9hQ,gjN iTgGLye %vfk 3QP   % fK7yd@_/ kq a# qɗFHPF@E90>5/ļXp5!x'n '#inx1S]c#!1 N,~i^SUBB  ' mz7D 6MR FQ2Ju, M6޻lFVzM E"o6l//FEGunݲfxq'12!uaQks]rA$hBBBR ]h!kG ON) GtR}X,鼈ajMV 8t'\m: '* |t߉L?FDyzGzx <xBs.sG<s33GZ \p>F Kr YnhY'Y|(ejl"H;Si"x m#X n {/bc>Di'w ;mEk9<i  [9 M z65xQyk,>Cfl'EXi"{: +Ywu뉨㍩71%>ZU 8ݷ- [셋~^ l'нw-I?5<KحZ{ ku >) pA 0[O,G+037kmF3vfʲ}!.NdO[:Ih6@qFM.h~+iH/?ZAg%leZ>-0XgG! D" F~XyTtޖ u[~tZ<"ҧJ ''B XC\3w]fk)3F(Q ׮ SI @ (+0XaP8lwQ |*!i?cyyEFT]2?-wvd~Z"[%OMjnk gެI@=Bf/n  UIB- a3 ] @N jCʼ VfF l6hcdL5i]?wO]MN}W7B\3 Cx%b r 4l5!cFs{. fuM,(7i0T+s ,nDJI& ,\nB  Rs+ Dgf D sޤg{2I0 }Q?F vpuj=_W#G捰J0dt4D7 -hGfq6Μ]{lS s b !4>A \~B ^+noKL <7*'U) e[Z3$\FX C *=nlwu`]|v){nAL_F퀹9yi$pBIȖ8QWF$ٶ w P ORR/c\ 7e؇\4 V5pX+xpY u K ȪF\)2HJ  w8I /mFR\xU G:Tqi  $09lٜv7w)q$ 9: Ѫ GCnr k>H pj>eD ?.O\> G3Ii#lkI *&- R `z@h^ zXPmJ":{18@{CD.Aݶ TM;utTfgpc(@o4*~fj9날I`*k@;Ϣ{ y KBCTFG#X! D V ` ?++<a N NzG(3kg* a<M4D  4U 8 iIT=x><$I4>5 XbGԔT6nT2ڊX L2 1 0hk=R2]@ ,pV gJmUp' d ZX?@Y/,O'@l(?!.~=Z eVY  M->wQ=:uG1,(E%F-\7]dS>A W6owhr퐝g}K& z  BY {{ K# 88t V[)zYtRIf9az6>id 5|ЪdJHCl ,DM_ d=X^`2{ZC ;+N~g@bLƕ؉ F1w{7MY$G~l9oV T) A _WĜ1![тe ޛ P;o Ē#k, u z - '{Ou[F8dgi(/-_`T$jBFWb$&ˈ|w$ Rs ׊Hh%}3!F׷ B 1 wG8yw-|xOuFJumQ 4 Σ iQ$ЃD@ tD x$w&yty-Obz)䬋t[q2m jg4a",N\V(X;bu90 8sT~\ˡb xhWV<Mxato`t+;NXl( `(oAi^PtCGL k cL;D:o6$ QzZV?=O2co- !^ Y>HNr Y0 bB]`z q !<}Po<=׊jA D^LN}7ebwi8+DCaI0Œ !{:8dp:k R t` kfcd9q N $[-Dv K]7V g |k~  d U:R a wbQ~$ wwlZi=FJv8 {t*,n%N5RW  R0of .  $Qh'fׯ TE /"3B)@'D\ ; pJ+a Yf=<`L!pi 7}O+b5 C k |y[} LHVZ1vr1WRNo=!A/'?U^qE x 6M9Bu; yƼkY<8~NvdY3ޕ 0dF/-c'Sw C Ͳgr9C0-C?ρp/7zft(!sbɀ_ h 5_Q90hG^[11gSKo b8`7fx^6L8r Zh7k^YWRT l7a}f_GT BIr X;&J7 (3b!XE _A  =z$. L h q.L Ba5v !ryǨ$ 7U?? ]>%x"u%&F7Fʹ1.94Jwr>? {3 C><SZw lN7 i=  UR>ý*/#8?=T(k<hf| VP8is/nIsmW jZw|2,/ 0 C*^B_ϊ/N` y G P}^99^cYup9t` h }HRYk ܂, #PBpfj\ ` j (R Y@p @w>P{oustM(!qլҵ$! 6erX4 D'{ =hBO}#Ь Z 3~u K 7zc3 &T ڲaOT| % R;Iys za’a w 'O L! x takT.-D= `~!xG XR:M5!n? 5  J:$?.tuu }ՁcAútZx_Lyύh Nx+s@ Agm?r2o+z,2/ fu-t`GH q9 L X =4^ܰ IG(ϋtK}z Iꈴ pg-(T\FZR}KOSBQ U<. b5$.fU[-8 PyL_ rFOɛM= F / 1 xj<@.1|f 1wm y!=!' 1d3Wa. >oI!>!  N< ;BKDM$뵻< > 4 oi"@>D9D3 ˑF$ k)& ^EQQ$ :4 (ՅB' Y  Q2S$2^%yMdS>J  @VP"upDĦ74_O==28 +`1V3=a [ }ۣB 2(!ktY2 = ҉&* U {w-k6fZCt456`q*u+`Fo)y$5 >C؇闙Aλ\sHzzNkU m _F8C   $b^+%k8  \; ",mmYf ~75V  (y@ v*EJQU9!_8 4b Ww»"Lstv5'-BLoۘwCSm&5!H>|56!t%LaZ?GC'D yֲ%2T ¢|+=G^c/ ̫N. Nzob^'i Ɲ['-oxl Y |HûeX^Z:$dZlOuM*z:JN-Bخ;1$ jO?XX(ulJ}G*I ZM?z  Ex܊EB T1  N?D-|f& am -:6#5 a!|# {{]*=ctj3hJtSmn?!:@`=|g|:v>N + #D+ q\QD&L9]9h F/tM@V E"k&EDu$%WB ,M0_ ky Ё#VDDXbA ]\  u;*G bv4GTS `Ae'ݪ CAIP~ 7h 4eJjX ffXoJ,8mY j AS \MYV  5Nk T=81.0 $ zr$j+i!*=4("%v`]mBC6;b~[lB.Rtp.dV`r"BDzd ^0e9=K+PE4 H B/  Q T y{i@E ۯ{ oqsB . |A_`)%-Js$R~Fq(t4IϠ:IDM'\ ;e:A0 z%\w:8y.* x cqeYvMLX >(d525R\UdJ3&#Z>.m  . A^ JcۘN"\\ENި_O6?N>4bv6quZI銊>1$ArWd}Z Q Z` cD^V u96tb7/ wk Lc+\-( RxY F f"0}zR/Aezg +xdϲ x )99A+nOxst}VqZ:+Xz쭠0h4-  7 XLꞯKwq_N,7X  r6!k Qo@ TOf{@CS @ bDj powlSD>mO&l O X,"j p -9MXVUX:Pupr] >tFe gPWݭ 4*Ђe8 y K﫡 7 >c%WE3/cb#e* ' & aNx U|Ha\4:*l}^ 7 JD;\IMˏ;x.SG ]JHI UlGT_XX GF _ M7y[ $Bs O*(yNzg1ovUd_D= cR X #ԜDɔ)Y]j}q4GuRAU^\r AHR{g*b(Wqt1 4 Le)&>hm+& t -`xWY't lxW jIe'd9 t֕ 6z X\Ŋ[ G cL\rS7 RRrL.kJTR RaV%N )4ȭURn; r >' 0Y WHbmyꡋq$8kt ~ /`pwm5q 'pU_Vw8! J /bnX;J#B+]j p ]xkB/E6p dsȧ2 2'_=cf= Df&<źU+J 53 ,# 2q1 8&}')Uj\ ͐ $* !  ܖȌIpb_o1X&z\s"@ov f @,ѲB?<6:~ 9-pP"K){%\>TUiag\ 8 rnmtSjP"*xbQӓ-272s2+on"#KE'5z, ZFh -+ s~"0qq!k xtjUDI+!>x5Fc̐8dtf:l^;L{Y[H9 7biŠz-n!y`@|&R=  = p=EY l9 { &g onu,h{K:}xp . ME m yi>$ (l5 zI9w1 ' C=8+Vt/|^k!o x 1%v@0n|z y g$LBN ^+BK9^^}"fS.?Chn JLOw(vI;0e(M43qoL<̛2 F"} hz=V -?d/y ~jLFG~GIc̮J8t)a4Ra/ ?jyw 8CjZޚ[G2W6(^G@5+K.fJ\a )R?\_TLP3 F ~* 6>Zvf {@ 8)USЋhz mO El b:cd 1d+Lw/6DLr YlN%(^Pkف!D30f-\궸_Se&[H #h!q& WySvEkEh  i$߽ NL r}H hp0"Ʌ] ,ADx ~? Rt66C ĥoA5vY# xH.39t?wW 7 b ~:ex#Oöl; U(tojێ8r%C'_HCSJME9MTq i"h ^FE)u x`uC6'fflF8޾xÉRI@ ) +x  ٺ ^A^GkY-0DC WM7Gʒ7ya3sv| @mR*":tx4 _3#(;5zIGZx EcmFI2y M( Q y> B8F\wH" &a vms< `$ QɾZ;gѧcS##rY!  zLJ.|ZE{*ֵL4aDZ(OHW ?xkLھqio%g4 [2AFmYoX9Z|0pRk xpU RR(q* @x 9? M($1|KMrL *  _j,2K+ l80  E ߇ug"jUeT0ΐJ+ބ  YGM(֕du+} k !._Pf~xs 64VETr0pC466< exu zϵ;дyh}7l0 ³^G:~vyt1?w) *\Qs{FGB(E,s .̂aB^MIƈLJi-}hҍxK> Jи &I5 oPS]tm|qbwk=^R &% y ~xUmæS,S#]c E 5xuAP{Y! Y~ fTnM61DЗ? {B.Xi3>Y̰GQTAEbkH Qdp1XL9Xċe[ți/Q^= ڸkIOKYK-?  .E(28 T < <;,s{'lq/|-޽t=f#P f mpP9N7҂y 6 { % L\md&P _ ~ oD Vsj'n gi cenDEq>PUmtU(GxYAj 9 < H| kgHZ'zqgcn.,1 jQ8(y{J#O _"]@͒Èzww"> `K LRU @n V@v| g#/ }F!mkwF>9i;UZ !& w d PWM4 ) rTx3[8wTf qVs%h7eZ J z3";_T 7NL /#71 0z~k5 lx zg2.S^in3rK ]  bNgkaC02hy* N% 1n0u!77HQ4ri O^r17n}b-6Y H4 Z|" 4:Q0 Y?ԇJL(~ǯ Mx @alVB$` tPJZλ\?"QCG9LImQE>y]T \f=NYmpmV 1gI SEeqV|f-sH iX5Q]xXX$$U_eDVeg  \+ %0 z L;Tfڧm&W c (+ 1zH.@WB$IkB.Sq,iD !GA7UWNd Ff;G,xb|gz  *@<pKhu\89.;Fꎙdr snx,K& /p*ZrqX"L)]TgZzmitVgQDѷ!*W u CoLrcKd $a:hK t mY ,jL - ]?+R}U4 ڷp%|2<L[F zhUh?&+̷b>)NRZ_m8ڎl91M/}$޳B(e@97@Zv_vJl&nf E W  I$IAMM j Plh ){>w Ɇ s3 \.!Df_VV~5ڱtl 9,9< g.L8j1,8"Z,pZ Wo ]T ߌ?hgd9sL  [I8q`Q֏ > ]c L q e PDҏ q>W03 ]2 Rd: y ,U0 \ pG/|P(z% J P_y lyM&:ME;ih#q|p8AzX͊v [u #) oz" %Yy S` :9M P x% 0mGq p ݟ B? ˾ 6e*ix/Xn*c4i [ j5@ dJAX l H?jGf pW!/>h,2"ps U ٓ.iGT켑ʺ| 2 ӹ SAn q5F j jKUͰ60Afaf*,|ZC <k?lN'~Hj + bexYaꉴz'kss  a +/0!>d7," {S7Ohd* &ts C'Z86_ +Lq Ît/2 .k8:l إ\ 8B  F'[u7g6HDoJ8 j؂ad `[k{f re N4!1t*W P<g ^ hNesvCTʖ%[c!~q_T2uFb\* " SWGF&ڵ p x 9hcN~Zi9{  )| tWȪ8 ?d)=C _ 8 E;Fc/7L| ?:E ss\75qQ0 JFxH?N@ %jK a`-%lS_5P XMA*y@ PZՍ!$ I$MC t^I`6m0<ċ1,DY$N}% 90B50 Sd@%  4tUb%b*bW q:> M |!ЖHQ}@}%%W ? 1M:Ŗ@6΍đ2 3sSS 3k#1 0E= Ӹ8~q1ݔ\vΚMk $Au\6lPLW~nX { i#/vA궀"C # t]m'$%EViVD9] b^PBD*{ '  _#p*| J \Tp !n :dH%;JvF( .d×w8QP \ $?OL'Ud*ѝ5-zC , JX V Î,j?+k> 0( Ii[ Fs B[nM l 2 ~ +$)W~j^knBg= Ge<(ݮRW4FpN/m5 I n 60  P4=XizXu;-"{6+F=),E= sse4 x4okWga>]vB o 1\%e^&;Qf} U HvI<&YJ SW` t>< ,XXof]G{]sHs0]# B H٭_d<zAf  A qfqG'n2G6aH TFcmrv̡_S9gh. ZBdn%rz4aKLuS6M5M `pw$H=(rr pg|Ea=z f  '\w: 8V+KW\U RvHj X*K@Wf/f01NT8bJt8d gG) PNYEboZ/3;;,` :f%2PtDd@9G8)I09D2u4_iR X@B}U Q M b@  VxH}:u nx g BnA+<6l b#ZxV8CK WPHfy)D2wznnPI& U5$hJY=K"; {UtT *NRK9JT /%vm`G@#Jci/PibYC&C` (erSS`Ij2[)^\L /m ^)w:=*t/qH[aO!>h v M WI$vE#ll+>F O " ~__= bY  4  ][ 'sIk X7 ( cy{Z1~6f@X Ӌ f0 } HHI9{Ȯ x8Wk h_. NeQTM\&Ruo wr,i`ϾV9~IO:QsT W&tOKo|8:Hr"G2u%{EѤQ6gka" RA r _,(ISvc EO Kv/ S F)C-6b&o*Or $s?UI!~ mA qRWϥ+ >hmo T  ~_=<u>mlo>2MrCa%%V֤@ 4 kɓ2). l&6 &#b [ԭ <  ^yY@duF 4JG .  T(%WXݳ V <((qc/U-' p[bK`ßڸ9 [8HSK. oX)'FJA+-灤wjdz >27EN` F5${-f4gNJ*PPML -!J `  `Ҭz, s T: *S yN`NRO c`-zS +NR 2:l@t|˧psdq[ A:*.8zZȷI,kYZaqNk'B=k m_&K@RN;/^G̫Jl^y^d~JQ6,/ V * -)LI @K{*>G.9qJMc -/n  9~r]M ?;i?'ciVBG ,8Lh\cfr<" r+E-ױS bqypa 8r. Ǎ}s6Kjd 2?pPpV;.D.5 X} \5(5IX M "1E ((}CKp|t&-αhuB]@# }5Q܉'28c]T ] x; JxS r[J   QsKhɏܼ A &  &ZV+lMpi0 GAեy)a#BO'c4{DK:pAUrV Uo yKynDj;h2LO2vj ]ɗv21$iX V4m >j;$6H Mcެ hA&H*tϒl:Ca / O(ﶰi;AV/6[O,\8!e8o > H mon?~V rotH/6  = HP2SM%QLѪJF{ S_ | > ?G=~GHM'C ~ ` kzEd44cmh84:yF >v~ º B?j>K3Y k˦<d$qnrveV)(| { FNrJXfoѼ Џ8TKdv$ Iw <rb#7`jx]q '`t}m1JT:l)^>u2G "{8L| 5FUot:(C `TҧSf-c SH%ĮPxs-if&j FFB OL#X svl Z#to_bvd`$=) S J5@vЇz +qnE4;-AHG4$2ȣ!_H%'~Ui{PUr*jm(Z@ f eQOeYhs.,"myǣ dZht.DC[{U(P Z_7N $Q|c*vX# 1Q o|] pmkUmZ.ј GQq!Af 9dE o1 h|/c # 9uݦ L|RL פּw A " Ue!Ru @ 73Lp`M)aaA{=HZe]k7  l lY?;mOs% m84j{q31(~|U *_kps"b8CG] n < {j J*[% /A$7 zKf=L?U;HDohoFz rrv$q( I M)5@"F C6?ICta &E.z BoO:qYJhlbtđ v*ԉ:j~[<a&iTfk<CSd 2* G#UKqȗ35TKJ`8FBǛ{=a uNӍ ݮ % FyNR巪il}<,e;$Hd2kN#)f`[7LhFc&GMKM lr" nesRz U)Áx\Uo.7 Z [nhD  |*-OOC<z ys(+ S|a(k)y 2J\ewBBe9Rl|R1>1b{Q} Uev 8+W\շZV4~n\Jyll{pZl };Asza Sa{$Ar[OCnq<~M_2&Vh:E llc7kRfd~RA d WI=" $'\\x5t;گq 'i% #!."X7W|:FR8 ' 8 wJ&`4f2֓Sj 0CaT 98{MȮަ`IWsD/7*9};N Yb@$KB!Mnڅ ʋT> 'D5fTK $.'+k? `V2zMs `F:=]XO &V8)TNIM59$ e r6x}uWJ_V .VVoi dK]R ;I, 08_V<H g7UEuCD=@_ls?l 6#hJ^ G04fl9DT=y;L 5 -> g[Ш U 9 %QKGMxK_sOcU&lO9EU>]Ih j?ffm p K sJY=\`&ae Ѫa֗(R% T * Cr1%v %9Ez8u1UvC + g_d`G*?vl P( Jn^9 ab#k\K  9/k"rJsdD  .+yNс" .r  2.6'?%˃  2&4&Ӻqs sr ԑmb <ThkQҰZcx+"_r),Mx/IRm-wCNodxQD Nk1t)|uF@~ @ʊ΄pUлR1qF \y{568~   sl D$fDK.MkGHF7R,\ 1,9P"m-ut u ~rg@d7c-1w"M'#9 0,?`Spd|voLќIKx: zֹ+q9'MĈ }y k! ۑ,"=&YI˓ "׎X+ [l(9;fe ~| L)\+x Y cК.rkΠNTc(* m$ShԤ`í0ػiADc 3*.&GeGgM>i5U?|E{sRs C:#mf!U8*@7[h1W*i(%)@ o cU"c~`uAԢ86ŋ#VtIKWK0u_1:PO-TM + &a+f~t ,{QRP6bC6Tb;Wx{ ߶sas b{ kNfQI7g ( SSx|jAFu} = f @A|Z8Z w"$MX}D];e{E_ン^l{s~G *}in V4D f{'lG C2T=u"L0c q zD~ iz+V` R r]]i f=b$C SW- , ̣F6&IpbJCcaj9Etoe0 k>G1 zs<u| |uO="vS4PN@RŤLUѹ\UP>K 'Q[qy4t8,M1|A`Ke[5 =j cRpwį ̥ E@фoiȩ9NC3t4 a xzxsJ` E 71(i zyF VȟPmk 2}" 5J PBA?A"+,*9C  jKRkWb8"lY+A1M oE(l9>j KFnl1p k Ti^dd|8G+?LbV:8x>3d|:2MN@hȲ~ ƼkfVce*e3xVn6xL3HDW]-kTb^#_,9 @  8ڟl Kn@I^F(`I,%@wllL'֩e{~^$,<7U: .,M=[=[XOxGzz B.Ot#xc7 3 NE/ Rܘ#;&H5wecsG)rj2Dgr{jn `>`?|Z+\0n)*K_bϯP]85 H; 4Rh'n HCϵ Bf  Ё,K6uV |)" 94L&u{tI*hm ē9qi<OfrJitBϱfض|4t@LZyj&rN = > *ItaM/DH H+D\2C x6g Q6@H\9[ + _&!b oj=^*k76f((˕8ߠT3rxl+v|bV* ` @X8Z?Ro h  b)5yb8O 8ZF ®4"AL/_  iVq1iC,=: ?$@C͇;fՖqC`x-& -3+QK{Xb`Ȭ* SAhV40]a5 / O   KbyZb|[ B[9u+N(<dRFB-  5JK1%(l O ?^zRr8uؔ/ M :]lB5zJ  O W  (0! x 2ӣKC{SRHQw,&# `R „a^-1RH ]" u R\D 9 q0S AXwF( *@d (> sd7+]!4782N>7o~ο{'! {XiS  .d> b |:  L6] &6\HڵQ@a+OK-{);  Jڪ)kOrvf$A  `Qv|Ec݌_C~,,D}F/52OP&`@Hz_ nlay}XZxJR{ Aiyb#<#/*G0q e] =*~Il=xI3  ςDQMa$ Թ  w;잗ԓDR > "$W_TX\=8j t AWW%߃6 A;P`l dF 6@apMNp]lB k(x" @u,l } wG{J$ ~; @vHT겣 #Y B(ם :y9{] 5 j2XSʆ7v-CG0kx]WC HЫӫ D 0 ?/  b]Y;Zg"xBB.c  $h=[ 2 E$@î]#6ڨJYc% ,b hO"O LNj 4tw4 Kȴj!G&\ $m9UV zEwEe\R) ՙ=2 u -#Edx!jY|Dh~jF DR$ .[a' .snG&8nZ AODO%d/|ȟYuxOIpJ TM^,Fo Ua{cLG$.? h78 X-D> (d7cl4B݃k*>h a %>ӹsoѤ`v,;)ƾ5Y)& ^gQF Bc_{-hW`653FHDIf}J<5|H t`K͈aU 8\%Z ˁV# BV N ~M8WjmMڄ O h  o-i.- `P3Ge5o _W}evNG U#9z i LL ZT `8tY q 17-zyrinjPO{ ,2 &͔ #$ 3*=~|DHq gv  "63eC#n ӝiT+\&Y9w^RI>L&S}R+1 #"@ -6 1vqmdQ Ah ny "&2 ; H}) DY؅2(MEMzz\#( 6 6ħ3r0f[ zxU P}ӘÌ{#nԠE/dm? a$E@s%ѪL1FC) C30,~j Y#4S 6 (e JdsA K y 5CI#GL-eiXJI1R>G, q Eyy f6F@z9lpZD !yB>66O_Mo)@~ï_#ݨN. 8U 7"Z$v) dZL H ME2~~[1 :i$}@(2Gnwm?aghABRA&\pLI p@kfcNwsOtV! 81 1MWfK^v>?A Y  ~ #O?wԂ xc-z Va4m.-  ޡ ;cĿp _JGa 5` 5?8L *>LLeb+$MoboV̂Ri-yflclvnkhtWB= r#-uh&(}#[> 9Y(fҒ ]BQ~[ Q O  _Z.0 4n"t^>,%-'ix R]} :]z}$\ =t4<(8 * d/10úLz(_0)U? 0 );2R'<2 A ; pPfXoXuZ}'!˟ł~> |PcCLV(|/> @w n *:=Gx-jL3y A+T84kx2fԀ8#? 4%2vkh S o w)VwXoG2u G 06{TAQ0:L+#̾ SŹ -pkal%1vs3;;n q* +?Y9)e)Pr -: s;βP'G̬ND}a= l `&bv~"o L;5 :KK   L =%8;bzܱ}t#y4s*GCZ l[eoV!4.G6##Z E ) /gg a n  ~7l .j`r x TU9- } :R TbuKBH\Bc7 R9=,Un\l. `-hCoG:8'uYsv8! 3bYKr]HJH~PHb`X%hB Koim =7 k4<%욅' S cH\cDMW% :# wF:B=0$^) BYp\_@sM 6"Mpӝn|e,J6?]_E  cF/j@roR@*yZx0½  j~  IoL.byzjZ.5|Toϕ,bϽnMq C_gc'/wmC~K  ttM 2H(aukK _facqo\fJQvtk 0 -Mz4n8KQuBG^ e +O-_2'_:Hi '^r:"0Ghxvr7֯ a$L$\t#:,( Ԗ /꓁mg^u qZ"' W ?7muMO/Sd 0gKmR " GA ,` 4<4( j/ w \50>b,'9FhזA[pyr~B3+8gcX|q[;Uy>Eˏ<u*!!W,׼ρDoDoz]AA :/V >UOsw GR6 d) ]^ )-4z j M #  * )ߺ\؍ cZci j/637 WQ0K8J: J KrӱG\xY1_9Wj6  u "Qm_)EGK&G [  $vC<O<oLOrhA_mިkg   :r OK* Vµ͸)r6+\hI +)qvStL0f.sǮ="V a X8- s S?uf}i6I9.v t S 0af+M~t8H0];vjCcW <[BgwU"d~e>)Hvշ%TJD Ĉ \_k|fI&(wXnN5W-ҨG  G]+r6N-I;jE[3Zv^ o    ? j/^Hd @o D8T8J0 qmq [M)I-kpex spg6qD{p ˒:RK,Az]qT;s̭2^)8pg +[ >nP [#n"iFlf  O ( '& u sd 'E $Qtɯ t  ¥yiF{#OrRWohT&J!)Cy ,Khn;Xde$aGDA_ :JZkwa$!UFguhqp!X000[I8iw}. pG55 0Ip0D=K D$\+=&ϙka:1r<lu 3 1 u%ZGyҩ<5Bw[q%R+ d #5̆!Xlz0e+T_8ENtTvB, c,Ϲ*Tq[ n V G_XHe!&D"j/E-" B%tJ r  q6 $s )Ȳd|9$6ڏ!I9S7=ZS1~ & Ttמ 2 Xz^mP }:6 J%ya!?E:'gR BHKs_E8Wu/{tD46thi^6,_a/Ozҝ $4 P9c>sdR6?@,h_! "-w/?}{ R rU~X@x 4# o H  v l,Vlg@aZ s^H$V=Q}Q$֡P@)H8iQ,SdtAW@&?L]tC) #>N {PL G v> jwyDXi4 xu !`O@QF ' IšB"fdT`<̢rC$:PfpqO4W,glVcB$] ?sǖ  J3UYMdx.KSd]i@ i Y9|M,b5Djj AghJ2a>mp<6rn,9R VqWR ӯ$ otWICcQ^3Ϗm6u%nh_\U91X"&86O16_ f 1 00Q72&NJ%Y  S!_XZs%Ug"%;' )} V^T^h/WVDE<.#^utV/p  L"^*hpSƾpgi(0o$$!:E t ~%S/56Q*!r|?7wa1Jja=XX~K.1?@r.J(<><^֙R"$uK9Pˈ4+7joiazn@M,52k}h2fA! $ dc rך#\5HT_A8 zdfs VRP^h'- 5gS'eE$*.Cns(a@ y*AW4idCϻ.<0 3 vV"h."Oh:4 4h5IyN/eåP;eP/a%,P|TV.S\ y+ M<W0̒KҰ}ppT@5"[X8h{P>D[y"R'f=-Pq,m)({ S >N*@~EK l2 l v*5 2N"LT@S >c XoU40S,Gcyiw7{68X4WvZX T0s \Dwp"A\\uI))Pc#d͟A= GUB6$DopjـcL_Dk/Ht[hV6*cfifstwFrz*F: M ~b,*x&DeMgC@Q,rmex^JfWl;yLp%c"~@o#]M, *XL|P "wSoi.:uF+R!XrE^?\.h7d&9 EdY%MjWLhq; %eX0c¥7qG^pm M!$4jqC7Xr,SF74w@t5>} ^ TD HrT>`>x=4M|WfJ\ &!F" 2W mmItW`+ iF  f` ef0$P>50S2jwٍ2@C?ng7W"r@)MuO/EηJ3~`U$5KxxhA9ǩdJ fܻE:|En!X_}>!EkF2}&eV}j-H#a{B  aB ~{&C'H^Hq'2pPܺ>"=^BDG{Z3uu)3HAN]ӽ@?jN1Ozaq)ȠK, }K+#< =%s 3A.! [>'8FMc PUg %X|q*_F {41Jl cXsIuDITN.OSv۝Q PVSG{(vD_U O9wj[XB=T=ã-VM:rjfMNG`v,HXf`[$6Uϸ\o+k  , MD"%01JWr%N\uŚkaZ2_= 3ץ%c̊2 jPX$J\REU~vg $(P(L`=l$ ]1np%L}$6rCa`sS\LWm.\.v|ʘՅ=VxQv(oajE/?4S3;4F%1e_" FJU06Ԍ`Jii!c s_!yD`b P>Կ1"٪o4ʪS^Z1Z0TX  Ȩ|hxnu# #tD?pHHeۧ{|<bh YY~T i'Փ&I%{nh0i%f-wMb}#BWp|b#)ʺPǐqF\ W>YCwjk"f fN  )'-{i$@ jT;w>;vE W-1>>tzjAoxZ+Iyω`e70iJbUڹ8~0ŲVDˢ׌Ay~-;C:1mBzM8s 0 lgYk`F =] 0d ^%wAZ#B7o 5 `KˍyWkEAz]D!CM e p./R&ijpa+DYa m0~p]\Vx11.XaN|DDjۻ Mwy+#2V U)K?W./y   \^"MAB`DTA+ef$<n`oB W\ p|ivi[ s?&+;nDt"}y5Av=0@ pUic ^?P[ Ƙ4e6RjS~/wZ^ +|F1myRKvMːba/|"NX>IB\ T+CxGˬmo՜.]6Ç)UyuKWanz}KDD/(k[X !(p3 %$h BNT$Nn:/|}XD(=foYNt\<(oBeafT p6 8{?MQ]x%\R Rl_c02md`R+z#}5+s,bNr+ʠ%R%mGO|nCtI(қ=H}[NME-gsw<%8bII% 5yXL6p)hQI 'fQ?e.;\G&`jWVd1o-s,Y ~U&0+GØ3 ޿a:gbb{ON [O_gz(?/i +7[hq0 H| T/HG7-=atPssSr3J=+-%oc!vj۶mw2*pp?38'W'@Ex(B,5(czE,`g6iV Yprb[@flJ!ID<QQkp dڐ>m0a;2sJ s_hko 9ѣ3e Pp)HH$sp4 ߀v υ*(6$ _c+6K_Vk/wk~]"o4+hOxjj ' F3X'O@p{l\4 5u $VcfVlOs'7 Ps:ыnfM0ؙ0Cmb61تUЇJ.\ Ӯ}"C<&L:C75jbYt9'} F:ʆcvƪY)Ukz4*D_0Zh y<:u/vu) 2aA. p&=/sN2'R oMty$Vȗp)zm{C<P&4=n`&rDoAKH pC' ?{.,IM9~W)LM/,zpO<=W5sp="8{mlL= }9 &u  4ܬ t?b;!JQSma C7B-&@K(Д`8BX 6`GQ,C p\9]j % I #:G2ޛtIV/KGQ*ʴI `l6JznT~y,KZC`9IǛ<<ey+~f {'=>W'z\ooYqnV%jt%Ej+oqNwE  I m ú k=S !@"#-ӽf9@0[*+c8JT|b :xt~^QMo%uod^RhĩW.'Q>pC[qFq<r͐q"}=NJHCaTb48Ik`* 0D LL& c !w 7 U 52fP{UP}f'qN 18ެ^.bŠt< +QKk.Lcl2vrzά ye@~j½D K e $peI; J<EPM +VTq xwi=2ecQ@T.{ /ρE5e}l1~\_ec v0^yD!a:;etıE(E}G^AAAD$J}Xv)OQ`1dB'm)|Ƕ@8 " <F\ 7=-g3nw M0@b .zFS ^"{ BmOrnҶn6 y8{ U  '*N k3-O+6sc]dͶ"V*SfcGJ+Y "&:'*%O V$!M@:~ є 4qpl(ŭŸ`VO ɃU-jKcJN>|] r CqRzzWe9LV Tע|>aH- ESɭԴGbI ÑV# Ą^mwj͗|hPh6loe %_,F^I>Y.F#`1J=|Sl Y/h Kkr{]4gG.rQe9cML}$`2f4)O`' 0Cׅ84IhrfWd5S[/, i,MLnzwM2rjIDSt@ Ƴ +tM*KN }2Y7E޲G+C3OjdR_FYqf[.1׆<碌S<y5u,!CR+5z;|S WbB+g\_D']06. X1hLAhmP/UQ}]B7rN2\ E 5z*;:s`ˠ>n] }WmF*+,Y? 3{D7}T+k\f:VEWK"'8>EvTr)9+3BfYb :2kcNg&`huJmcq|L6+(ؠ %7!t%lZdՏ77)US26#1{F6-2mG#h+I*C8a pcNPu[Y x_1A]*L XTF NQ>f"78blj2 j˞%Sue 9og+:3 SQ`$ Eiaa/1aqlkr8i &Z PjvuEf`-\?HIPrXh}2\{ ae C \U\,+,a]B-T96qjK  gWkYZh4%aXU97b)iC5ZBsN3r i'ς fV3=xʆrL2-~Q5<PQpquJRh^2qˎ/=rA 56wŹv u7 ob |P2{}Y%S(]< z\2,kABCY nK?I  %dZS'P i_4 MS( D*eU08f O;Lo8hXK%)-g2.dJ#Y\x%4E mX)CAS _jX è6hQvsY_lڡiVO'9OBRWT4bbCR?yn8kÔ;y0|ߒun4%<Re|)*QJ\1xZzO8?> lUh<R>Ɛ^C]IQT|".Mk֣-JmApcY"9j&Jh[{bL\d>4FC,`6>ʴxf:sktsSCX6~EK+)8W* gJ ;՚#I{-(%U6:"s!O(:#%'VX - 8 %lD \iey.N >32,7\FCLJ'!iF|6QPDzcf9zeBr*-!$-Wq Y*$uӈQ;pBfvW7}|FP4wpS_t!Hu1JE;xp;IG-{-(R@xT&='{$,/>+` CFwD~Ie Ql@AI]`Dݲ9sQ =%'3Cg M(~7% d9Ar o aŲXl0A̡&Y68:H   +lLLP=*  Mt"1ӄ݀r]ڤY'?lIYb KP8 2,D? 6*4UQ14CFs* Q4CDIbDc>wԠF!١yFj jfob+ioݷd +]LcVx2b F?'t#Hn=Jm[ LbOhv/LS .Q1].iG+(av93CKIUHV 1ĂAqÞMʣ(zvyG(PbC%)C-"ĠZ`<fo,d$Ț *OPl 2|gz˽H26A`GL<5)d@1oqNr~gZJA-ݚ]Kh_nK>qY>f`~>U WqO 5}t|<r vz x'Y^Cdz ;0#e@| <Mv}e'l7]q uQlU!NV8b(4 b'· 3pA# aE@\VZ,-#Rf ~0 V48~x/$w z\:Q&s b<@:5]e&jiW*ػ B%/Kv}RPL7-)+nZX)4 ipf  YZ>Ǣ69&kc$4[.KO)gx*T/vv(nR=͟lnaۈr2r EA>GISbͤη3۾.0e_y9g#@NHyi ǰGqe'W@Z VeXcsf^?`oK,A5wg8`|i$t 7|G) DP,P|(Z. kEH8j0ѱlI1@qL(;ٽ h C2g=e,&R&!wX.t $s,yUNT . NH IDW,%SeU;6>y6n']eE()* ]ji RvJvo%"@V.q ƽI}@P8%_ %>ai U !myInD"c]9 | q oER()-llM#ļz yN=EMB_ܼxR_05, [9 ? cq9~Dq>n0ENk[)!|b:dTقtE>GKl~@#G`eX.?ğ3^vm+Fb`=ud@J:es3OޗOUOL&(B.o"1OQkTo+?UA j@d0 LMR_άtu:nF)zH{$9I0Y=ZqnbrnU%F Z O ci]hxZU_#A\GƳ- )b)G9SH*z/.{'iD!R:>)Nee!trI  lq5A–ت{;$r;v4g8;})C}i(,HV*xK*Eh~E)>P09HAՔWGaqj.7YVkxk*I ^> A bc)\m8XylV3׭@Pr>p,T C 0=с'gD7_yrn-XT M0a  IJ(۫aϋW6)=^!$e}&sov1ec3܈1?mެ"/Ep|֗S O8X p=6YTUNt,JGfP31-4W!!1'z0(BƾMpN8Ww zE)549egx`DpA%h<C5klp ZN%P-FZ~_)zrHȑ=>8a"e z6qH<^j%8|Z9YT DŽ[ip%\SZd8RdRdT|x?cI{(ߌ:?]Eme{}7N" [-&?6;s -h}nX~SDdA$o'hw\eCU [ֻFyX@qwlue ` m7E3}y6g1-?dp|QM-x)Wb0k ДqZ?MG8%7)%0# ipAD{BzytQKM`jj 6#m _; b8kvxU,0gHinnP<|oE_)_=<^ =5"9A;`Q+E l,; BJvd`>}GAeZ#  ^xfba4ՅH#˫ntt~&UdYZ>|}9yaRI!~W l2Ez%-$-?Ӑxl/ q=%3HT(~#Ē:}7MX6 J=k3%cSzs wLg:94(T}]AS;2K0j21+?=yaz%,6PvVn^hf>0vW tP#bax 5z@L S7 cek_)?[ЎB7:R{w72Wy{|Z2;q8i  $A\ca]ݝ!qVguK o-/Q8Z0'-r(0(}K]t…GeGYu@@!,odC 1 :JcvYXd>'YiFB POD}_ RG/X}|[6C[j"Alq4.,<{]/n+_7f*LP2i'g6Ͷ)?>|iH:7KL(hV:$\y2 g:]r$gtN 3ACb{V2@F%KBtbl,:Aw<70.$g7 !;C?n)bd8ft)Ɛ-]k+>j^7Vm#{e/(-rψbǧK1)cr+]|":2e lT|CkU KC  jҚ/)`=[lI,pȴuB.~!B /` n\ L CP"Fѓd\/FH j?wIM3(Wi0J V6ܰ+"bU5fB9mLRI Fb pzQkokaC?d }$'^Iޭ%BW\"}cZWm5h,uuWYP21\TlLtkg8D8|gy3Pztֽj^puI&u1,m^\upg58-,T );s uH?L $4hej pdz/}|Fv~wvZ p}c0 8o$3c865dLAh<_9} eo^sbs>A'mGæbhV6xen+pނq*]{}&u?ZAfr\/|>]xĆ ?=1wKA^^S%o2;DK3$A0cZ,!:@SD7`C'uFesj)=f!={ !lYhry@yYdfL"`a5m$F~oRyf3;M> 6 &= |۱MTd,c t8y#W O!l@M`4Qll=Or'{ ZIW8P!5~y+VKy><X:$2lSTFYpHV`;N5L,}O~m|G|!^N(:`=c+-!xr|A q]'< *=V.6&<Hn.-B7%mTti42xT̥Ui]$r4kwJ< .>>]r4O!n_l΅*oRu:b;kI=ft]+duHLӪ;opSA=ķFU64_-R}H?S݄ (~T Iil @MDzOnT, xyGWh.*xw7jf}']9Q{ B|^4T۹8/xQ+2lчukTZ=bB P[kRNe)}A;dz(O:!2 k_9H_ hyĮFp n onW$@ k@yc48߅+tׁ,/fXҌpq Is=44N+ny -fx_dwQ_0Gk-*y.4(+3T WPޖ'S |S(ZcW{ dtJmT  7 p+dfJ)`HoJ)^D,pS!_H; ~4` i23_LEU/CU>^-@u7=aCa1Dso&> n-sm((_xw!JXkA=~*`D$9ab!C +&[73K >`6eNk{KV*QOT(DITs0(|UJYes|*%7,:>afLE'[zwgÏ1 as̀%,e+b;'esA<wJw (FsqAk!2-hQ'kn-/!} ~bVӚCJr%<(_P,!_*AS^˄o]'3RN%FQ.O4jkRN3B(%`}bn 8 2Г?@>Rl|}sfmn8R* `)/y9mgt^8}E )ϰSESdo"s p739:6Pghe`IC6\-J-Y(Jdb~nR[fCo9~I>cp ,-Ś44G('7z&)\K۶/)a.I-=h $H}ޜdz-eT}#:X1w1=RT {fzjm~ t=)r6OMows,6vr }Ngb:gtVZA@G%)d2J M'`mO0KFMBh2C>YGX3HBYA--We>}zT,}kNV"\@"t 0sV\['yۭ>4!ENo*|q1sq @ٸhȻhydzv[O#u3 HHeXa0!HQ}!x:xX'` {=d ] zօ'9,_">OMtv*Ww1R>1|[) y-ˑ  QHon/#~GV(YJѸ<ROx +bV`DlLwb \s.yw]k|\32( *phGhc~ 9*?t>іMKIWقZdJP#c8h,+>H a,<'Os50 DX@&$$E6Vf~ 1޺RÝ|T |.\w+up3;+A}H.'&K7 '}|wj:ʯ #>Pf~Or[[Zy|c0JG]ri4>8tQ^ڰg?mB$,DS-m^= Ci%D&J," W E}SPQy 1o[tN^Kx_=BtL)xA[a*>hx`T6e[ k9x%Qn F h>8~M{T-Z'889woSJ~n۠9QkJ(:X@͛a:>&|> (M"}ukFJ)zAv$D+ FF%aSfu%XBxp9ۗ(&49{_\ r{g1B6 a !4 $$F'0JO*$J4M, j* t:ԃ:M?=D.HaB VP ρ !^i/Inޒ'v"*{85d  j|(YKZcw/Ģփj:5#NiKs H7k8e[Cjzo x2b9yZ*sJLұ!Z{Epc~E!%Gh^NsiSmx ^ Q![ lϨ>3l~$w=f2HU6 S޿mdXsw0H (Rݨ5$8W* )<޻ԠEDZ VX/K'NrǼe_$ˊw[A{juV'5@8B[EO3.+NT˲}0"5"1,&A=m"Sbf5iV=]Sj6=XQqk83 JEyE3z\C8=I%*[? w33 Y2 c6 :n1Tbnq9d+^2Q$%6"z{߷ xiuQ>]=ye9@hr95O61mQU3sS{,ɥkr+ :t *@:K0@JRx*/iZvpWܧA(+C|yVf{HG?&M(xega1m-4{|'P?#=10 Ȓ9?{!FI V1 @ER~h)lݨ8U[ē?~ugS25ropN+DKu$-ӞO~Z#NMrL3TKh4L[Z.V0B; ^6j~GnP9df'bī5# 2 h c|{`3wM8gg UN:@P>sjEw«aw_|ZmϦeU/U&WG;!vkHq',d+<XiyX|+;0NPT>AkqY}KqxMdhia}9>~Qb {-Npcb7 Av 3L3R-.+94Hxݫ5Ws7;.|NQeP7/uPh_/tc7+@h #108rXQуK}6ݢLwEIߡրfC^v_OcPI{ ]ֆ )0[6Y qIaFQҠ^O(ם<i)fǠHo'5J>f/zJzTEhcgz\4,ι| D0QJ-wx ,mX1bKl{pKa :%gBLSTKKK*2&~e:Tct],3RBp3?SskE3dxvU+,j   /` @s kS = <^ҏA݄c(iB}9G<X~ 9t*\R  :>t(\&`DL*rI+?^ P Μ jٚ;$"kڃ;e-1eWR0hlc<^r#H2)UMoTs[%nҽ LS9\{]^V/;3Sؾ!+hJVձ:eK'] VMKTYbZB$7Ւ4|u Meڤy  9!bD^6OMł~6T}r<`S S4$ΩbyHBLZp qzC-65 F$+b&4}aS5+r hCGM(0y0M) ezvkMn68;!ɇ\^0;) jlDgF  %H+T7PƊ'+DnSH. \Il̐@7Eqq $nb >+hU/}R6AC%8:wPV?nZ9DmczVW('lXOFa8oS_w}O+WnT 3L{wmr^x &~} Jdrpu=Qv[KD]OW,{F;[O aD0^FNWfq'âi"oHh9svE18*UVi_/Da`?ԙͬIQEsSLypn0ntaJ̍vCxւ> 7k<B*SewFTw,k No bL y9QEp$LPK \& | CukUm[2d*i{z>x}r1G$}P }?<kuF/+c^d%2O&P yJ" ff JUV%G RLlH}'M>RJ;z&G : ɓf2>G8 ´Ns =Qw2_^ } `r%df\6OLlqӁ<dĮwiKo=yPOm` Oe:u hb 9ʹ*, d1^v$ԌV~W+P`->_F#! Fh F'7'D q 2A`Q \mf w&B[W 3tv@2d }$Bف \#N˫*4c^]fڐl~} ȵe-?j6o%_CIQh{XYt%{Z ҙ0oPRmP(Sr9JS[Nr03p")YIrT@n :R_~wc1Yz!h` (7)9>4OEd[3og kf{kP&4Dd.{_ \*FbL" ^ e[/mu %<$ʑ(xi!(W+DD-Eg=ɰl37Mp6nxk' 8l2_0Ym{Sb0=@Vxx{kJeW5u[/jAVf 9cF%edGXYX_r09[m`z;e:=B`+V$4oE4*8N2Py?%Dxh}? t'xBxZihIh-G 2=3iQ[Vk̴qcPA 1jjj0\/^"]_Uω)?kAu9+qjSiRmaQ4U: <.q }h3wy'F\mǏ2]'OH5Zԙ#';oqg͔Mz$W!/KY>08Ϣ{2uA4Ju^IW< $էtc<[xU{'2:!cݣ7cwe| KN Y$qd4u0bK1f~ї>A3uGC0Aq=]}&r88b[] !9VBf~e6oqp#2~ ktAv08R-{8k8ZnPgwCדp=8cQ3a?(\o`AnlOw1"uJr ~: s3w9f=> U"N$(ݛ]W-LQ(Υ&1!sqs .+3Q?$&uK|DMT% YEx&)Vhh#^o oʃqId ',>WXi:`~kPh%} !$ה_JF-EA6(Raz1$qOrCf90 Cj(I#_t(As45V'r3wikj*')=yu@_wa3|9G~jW|$B~=w9>3t9tWۋ :XMK}#&( }\~o*q)+a1[$t|?ZDd6EN^JS*BPa-B#MY$ip o vl I_30Cӟb?nbx=K-e>'Q ^(  t<$];8~R(/j#3q]yw՝|_m0alnPz =ҶĨg >B    |lJU}oi-rQX@D]1 va)Pdbp (4]:+kV,("ޥtn_u%&jLh0v18 xEP]--4 ǷriZ̭I*F/z1A"wz<,&p,*|B+%d nJExfiUE|xoFe4f jq 0(`1 ͉ Ϩxs{Wv_]BdHOgZ+]. p*}bȗ\v/AxS&@Ph/& ^ a$hSKsneF!e?Lw:Fw[s~OVh/XTj 5KqvdSÏR=<0e\l%m"qlh'PY=>{B\O82osJ :Qq@q,ZH:ܚDS=2{,lH#à_ Y'LiHs$w@A*MoY0B2cGkoȀ.es0Y]MsFB-83uT ! [A!z!Po,(DJc* ~CNFW"%+/ >bq@4yhu: \D3oF7tHI}&^;\ N A* -I KN3 C?zr,|QfX"` d 01 'Ngc1 -"u[!X)@B"mV" RtĨz 4cOFve(V̀]&z(.P4\3.N4BZm,t1Dfibt'a i >|nB]6:H`nM ^ȯ64k9B&gvk8Fm>RКNݥP7otyt@Q!<6FL nOd bgC* Ka/n`@m>R]n N@?=؟RnE_jT6T d8IIa d!Jwj/vAnqto@Rjfڈw _Tmk3ZCmvV,\?KW3\8)82 Zy:R>4 +5v?kaɍ ƪ 'L 2"8(*ݬ M wvQfq4 ,iN7yʊPc@CL K\.W/Kqd2:fxPЅ9TؗH5*|H &l3o(^.3d$l6 wjWe >q^b~S urߐG }+p\e]\P6=Mk| CsN-qHg[OPVzfA:wd4`T0u_ LJbW{k`l,B\y_AfJM4N#`+}ְ1$ Rٶ ! v,~43CN&4߿,. rPhwo>1Hyf,zH a<= 46,K f|l6o!m%CPR+TʷZRK0J 6jY9&>d߉NV#I@9>CJs"K  Ol  tSb+b;Q]")A$Ju%[-8~ACot\ sfn:d/BCG>E^;, oOY8d.c)#iPxT4 UM @TYZ9" 2+m7)"2Yx~,1c B}g4_=*f59aQ:DKYصR\c+*8-6 6k3crI[ naBncesyg>VM AF8o~_tٱ9q9x&8z+kK( X7c?fW^@!~jmf)^I'St2R]`-ea̶MejzSaR[=>&MbabHO>w47/\2xw8KP;E1Q8=eu"{[.)jK:~ [܃xj]pm~S6ݿU6A)HU_n ɹpR}g_lI@*!ңI3SdHԻ'١ty, JMh  -<#'IzS0<ƈ];?@?}sbsDjm1D7r_+KIGq½#P9Wx\ky3~8Qk*2mGB x / W؄HtiUT 7PH{&sAm(uKm8!$Vm$o.}M8j&UI%x(@$!bCB85X\(\>bh F '^X"nJ-"T1 7KQT{&A*FT1ycE3MepW)}&x)njz\>A|%*av~y1v ?jSi } X  .g fEP{R8~5GcAm&)$meD0W`]Bkvr Cwy:Qo' 8KaC<QxF@D̘k݋_)xsXWbG9zwT$k|8֨N[<VH,!sup0 gTVsI2'Ϥ<*jtMtIPIm63Juw0p3>sj+_^?&TSߞ(b;nv~V$Xj:7-=''#VpH_י20| W{ HL+7iJifߖwi{/unKtj`+Zt`XC2{Ey>@#?g G6X=& !/QD4DYUea*evOTbtLGTzwN%^1w}GBy% $`AJ*.;vls ~}WHKeS=;$ nJαt)_D s[!D4X_;{#g\~O*#9;9Ow¦?~!G[!N;gTIw 1$z L{ |'9 ~;)v-IVKߕDb.ziaMXa/,e=:q"{jnWt`Y&kP$tp).JzJ`NjR #js4є +T_FNpOV]u  9+J5x;I!Xj6D4zLWo,6/vMj`Sg n}j[|:SU|:6gWBMXdFcIFl.gWJlPs~OMM)wR[ð t_ر(C>r*-gp: Y&#}R";N!}I1 Lg'bF^m2kYA wSc'jÛ3x*'lEVrTE!=Tw;P<>jAM* 6n)Y`+ޫ=f9 s3aS?I3 }d΂B&.dVK:;Id ڽ1;Pa2?4lSQFX yc ]@rʾ#ryJ*>0ss *Fcl7~l]'U4j\cXm_<9$*. _:NUj1ޢoYnVY ,b\v&b]AxV&s I'HplmNl4[2a8Yߘ'5yDK V-1{[Vfa6kd-)V ?U?".3To3Z*axZī]YmB/wٶ-eR=@Ы,kؠY'M݂RK-z˻XP=-` ,u1`6"-BE/CL1=xI y4hm \K`\8$68 [r9r$ A*C=1 AKM_`:8l>E,Vf K*{_?!l08?Boa K / a|/AaVt,l&$kI0 }K+PdpqW{Jb}4^<w J(R8SĞ[z_eb{׆rT!a^i>3)hN~tmlE dsM?z?F~p1&.G|L|KYUBs2.#dnnqt&q+fј3PO7'me8)wrVp.`3 =)3ON9xf)FWy~FH2aa<4p2Zfj'b& Ϳ8["IDN}3 P~fT <%ݝ]2<bnv"9iuU"6_ OwqmsC4gm;Urss2]>khQf .A>(Ԧapk#܏zEpur$&YbLS[ ~D,14#U) O:74^LxxZDPn_OSYbf]WB@N=> $TZqNRB%u:JpH/BRP"#pr2^7L&2O.K/as[,ϦI^';.H)Xuc>}C.pGKi)Ag>M[Qidž7:%phegf}O%Ƴ5&OQ$0hHO\T,3;~`W=>6`'x@!NJ]NqZRML_9a&SvpD*,F"fJKKoJqPSdBxz@:Y~KR7sLeZie{ҋi%!YG@ku^J C[7hCRF`EqAo5sx]13 7/6\K I}f&9D8{CxEt"$>@ zjsaЗ9Fjy"fZJAOlT_a6^ r6{Rԙ<KwQe e0{gC[ ]&L#_aXn miTmSh̒ '&s:c ]V5.y8at!TJbPTILT*W m`fw@@<>'qiA7NEaDdmwUF7<Yps>m9^ze;5u1 CIV|n12B/n]y6* FQJ$N̰C5=I2?-s~6Apa+s%RU}gtu(ot<%Oa7[lW=o5@+YbRG@p0 k)<wC)eC !ʍr;u@E<%grWNAx[@JDE2I]ZI#pR' q3O$k?D09 k) u1,T?Jֽт*M$Ė<%xf #Mn<-T|a ^  0 cXQm0s`scKtm|Jg*EtmX&gvt {X4VO$ՀnUJ8EPUvMtjl 5uA) E4@.uGCs&ٌ`ԈDew1]g E])  {q*4'{{XJE",Gh@*צd.;oftmk?ZvTc)[yH[1pS+ 8=V/\E*@X1y-N)(C,W~XdGHz7zz(<wsfZ0VI;$J{zUw:h7tU{HjAQDE~^8 9kq+UO]GGC+mF6O`AԸadhccuի7vQVZ|F^Lm,EUVsL-N5k JĐHG3,GYOc%y ^7UǭTXKC:8U$> L#I^EeZE}:?ZNE5*QY}9h&-/.>QT&z\:BKT, 4v/MHvlU#T av!ˢ5wU_BhM*W:I_ j2x0:tۭX8/;cR'TYdZ")~8R>Wjz@ۊEKYv7pܵG x.N#^(j5h7B{=@̜.[R=,4;Ρ.65zn1qp V6:iŷ0*& g%f[! D0s^`lZŌI.wY#32x@DtC,j`AT}6MPqq^o Ч,)(RaTQ(? '/2g<pX@}P(HUb z_$gbv:s|! WGXzaW+-{ǹV8q@Z;}͞քC_,"XWqI;]k% LqHn&q=~W%&,/i]KXy|8 uE@_akdkvRl!lE˟Gjfqۖ*O^!3kcu2$Vp(ohjG߽4{5iwYWH40I| 7{ԡ1QYf}\;j5 œsF ON0Q]%|_Q7w ;:<EVjc`sD2U,H;Mk(.P{W[U|WؗWG#pf]Q1am؄f)9YT[Bvd1SYg|"Ba]lEHi&DkG}%ɛ?GUf£Aqw75%:I(lesM(U :O1hoI_:bCXohIS/Jwh^iK1icNfYHc{I'^Fdx^x6*4p[Odsf'U&S.9  p4FFw87(53dUBZp4Lj!LD*fnFSjoq\cp͹;0+'Fg:/zޣ[8Q#e" a=>/;;qγn=T)e-XErzS!@#CttR*u [6+w4l{+3erlM҇LaqJAk'tN}^S#ikQ dbcGzV8 i~Aem^<z?8sB8H_Wo]ĊXC 9YLTg|U (tUumc5%-D^>WJi.N5bwD@5"|`bTHxRz5%!:`:GB_Q0ڔXn& ,|D\I%&mb?#P\[('sbBψ~eUhJ#;0 {Gп[ L.V +}q08Ysخ=^v&H ~i{:km'f"G]""vU?FMe8G2_'srLso,M9}FL2K.!2@%6ryZ+qoEl<`ΨS_uڦdGDbO \ $zyn ub'-.Mۖ-?IJ&Ml)sLl}6\Z(>1HovD-N90tk_O,@ Uo#Pg>MvɆ@.?I 'f3zXL+)`wı/ERGU0uptq@=;ZS 5/>Uf<r){['jZ#?% @;!pNE]TcgB>gK=8@BX;:ˊAv TD;x4'hxAmW~ΌZJk?զ7`{c+, Q|'pS)KLIL\np\Yϖr!3f&y[r_2P$hχ7*C]nWLJ/3Tr.5v!np _mEv UbЦG}F/_*Fpix5}w1Tąhgx4)acyoOQm5/HblSkw3::z'x58WK (isHɬg0ȬUR0xWVYhڶ5H]w> ؇b?9"Hػ4 $%~~fB08CFNpuS@Cp`.IEmYxqx-mہPTC>&E>"LOd>zVU kȼYhre'9'4<K*q;&db27UX@vCgAKn&q)j/LTHu7M_+3f[Mdrr*A [yM9CP'tvy`[j=*zY@G~vEyrE ?ycJDU:ISn:sT~[EV!.wx/ie')cZbP1 H]@wB"W4S^,vRS{cS%ܣȖCI!w( {W#pfkFf=[&!>,s0_US9$X+ [0GCO%}!]߯o2:[ǝԣI F.nH)(7eG{7q|#_ĥvle&|pid *0#@ e@~yMdm W Ko/ C en\и<.G-S/*;lU%]TUeK>'rr!s7 iZ}&H\N Z?D04b[4X/8jqXD"5%[M,i/N(pckhd'H-x )}%YA١5>m:V$]IQt>_;z@ |D=-m(m3P0w6Z)FhIևv"MQ>ejfbT{I\2u !iw [M*;zuhBd`O5\c#|ܣaY^rq6QW"WC+bd;k;{/$~ryune.MҪ4JR A{rcQ\DtH 1Mep][E}[9WVE9[ϛ)6.3/سw0/R69e:@;H y 8Z6 ҎX'v!: DSlS ]z g,Uz);+:d_&V)3!Hv=U18.zZuT@:FkVHB:3 ^$T!0 ?lWARk/'>(wdD6Aۤ/.1w,6{y:j#S`ypp/04Bq{INn6;RLc[BMb*j+CnM}Ҕ~H 5eBrYuyd1]k-eITۛVgye ,dU\ a+*Y%AZ*PUdu0OSnJb>vm6XsUA }6%2Uz_6T[ļXjApp0bүmOre8]w-azmRz $|7!O#I[[dTkWbMlvoۛkMƉ}-X v25kѐfy(Y#uXɨZCU^Z ;r=x]\isQ)T_ l+Z-ʼnџET%ˏKpC7>3}bvWw&+IFq(^( eVXIhssS31 yX+'BZ٥G"Saq.o) hۀ?9`YùbQ zj.xK[ޙ}|32-9_OJ3)ukgzճnTroһecA2  1 ؈E3Xۢoߌ~JZ P `-T~kt~2@!CQjD"rttEEE~,U$h-e#)O|Lq W%wM46A:| hЛkXwBR0bK"^0Q56/m _a'CRz4XygrL=FN͌FIm CR:fIw PN.H K8ms03y TZ0)wxjgbd1CrA2S*;e\i6u'vV-tdro3 Q-u|ɢ@MZGbgoA E ;^~*#lLO.w/&›,E X67eNx*8s: ^ߕ$#vTiaS vRL2X A.bmi Ʉ4 D8vc>ebn.܌vHyf+=v${~LQf&-ow+DN`Myl öD@\9@~PD^71A-2Sv 8$EXХ7eD9a3 OJ @&-rg/4ԊrD)/v S.p}` z>^I>x޲2i IFI!juZ PLiR G 0SP'ӱ.IOxbnʛ?Gokw{DaR$O6 8ܢ A*>8DjziֵHf_12>$Qsk EQMA|<' f(gH{8$w8J^!4q' [w!(k9\$XI>:$V{FPaL )&"9oD/#|Kj[b7\'i0eJkI8d'٤B!=nsl075i O0V^seju{NkezfXYaÌ%:% 1 62m2z{QiM,8eb)ӽ|Lc9qA]w[.r@<yfsabK( owa+E'lx[Yg O]|#Aq5JI2yVϻ6V,I|&&,2CITgit."&LڞZm1qKhT~F6|eU1П( kuL )+4W$Qu`G?<CM@`M5 5Dj " 6_4.-_6&5M9={> aZ{ˆ[0ݢ8jcLkCSr'{,ٮ]0`~1M_ x&S!vV6Utc$֙h? WGC[;Ln[x4~e_A~Kcp.Z&{=bo^sZ Z{'Ҹ #L?$>'*B Jcl@v&(R5&N4j^ i2 .89G`S,< RAt 3ZF&z0 M<6' j#lWe6 Y(+`h9`O6!TK%\a?*+;Riy0,.pwP]`\wmz BO |ң <+.2;%2  OAn{a{hcOv#m 'X+g1ޅ4E\}'G3MLn[*&{roOKcdDft<pt Dy\a$n oՀPZp1 ~d?Lw@ syN|b/)gO+{:<(VL F{^A/J(_EQ`g#mT' [O.hQxàORHRMjdWҭmO:!e7l4o:38=>iT_0)|CaE=Ռ`\t o)g_Җ+Ҟ@GK2@,>A .j$o}7Ҿ'_ GIx>,a );T*"$CE*}l-GGZ{A$LY0]-s ({BMf?VDֳ_H,4iSqyMD͞0dAoD466%x#MeH~/N"VZs!ZziiAZy,0> >JK:m/k| 'wA,EMLN2J6m=ˊho-r}L{,Ue ;Wpa'5Z-&\[d5V`t;w\ 2/x zw&18MڴGbaf!i'k'aŒJ{OLmp2dbN~,8P`yr{"Q2wu&tSaugY $_6*S"aH!qKwcdsC Xo *yo.po^7hrwsMڷqV="Ig7OGH5'i#c$(i'`<Lhb P*:!mT~| b^>h JkQ N>{j$.ek54ca; M(^GARf<W: PBSof|o/m`kT)nG+{S =N&p1VTlEYZVwzMJYQғtKsL1Gl[T%`=J2%݆3lCBle3V rJ5Tx{EDWxu6Zm^eyrVG{}R7AY5\J8&עjEwCVV{^07)czr֒}wm8n(lp:sFq3f1M&wC[ ]:ZES;# E_JzR=Q.6/'MsmOl$ǽFԞ]vž9yy?K+vMN| ^73a"//rjfxxzs5Tr9 t.Ls]­īiYsL)5 chX(eǜf*G E-.p5.t%S&O܍FDTb]`9JU]XׯJ1r>E/_WGZFX3k B$dG=g>a#)j)' LMGK@5Pl#QCjJCi^ZEm|jd<%ll*@qi?a~] Qr"A+\qSW/Md~RFJ:*2,bk44FЄf" 9[(gG2QwIM.3G((,"J0w}{ B`14u|u/;iy`,C=@p7\9} #:fHΤ&# 5XGZZf vTT2fv`HOd)A\1ϒG^P YԡX֋A 0nLcQ19{t =w:^ftyF P;;3c8lqY4UBar;nHcS~ `A_ $<#̗(H?}AFO"2Mw_"[3cWRn~9}~ 6~pzUSW#?Ϋ"2vH >d)b@irvxB"D',ۧLE7) BAV753|C{<-!7x )PڑRgd !{6 '=sNX r 2: 5v2|`~B3 oDnB!0!1il{StCfS]P&&›;M9:Y_WJwI8Ng)p=ɵAE UP`t25Id K%*0Gv%/^]-I]_ EC UŐXРZ\/VͩR`G@??8qB'v44c1$[sb8MX (-"D ZIY$ K*Ep\poAl#6nyIhUI MB=aU)ѕ%?u?3j@֣ w?W (ɋlUFZ"U" gֽ_lMxx)19nDIv5XPwf!5*}M (f&&#SW?gN P|5)4^0+NF6+-I=KF+>qY̙CG?\%mojƄ x)_On}ͭwg ԴeZGmw Vb~:EC*c[fDWnAI1%G\:;&}`lIQ/#͹s«*^S92g*u$;N Pڐ}P{S 7{3Sk)z&:g,E`D~Qz^ڞmp2@q{(v! 4jˆ1y *l"*$$y \Z5h'`t_'*Ulxc )8RcO:\b9 Z0i/QXQ\0F? ovM?; kA|[11JFɲ%]o&vvT'7PBc)cB~zeT+ :zb-4>]Swm;Cnx.\RSC^dSM1KFDI1n& qtٚl-[$Ŝ$^bMxn93 *WgJ}"7Oz@SQ߃X`X`4Ҽ -^wu(EQGŎx"=}Q`AJ(N_Z*3R#,! Q?E=Eqtw8Lp!i/3Ef\ (ҋ3;rpEA>HUq{'Vs5~)q:~IrydoFE6,M'\4H~ido'wm%W9TUpZ)}^ P}Hb?LxX-ϩVK@k}4%*!X \SX0_0{oCFDWӺ(<j>6~ (`1Ml2Au4)?2QY5/O=?H40M%e3w|_-z lAc2yOzК;`oxudϽWbwwo°&rK,%qMq_Q!P O`&zmi/20(XO}xJR]\oQ/ .2 Gv3 )N/"E:74\/cwj3sfKRbxp[–$.qm,ܖ,yydaqKT26qO#-9.?>f% ^J|ҦF7 [iG%n:Jlb@B˽AWt}jGp@\q`BcD1u/r\ZS"bǨW[,K6C8uICPlxC9 #$ J{wC|eTPPJ[raW"u(|Ҕ}u@#ս*"jpyswє5?J Fe9? U eW0jy_Q3UDsq'>qQ$ ^.MvyǾbia.r@8kR=.sWhb;rp\6^# ;W_ ljp>MT&*+1gFnH%GV8w/D|jd6B2;*MH{€2P|2K{B*9WPݪPAa\ !g~0S4c50a׿w"G׸BhOX -}Z5RW`ґZ.csŜw-!&2& zd_Hh: b>ZjPzCh3-~%3qyi IzcT]FYv.$gzr(?#K;Ae{Rl@W9^'L Pr _e.yV;ȎOqz7Lh`;. U} P$ nJ@G E.E@7)ujE IQ_Q#w]UXj# X~>ۭJgfk2|0EUcd|"jBGdH1'XzGy(b}#ӟ0O6 YuQ6Im3M[/ ܬb'0gYNV$Le!h8}Ak0"kKKf7?f)tU*T#: 5XE{ueHd`5OPcFqwy8qa?|^9KM| ^J6w0i\5'? l%f(izD'I? ROav& Ez?o;laX zGS1"&Y)3@}?"CN1u:Knp`(\~ۦOAoY*1+ +A'P~gP85K{c{k 51"jxajo4h=BP>|RR*Bs|T,w>gbw\M}P0D2sH>hcZC\(BNJV'cOM},^~ϗ"cUϗA#t*QK 9Y}3FT |Bv\51>2)y,7mfr p :v9N`62,=-p0!j?Ho,k7I^6{ tRS/^6|(8Y kDx%:l04]Sg$;55t>4un*=m@ RZғ&|+Z e v %Z6{I?TH~R/I> Δ 4%܍Pz\U "r F|kAѿ79E^ cxu]ؓFnE{cx0+Q1'o(hZ)||,5jhP@f UcM[Vvg;E{E_V{7_?-@FA"<&(wgMy:~#zǀ Lr{0{ '-#z% ;\. xa SQeP G C8&$62V1aLibϷ_&ω?` B}3_۪z"~pTSDTTժ+Fk-w5ڣ֞ga(%-Rѿmw_Zyî87Ud-Y+Evݎ6wA(WH*l_9t°zK|\B-&% nX"[~gԝ+u Qp\H F9FV݅59lTih.WGx ,#H C&zb]-m7 R+d3;=NڭM U7^`@3n"M`oM m;B.9%mqx 4<,{ uU5 Tu5Aa,SuKIgGXu>XL?T4^5dEѥ"G 6Yo8O\ u; . ~$_ _z&-*F ȡo#<;PY=\0`{q{\-_mlEtnMOhsЛED_CcNwhl;#@0m^PP%9 /<KD?].OrJ$@EM3<+~:b|{#=;V $ͽ{m$u+x-O(2@^U w YW)XXZ cbG~Ic!TGm5b9d6K֏Ky_@a6u, aZ~AsԇUZ3IBϑё*!(|JZk&iy< -ߠ Smr\^C2g%CL>pD* .~rS1g]$m 7bePTv;2OG3 Qk @-kasFv!LMJF0M{'R+?fpW+X1,>з51 ]n6s.?2MU 7MGs~K#1?__6A(^bN@ D0= HST~!*x7"Rd8Fz0*Oڊ 6bbX jǧMȵ>(+J`sSAIjbҕ]0|n|g3(t1VɦjwByb'T/[| ; @+~X!CJb=^a-+AA'.- ْ dyǁ/f7YCtb]{ 5`['`%~* SmFMX)>%"~ݦ8_Y L"Zg4&R{L`FB`!]~Z|u&5 @Le"#1VoPetPYiSBO+ɴR0W9"g|] }G\u'Bމ%u#bLV]#{Nrp%rϛep0Zuq1y+tV_o Rlxoo8Ib{ ] L" t  #<WlmJFVȗ2^bkg|?tdQTiq='!SQ uN=>  $a ED HvY{=dQJRz?.*^[Ts,4>=G q">!N.TCs^]կ5)53}A 36v]t5O*4I[a,Bہw|PD N0mt;>Vkג`Snm! bJY;2"[j\V. 35jEaS7z7 +WT|`TT&pˑLu/~Pmy}'^NzM #M0="IIvGɧvy.dp=_a r,(G<2gÐmV.I896p :OF^XGìi^pt2(tlDdIXM}OK-W\&;}q;<9 z]4Jz4WQ^v4*ֹz CE;P #M>6A!N3yrVK1D* u.eueDCD* RvY08I<Dh+J8-"hu9"jc( 61R(i=2G]q{ ,itHH^r-#IJ`+E)>yh,HM9bs @S8geˎ|YZ 9WuuZ`|:$Hb+dmGf4[9(b2})yáyRRTu hNB:q+' plsWtyGT] ms1}&PeP^"HF) j i<1/r6f<;u2/-OI27_DY SJUCBzZw|x"kY\9k KIU@C]^( neŗhciaa_\Yg) WPfZ.h:fE?>@ m< ']4 +-5unVZڮej5NFELiP"'PG882(!'7Ӑ 9$[_PL{<(nV_#Lkx;xD"fJXYqZu"o7 '%lt/ߞujFU}q0$?,<S-}&}Jg2zEST{pM>6~j BaKs_'kQPDe2N; n6L,gdE=#SWnB!}ruVIpX+my4s1ya1^.koJ2&bO{Q! E@:}g J+}F ':0Bdm+0&1Y*C|BH m4+9eho^[5_fWpAW tg$iQ͹R9 S &т5V[]w}B\_j\|U.#GnsAPm^_Qc3^(@C RQ[%ėȼA#>Q)(e*ۭ| F.1)!K55~5oVc8ƙ9x$M)7QGtge%~N7ڐ\$qOMY oEy?[$}N%eUMgqarz\*ha/ }Ok/,ldrfF0E GNCoG2q}@x.V\u.)ڙkTVtU1I~"yg|BL2\od <82S*Mv mc|ҕPB#J58cBu/k|7Gc!+>hwF.&+g.&F,an,??9j>J{q*>I 8Qbcycs*T߂eO0f ;U_Q'K7^Fsj :~%{'uX "Tag|_%g$m:J/HO ]))MX8]Ck !)N?UkC,1R__d'A~&s>~lMC8zZ)IPBF/Y^(PU՛)>:IJkv/Y}TZǺifcD2b5X\?rN9Fϔro4Y3OśFlaiJ zgTi4C.<0o=uYsjj&O.,jb qkz81&؝4,k\߀Q9+gUj:rq=QV-cj+EӋ K}2Xh4gR Hu.{UO0f/**!w`~?D f@g:/p  *|gr}#b(X&\[ʟk0|.Ɗ{"piʊXe5uj>Y AZ^KMF{F_ cQbG)LLQdrL!"b CTqm` [2 <.!E6s;~:NWYR/g4W]Śf(Y16I]!iE.Cr99 /(SH}1^>&n1fpq3cWk<^9X%$LLWƌL^)VT(OU?@ CEb :Gl%/E0]\<0tS1 > ]WyPiʈt4"8l#ƙͯʹmT(nDŽN(\zb9-k ZCq>?p, "<.T;xqdFH:>}Q(]JOB6H.4Db/.>-5KFWK@-`زb=8Ò1  DznOECAQtILe &0%-ΖKnn)74}B1c+LQbUWFr26En\TH 'z#+I50K\ajߴh465qeMg7)C4\yuDHiы:0uI0+z%;-Iij (v* H.ud|)hUeɂqIn$"x1!vְe` 2=bj[oN#0oNjAZHx,Rr(h ڗEU oDMW"(f7?z**њJ͚SktfP@7W@ŷ >ST|X=q@QB}@X.5]}D2#jl܉\rh k\)peʵ%cFH59\λ}El?Tt!#L[=0C3lRA7Hp=]L}֋)[c96U޸PeFIeKE &N 7G%GWy+EQbhzb2}QQaRLaG>#M\S:B\?vpC/?wQ$*!kg^Z:ˈ`L5l7\~Yp ,qdz9taQVJ= `C9r5{JS=Gh;Z|o5xj*>|KP!2Ufߐ[d>qjHrTw]e7) ?mCJGS{IxZP\Hz&T/s^xb9=VQ8$: %ڝ - C{zEy͒$TeGT5_j. &߸Õ$ BƽvXgWr ~vc5x\X3z3i}JL.]YGa}$.~Yo8-gD^02JwM3&šTHE!N`@U5 `%H0 6( :P-I\Y.xv] e `j]me]YJxo1"7N=b`gα`>, mVF/Q9*_snY@u q&_gAE6d|v[}Čk/GD_^g#$3ZZH$+A&8af4+ eO|n9Z%BP[aɨ 7/t7B\X7bUzPA5C&~k̼=0`g3kW[!V`7.P^ \̭%c$z"\8/#ke"0+{H<ӳSM1FPe'>1LR Mrփj]]s:xE9Kڅlys!X3SzCt<l W3Tr<1ӳH)+@ܜ WU-~G x G bXqE$8X ,b+q*C2nL#=~s+^*Jz}ܖ%q\ng"Xīp4XpR'4MGKoSIp6FY" 9t `dMl/NhuX%0P’jVO3po7[  HF3 Z8zJ qe}0OǕGJRrQ"ip|qBDWFM5ECx%Ihq$C.a6^9\0Z/D\W{Ģ5 7H[6QafqMAdqX_.b T pmE/0kT1 | u b(wR+!~-0fS#fUIЇq/}"}NhbjwVF B.OT[y[m(*N&l,|(mEFin|a?2/iEdCp+hc?>)g{=,"ONG6@Z4"3̽na2Wv~e{pیlO[2lmVAv)E  2,K>*G/6v-DmM RUwa \$9jB%zi4L4%34|-~GtQlc\<lƿfC{K(3eaHIRk"cyQOH2>Bu?P<Hj:V{eT=NT.8(66&[eMla0c 7+oV5%}7X~(:|E ׂF]ƪ-WB*צDu B!f*D )f4Rb lie͂jie\d3hg+[`+fh|بH!+k"6*cj.=v;b)^\^S(j$v_FIrn9'.7`m>c3е}ZDbMyYG; u`z{Mw X;  P5C< 0s`Vg :IpDbJOV}pU~UdhBcA%*G A^M JC@|Q%ǞP2p19aU*8jNL<M>]%Vl^fY,rD%Ml&NIj]g?zc2HY]*A6XX -n^@zR*,$:t"xO5tjoX"/Z]ΚJ-?ZYef)L&f5,-V!$J/|+N<1nGq;md&R`U{t @wzmR]\b`RqBm|yeXo~*~l;5R˻rjX} :\tKZg( 1c!Pzkh)5fC1&.ShK~H<Zy!|v_&{q,`EĜy.adO;Oxa Xd+2Yb1L-!DVyOUdK*L{6$VX+IuPoF<9$:mAc!| r%e6Jyd$h="&fS<GKG-[ U"k<1jy5u]d&a=Kj$CD%+b3o^P2JXɻK ,-,1,<d_SƟ|sZ$ / Wxc'~"8Ls'-2&>=U?^5BuZTZ$&v2m&,xt="tm+'ckʆsr3-))w(5TN)st=%#{^ DPDD.I[{jz$4n;P/,DVkS՗R]f*4Q -ld~6;~MMstf*._wF%*=lv\4~AeJyKj%BO@bxxKڨ M)2D[Ol0E 4_\5t6n@pVWLOU5/-5"*)21}cXa~;&:g=&NρRH=&)viYIZO&RחL*& wIUV=FS[2{M:oX>Fw#u|yy1 (UE' j,} XfdX| Q3:_J \)H5;2ٛk%64 ,s]) q-|U62{*$3c~M7n0~2YB$ujm3ޕZc:x]W:SmC>\ $0CznܓŚc,v676*, x2]z~U~QU5a+/\LP0>sJDfBNlH]t9h]4Z]Ӄ Pq= #7$JL=jK<ba\`kJ&v{߿b2 |.o [3<6TPv[~H;ؗ|pRp-{X'^^t aZU^8Y'=iK5 |E3%W.yku,|8`ݘ+N[Y=5{ʕ0k*UR#=<vC`9z%umv^?v;;b(P)Ggt$f?&m2dnylcJyY^me5&cbmldqZ< 1YSrp!V{1d 3>q &Iw7oswI,'^*Q,}MW **#BP=o-G{5ZZs4I&bq;z@j5a>M('hwz>\axR/hl>NO2#puU"eOwakA1EZv0qBwhJ#hxK,_!2gkrKmR>^"mu ;KZ~K)SJ18^k&B?|Br^r*?`3XEI|}w SVK.9<$T/r sk%5Tx6+O:R O p'36vםS@uu}FjD)+U;;#21WSqgt*}q-|S*J(M6R *I0!#$3rfraxF8d~.~y#RmB[;M~A$p,2pw,y-J~֤Iiy1zEqrNrqpMf++%I!d^صqEo;}8S/x^38ygLdZ)"w~!- -3ȊRXa<<!O.QU7frgx0'X4_-)_0 |z@IVov-2+;ͺsѯ60u*R<̭V`lK"P xB S{ 0kt}}=zŻ8܉: \m%$]=KD#1gU#4TN1 1L[xo!QX}a>I4?Hb0J рy)Ljn)u*08LI0Y{%ln  X#EZj_t<0[]Y4s [оD#H9sTT$U{Csݪ6mnu>wGq#}F[[ZF5y5 +)D.xJ5`[T[1^4RZ6CZ`(< (_`:^9afϦP i<^qEUz2O[h_]J[:~׹Bb,+.zv5PD|~v)`0&9 ^Q 35DDEy6P''!$(>?,\z`\tph?#5Hˋs_Kl&@>klJȬb) =AoY;fL e8~ czөJZ]a\<c'2|f[g2'R?O$l@ HMY  ,pIݍ1fp[e^Ngodg|@!K"+:8BWeIMY$l0z{DiL@ ݕ&36?]`(U݊Yi|/-Gcڈ|oe!P(4Jf([m9zz$.Ci@}€6׊K\1]#MbU*} v\ϧxqBk 8dv#97!SUyK/`LD $H &Hl3oOvmrbܵMKuy_.  M9e4W54C[dWFŀu٧;L`J'{+AQ"x/N,+([Vw5kqYTw|nm#8vYмR>+S@+vAZy%J'fuZM}&qP^RZbnx~\N!80m~4bvxB=`Cd"NoZ}-9k?#eAj<{d.>j sAXUpaYx]#bg3w +!u gBM{g9@]!jH\7s'hr8J`s gK$*|pJG wReR9vByO2#w%=i2>m5F"'/Isl)yipCr;RBpό?(E6]ES.J%&7o}1}3,?e@tM=?eǝ  "|^Ï׳Q}}:dtFt#8wd*g9)Ku@ .T"2:d61ɺ5A ]?2pYy߉.^:sHw1n'V///O{Z8k< #+E0jO#.|? ~]Fȗ1t,݊ջ_xOr-uT'*^ʆm^C6lsf[<Q&tJ$? nrb7iCj A{s+Zg_.6 gR(,u "7F`v ;l _ 9jmw-fl.=j/T[ E >պoBe];.cb}$rg6rS(ro}a hBq q\,ubO1iÐ0\qp1_ 98Ej+:ޟ@(HsI4KZD3zE*.JёQ#,JGmr4ê ՈWJ ?8M$B_BSExjDH_`7(wY+gZe6Yi&"GFj;no/!E;(P*h<yA ]D7Y7=($iQ.Xnl^h|Pc<(.r |Ajyfi.5I~@j|C~F8MF+v;hZf7L(mGB^+Xb[Sb(Ak.O\28a_9E)R݅+ͷc11\C,[r5]73BBvbG,Ai!@Ti0cĿ ؊cX1\ | Óo<; >q!~a RDk0Gё+/ \~@ ±~Xb ǚȠ"G8Zi~lZQym74vG G#a|D 4*C '.B27"N5nXA9!KI"e>woQE|) Sk ^1iA*"_wŝ$| 95ѻfM(qw ?16PY=u?mрEk,~9 =wy#w?*wZYc=(FѼ bx#|({'ӽ!%1=,Wcb_N"b4o8FR{l0Gy Ccv9_ܗ Ag}yza4Q#='=wLG r:&'0 b^&cx\;Я!$>2)Y"'A8U oz~VJ E6};ILSHWC }U< [J0`Ց `-I8 s =2S|ڡRt4Auw Mk/3lHnP9.:%l=@sGWˤP*>-rFO-0J^Ƿ%~` pZQT;\&pa'5;>+v+q×C+MO;#sh ECt OHaNP'6>]d2>=V$^TC8FƤLc=u,Q3DOp1(.?g3uH/Hl@ Sĵ 925TZ?/V3G9!HDdӊF_2ɛjQ nh=fs#>[r^Wbm0D8AsE,=]^%N_<m3bΰ*nqP܂I)}1(}@c-<X5L& bw>@kqVv`.ET._<_gD7)% LnRۜJxR ޕgVk-9G%/ 82vQ HٚBH":m[qU<LC l/l krE0G`#$nQk&:'!v %)e@̮X=|?PQ)|R0YvTI:;&)Yc|gH[]P uZ$aݟhӶ38/1DrB(+A/` l3,(Ofҷ;Qlp/LiajWE`eRKqm$hW]i:td2/X / (wwzzJ"smuOYidaP|LJ4#J^m4m4!w`d` [nm49 y\xsObs>'W&ذ)Ry) ^=Igp7tВEC^9*sэNf DcdY8dZ+WFg\OW1] )zigS|!F.5eYZQ2UN&wWܼHGh=Fx3lcu)Z_S XA:fY)Q( 1?n6%o/``&Mn;!DNG$;r#!H&fl8?"AJMz  3\ggs;Gg@}afhj"4 S~\Ds8|'<[(cG! ?5,$ȍ;0(er8DRH*@Bs+>.H[](M<9!l-*5`FK"tT jSGL+T/YYhIolVy M */H]R. R KWJ<sYwHc /L_Ry?nlO9%;#;;{@A/?ڵ&5Qx0>PM-cԕcY97J2 +>Xdmr9kV#> f%!z`Iex)Ma':YuJj{f eDg(8nn)khT  S2Lw@<<([QT{9C]~;eV ۉx{HjbmCBHBQ9 mkC xK]s7dY`uxLTC v.;  Iv="xOf@r^4 C>yhMk= cBR",_07E &.HlJgI smDED!C O@ ]~euVy nz5.VQxs] ]r,A R}f5W5\>T `* yPׅ͡,9I6s!5+:`qW? o "\ !> ^PT^opGgS!-BVcQ\Uy/_Ǫ""M7TR*1*%k,i %IxX/t[D;C<K]t!1N28$ K CX{RWe`9{֡8OGUT7 2JzZ/~URtU(?]JVl2[ͦ_pYe+<TZt ~Yn#.#O p?_6,NAyC5pOX3Fb7;óGBNHDwXFfJkrwJFo{m+7tJTr\BPzSwS6wɘN4T)]4E722 KDQ`zRkN}zEC['&QF$vln#E|78+p?df\gvGLgJGt(gŐ>W M*Wj&&q"NkjYb1 wiT"[yK#D =} y;ܱ6x;z*59td\IVz}jpS9tm 2=pvƴ P3`˂J= ^E  5 i;&BVe][0^h(Izt3fv}ݔST6li't0||N[{`ptGM)Ӭ~v$s5e=vO'O4u! - xBQ:OoXu \uKJPI'&Vx yJ=ԭ)2$;wz^!aH Q-+A}Ij2 p{ +O? g`?6%(] )T nAbtl:Y?j B bQ\T4|_&#",aa"KnWo΀LēMkm=I?n!X :^4AwTBJxj&iiZ9#!k&f]WkyFkDb[Dd_Vwӎ5 #8'7,Dr^'x/'jE9dZ~kj !7 Ӕv",C1&u}NczDnmTȹp(8EL <x39FDF3BցvFZ&C (# )<8Xx }'!et"j5)Mby{SqcW.$7E!w(>zNpKxLM7@ޞ4[,3ujnX15uA@/c2btO(k2.3pH&>D?eGpR+`M3һpڥ@h>X(TM&oZqrgVMQh['Wn$ݜc/_n*/,$ p bw_ec0a_o~&dA|p?3mA))sFt| Qo}`- ,pu"WpC*FxP!w C^%WR%"33"w?4tsKHy7m=,g.i? F٘DKPc,x~FQa}sc@ŵwRx8V|57!1,<1m&.is"_tgn{\McesKr}pq@ZYfI 3? s_ em^, 3^ۓ$1XN.sV]nbhHF!fb[uN70S$H"vWSE2'Ar+D%d[}6b]5']p`*SZ/IYbHϵ4ԧj؀ń|fox23IqN!MDfx(XqFbV@6smmPr)w}lXfJ)kJ]#OTTW 1L_yI)'\ѽs@'Y0EJ$ V#BBF#o[Qq^G?)ݦNO y|7*c ;+G mӅ$ O_gH WI#[XS:YWp{9ΤlhmapiSvn''v_a(m#`tZ/kk$|\\m9dbx8vY7Ey]\}1n~]4 &q7IY5ZoԐKǡg>Zq(d (x(WW+6l}? rBFRjo6k@VȆ\X[Lk9=F$Q7O;cЋk#Ѝ!Z߻¿+< RDTݽ: JH{B `2x|PTݒJ~elo[aqpm_7<; WBU 683~NFx'S2=NliRhΙ|w:j \6j9ў W' $Z5)zc׏Ѽy}Vf;qpm|ղa+ BB'^ 8/0`WfW&oC;dm::DDpAzcjdl=_1q3 xuA{UD%$Ư ;1/Kr߼)f@S)W 9 edS=#%l("@iZjv&]y /lhMlrY)=/.rRVde@'l*G; (:~nNtbjL~9-|r\09[3ElUt*ł dP_ZAG9[7hSƜ"-</'\>1uV=آ D_u]\ }Nx+b0 +QL/+!  &EmGP[|PzrdMX\zϓ]Ffȑ ae*ieBg 0i-d[M9qA&Pf:`px4Ξ ch#o %w^Ԇ+m858a@+D='YEu;-W+=.|`D8^iH{B-,8<~u9MUToHk DՅ͊J"Cܿ=Z8u@'IK=urO~_zh ONG.`yw ;ԗd]a}cwx>Ё^+7hj<+&Ll[0 {mox'hõ /yC bhafA MknfCL+^ O; ;BXj>ϑ)< 87G]O 'ϵaTAq-/ZoyMc9ay8z)1ުSZ8n _kN(1(viH6(`[tq&w$ 6, "=L $XBcRÎ7AЛsXdL- A: 2hG]$'+E 45 1-J89D-ó-HDGv B70ZA]. 9Nai-+~I3/72*Ie? d5jN =NTs~8t@נn Sj9<kN0iēl!OW  -yFiOM?,Mb~/0d\@uwf6S BM"Hɉ4x}e28b 4/nj\v@i\#RUDh= $1ѐ )prG[tD7.uKe;isxlJ}P\hY5<*=54graj^FF|]8B_U'!? |}I lu 7-ֳp4UK!OjPYgP;k:N I|(A+_RDly4Ug7&Bck9E6l|>DXLto_6X=L-όK(~*c@i#.c {`n5j+DiEQdC2s.pkqUqOz]<.f%"vQP$H>!F=mM %9 /ZR GO/m#9ABJ*v~L?D1\'ZMMv3.bUb>ȍiCS %.>mR.2D,f(l^ 2shR6j|—HHiF&&Q{qzo9z:.2.Xlo+6Ӿ {V-[YqD=CC/\T^Rv!wiVjO;/Kb>En 6*Yy;" g)`K8NgkeIKLx\MRY#OGi%2uwVK͊cU6dj}X{ue[Pg 6`qi)y~l7B^X D({@WʭIQ,ēěk^;7++țDH7?k 53\2TiB7 q`tIRu@)`ǭtez'B N =!x!e(PNfZ/gmEG9eJA$1dL_Kd'#{t ?l?%cuIAdw78Yw%EK.:1 ,@`x_o{сaBYliJ|?p4 d0H<+O|_tJnp&VF~#aVFE(OW^C#~sJS-Sd, l%9qn8.s%hJT#h;fe7Q;-K((9=Ci &$L`=M`rY6#1ă./sBZ,T9eh WB9fxd C/e4Cye3(]fmZ|N ηY'~({<3=DyDB ~ [wutxY[K٤GY&Ճ=rNBJs}FO Y qTzLJ]|]$UJAVUXqO("+`o"}]* #9}{ (CUYu/'_$"S ~g\6'wS_l#~$_Vf{DV Z 8+7G/Cj-H&~;|e~:qp[,Cv-j`rd5H=rT qJ Xnp;f]u9&# \t5DLRP_OWh/5:KV|ok;]_*.ڟIC˦R0PNPJlh,8ޛծgI8c2SYفO}/v`LKdqv["6!x[djDQ*ۍPgDnlNo X3+pWoUbsBM9wU.coݗ#i]~WeSY9{LsJ268R {7/@elқ^qOUGTd\WHw(U5q' @`-HIgN*xkwpӸjndm04sأʰOH]f\*80fύCA30fR O sZk[%EaS.$?1*HWǂYFY{yGs -:7db,h]c[ ]SEid:r#LV&W0XARKDk5hBr.Hlr"q޴jw P)mYA [PHoL5@l8ELR' ,gZ<2e75Y4\bhc_=,Du]a6fگp6}<-<5P}ܽo"SfOJDX 5xola3R.l@Ckz|,>N23'h,aD*ڢ45af};vU>[8leI,kTiT {R 3 [c#\hw@ڣOL|gg,eTr> ̗ ܾR&4vӄI2!0470k?9pk7N>Scm.j "Ua&q4W&w;TR`U' XL"(D#a+Dk~YOSWV\B)=nd$o# ::He19>J5Oz)R R!!?u y/DǴ>uE-]-2c}QQ`Ln "8}4 Nscam~r *Tg3Jh;ă|ZROptGE L 5b?lrbd*\4"p r%>G:0|geC2t9BYiB[vȃ.-eԍ $8T.m.XIFW[4S 95FONfSWx<)0lY]N_i%QI9K{'X d Kk?/_|< 2RnVnGt`rZ'%/^% ֻ 0-˿a7w3A*ZB$Phۭ { M.48E,xKqNN+1 P+*6t{!QYò g=ON,7.+J hz `w1 iM5c3#}LV)?l"O[GqDxbo,`M˗n<bI DfLLyHh#]Z4 yqeg2E`@\T'1hx1~9p ө8!}bY/+" /lBʪy=8fg]1ߣXp]uIS,Fz%Uc(76&w.qAo=XM4 0Zp:3qNM*B:;dVzjA/OA7INGXIO_W5s0wz_' 9 -qȴZ7T<d0S![j>t;,ik 03"u ""DyZ+ 17B47]<6{f?t;4PpE2{G\#‚V(+9T3[Sn|"z[$/& Zk&1_?=<YnCWE=Yu!|#"|Ts*Wxv cY|Vz([js@/\-AR D>)'9wP}l3VbOfF~GgOʪC8drAW)k^(tMZD 2G;r3PzD%&1(X.6 ",Xk H@Xc u'-!`*XgB"{qk%.Ŋ#m:e`8+ NuX@_uM^'_[b\bƦ)mz5eD\>`X'!7uz}=խ&Z<3KVgFT57OR|8;7,.E6x{OXu-? ? ?*gX|#u[*s k־.m-!y.(hT\6~e]xy %ə@{ &~ފmۚwqDan{&Ks%~^FidN_d% P3sq>K#<(? :B:H'zGݒfNB?#a4lOg%.;IX1Ct>]sl>TAO*֪S}de)L9D/Vy&=r=uӘ`KR~_Ibl`Eht.aaJUs6bc%O.Q~l|Ay]0˄DQ\c) 4^ hdLdSſ6>;k<@ x-A^Bc")cB=@!ylxS|*iWT^L?kunTK59w sXl\ϢT <*)}bf{BJ[_Mܜ{T%jUX x6;]CO{4J)nGHe&!N X[*93 [.WN'XhvKQ'aIjH[O}llձN8Nw_t}|:o>Mq]KY'-ymsi3$2kB)`Zy ( ~@mm?0V _mqjNn45#"&,oZ[[*έ ? y5lWLi;k` O>QH0|]LIU8CCv\%/B1Q p.o/5R;\3M]\cPg*6B& (]GKrOlGV<;p;1117/ ns&oȁ!`esLfW'0ZWb9_rn} +hDO)Q*R/RJa3% Qϊlāwt W-Q),u Aym=F5woI(;F{<5HuH#  P(&mKhndK"M 1kd'-*[Fac*j`zHxHx.It34\uZvIKb 'L @(\\YInZr$rQ+]VqzyB~aHUZو!qms GԪ@W*M6z5Yϵq!p7*U&B>n0FJP/l !1VRNXms׵;o lr")%y$vQp 3H]U+F )*@9<3F5+d;QfνnuOCͩ{:CR'Ր=l] Ȟ*+b2ǾTJ 6x[uج0m}7pjv]DZ[1a;f$p;8t67NR=jCo}r<?[RJGzmL2f_ &tb6KKU2q{u+L7*. ߁J]&PVRJ׃t3gB`%, AVhH{<%zل|]454kZQ- Ml1f#BpxIkY9+0D%%l#Fv)'f֒ڰ4_pњY&0GFX*s@RgfIN(l,Cfy"t:\cս5һ fO *c$k$Y4]\LV"tg )FƆ-+|S2C1?R|>h$R ~6a*('(u9A\Wz@1)\gPt*OEx/`5w.^h3h ](/EO`I2 v*w=G8 $cgH/ 'mk9tlyCmGlRmfm MyǾե8iԸwF|nݞ~_h&I`Nd..xMD d} 6M-lcO;H0I]-ܺMG(`Ur4} Wqu@cBq!)#7PIux(%YV<ο"&d[7ȇ,vH+Kh&ta!l-HZ|vzק^09a2mY,2/e,ltO,M$u;oİzA/ \D'lwzE]Tk}ݹwR]k2_[+xtUn˳n1VQKjFOGJk@n0_3kd==yhlS~J[#zpUpDL=sv\7/,F_^t}qL(Z }&N0vvtyh ]@RZ;OI#ERg+rX_3{KunJQs˨vWsSך!$@hn#'k,O`SX $oyWi'~}6M UPAA@] wJ #q?c8^=@`EO ,B6ٴi]ڴ6W$Dsc *X;1Ic2Qe^W }DiD}mР?JriC*MٚZ)bs#v7EA O40|fh@Ca۲Q4b5MwnrA6OX^w#(B5c45^͜:&@RU_56@97?? V1w$c,E tč}#3Wlc_OL,X =\/5z q`qһ Jx`GYu*T`9E4kxasZ.Vuk3J%5yT /y:Nwfْ?8p>Xd8UP[2.#8BS .b\֧MA}ТA;,/b&h)ׄQvujLg_OoAl9G..A )<փS@|څ\+kx:#k:++\&5gOs:E!;%VkVar|))% T** oƊ% z)P^jAp6{{ MS e(DPʐeQ@)!LP PFANt. R)EBI{[&hh[.È@9'> X6#!qRwh>t.^tiB &dċ,&l'Uo~BO|Urb[MIIF,SX:SkUKE7!5me]-I_jֆq"BaROO#͟*B(Kwb}Zgt88%6ȝ^mr#yIh) ׈^q% \# /Dl,Qlg{$ G:uT6 IHQ>EAg(LC_b3'ciˀYH$+8Vc@8\@E`o^][ )@A oY >8WTy˯EIa&qX\+=,P F Ѕe_Y,B)8Xw!Xnٞ3HbB AfW.$7S )sNBq٤TFGG@`yl=Dn HtRAk} !%a+:!C Y]}v`q+^FWUn(QRUanAIk3W-tQD\OA!v' VP], 2p@XQ<#39E %a@m". UB%+ ?'?']-ۏ^ -@ _2,Z|g֍@[ք0 v%{# 'x7 EyS*NT<9d<\"ihtXaB)%#tX E1w!Gd/k},s>v^%՗^j^*mi$$[,nT[|SN.7}/{/%}X6Fr37Z_UK[s?Fu4|*]v hd2~D]Ae^khbIZEBð"RR (xl8**D>ks6`w@|mΏjET`!ZukTVC?J^2Ur+slyKgrsu"TP +%2$3pC1W5tF xm%Tɕ\">O_Ĺ{C%g^ܳ`3\4A `ĭ@\+ a8@P^/,ϳl[$ ,eu!e](cIO.7H.:8B2C&Q#qAJt;2 }R5xI&NnL+)"/um5O-{5 T<WN', IW}JTiְJPTzmxzr.T3^o1Sb{Es)teoIIWHe0ku N~iF2g)+#QeyxSҳbuP| z,W4$J'bdq V((ވj|#: {ktIi89g6c<@kO\~< 'kZf< 2',Ȑ &QJY4`o(3 t~o:PsY3Z@Gbn>>IDw >@Zk5mqcE`t"3(5><WM EL w?/6x|3[˯߂afN4]@~qoJe?twuLEE:pCrSl`N2 [U.#;ky2bz\spi~R 4hc} 4(9)3yNuy6k(wA9wl eP'[OI$DŽϔk?g}:za}XXfjD3w)mUaVf\hڕlV_Zܭb<,k IK ,9?=v,! <k(j0" S)wFƞQY"V Z J@d% Q F2i.93TThw%zK<D8I>b&K5F.N{|94;giI1ʆW=*a G?v3*rE]( bW&xD{:`4S @[@#چUJ2&B2dS:LG2Ch " k!J_YrZrp?* 3tpy6^] LNz"ǀe3s#sDs58u?9w[[)$2,# "8$!\^v'$qfB,)95([P*;(0IV&5isgS;UVǾeG)/NZHu^]P}Ss=QHyc ǢM w6{Q4'enVyK/iUT QX51oN.| I$x\(#-~D^ԭ !  ɧ :NiAx``~sI2Y~*=Ncst8&- K] *<#>zi`R C/}WTeB=hq kx8hPRձBk\4qV=:9u۹ ?}f`=xβ%DR ]KC$<]r)gBfTQ6;rd\_@^22>{ޗn|9{Y&i_d5iy$t@R}0ni B 5Xo fI1i6tywvko"PB? Qd!kVkWwn]vt~}oJ<2cؐ|O`&Dco tYGrwU;La*n 9NϷD)3p&{A'nrQ+ stS[і,iToC$hj')'+bjwևL1ժBXiۅT[Ҹ#;: l\+$x2 B=d_`@^mB~YAZm]jJ*2Dt?(LOr?+'S)EV]D@o1/>o[ze&_F&>Bcp#j'F[-0YIvUJiV!6V-Rw(#Kc4:$dQa` M[?Z̎ %F!k\XG-5e UH 0xjm4m?!HUT e0]ލBQXT[L^ZG:gIrDNo'2%6h#D~ёF=CZtBeIɟd t^>F)/He)[omQkncߘӞ{*{#qOtF3~W;3[pQՄzcܸGHUdYu8 \;K3+hJ:.v3/DY|Cc}fJiMIvJ dnR8ߟL3ijpҰP}*hUbB] 6<tSUHPI<Юm[f&1K".(U~|h'c8puJʃa{tβѱ wpm]"?ӗ(rD9PnUZj\ Tφu&ё.']}9\7Nj&,`\8/(Xi_1tvsďNb]u@wm1~xpNtoz{,HPybE=[w JR:i]\!KI>s0Xt-5>_ Oĕ1^4j'z;(Z=q_WhpVd1Be|RR|R.jL7P7e6A }Y. hpIvS]ۻaju(/-#~4# $pbDs!uKs٥U= \/bÀXzm69 a+=*b- 88wvkrۡt$=_j)<6u&.FX?mkȭ̀kHV$>==f9 8u=O5' 5?F2[h7G!dK͔%HQn[m&sI_eWa0~/ &CF*U,Df+hEoT2Ug +3@;(+ۧ&y3[Uk6uT D®5r](14ک537\Z\V XLKw%= G{7dYsylPI^J}F=O Sm}ZO>m7`0 [o@dUs`ks?P~%3 ]>*$@dc-l;]2-Jo|bdjFJ eskmvjl|bE'S'2r*c|+>f6JOV#19nQ /X2+ߗ5,B .m'Ckr#ktmѰeh MD&"r6NF`1} jV\2g15%Fo>~:KLY\ o|RuvEn~ej 6Do&Q\4s-^vb)B\=Mti| z =Π[RDn%{+/LU)ß~L04\D=QskK|{eh,a}jOpriЉiq6Sp2qz=&K=F>#DJ@T@,n QZ T àJ~Qs5am4[ DD oZbp|% E?@58b1Co vWA><hI?G Q?W,?.kH[o O}E"!&!Yt|4 2n;vߨ0Ӫ@F":9רKE! ^Y*[YX;_JQG6 sQECe_{TS9ۍh3j"#QK@Y:yqE=0|#t2H,,f*8Gp;w- *?j'Гo'h,GXDh))J>@0fcN8^MaaP M{SziJ#F='x,n3*"lc/XW}4G0*Qr-ccpl <\dB4ʱBLWC Ea(hQI"I /=/[$ $~vP|tDi ] nCu?I#D2rC;B zD[PlƘPF[pf$hPDo#Bt>>oq;G-ul:M983UWShTd=^0 /{$?:a^.7;Z]w4ߵar'{6FENu(He9KQ"oR}wk8EL%A cF}]?Jo<m7@yebʎYâY@tH`:Ow%o FP7FLg`PbPKS!/ A,(5%ʩ|1('H:Vmj`}]v2nh+oL"j3ѼlT/_xj|)Es:~)*#D­p94a'km{l/>V_ L9@;iph63Khu,\l*!;#RX_ _7Od#T,ܫM.D iԷwA7-Ÿ=8H/kz0Iw?Gc8_5dF4p|G@ P__^!FI^ğQ$ [VV,-c\^$ >R&ˌ3H(;uR~wB}9+O^{A@ >±'$ ~DD<=&Il%@/O%+}2Oǿ[ cL7X`hl4qHNS&1w ^|9"M3:)z mLHJ\6y1o|qSEQ)GHE<r>[K#0qoV+s˵n\T'}0z"c"OpqdK5@u }/#K':rbG"X=TtіL56Y3HrϿz# 8[ #/!~Hi]>m!fP& C/Z*5eACt68~y0GH&u"#á"E,vǔ.&Y7^kP-)CTjK`x7\ H`}t\Sr@Q$+c{<JXdPoLekKhb-(s ыƫs/t+]AtxiC]rwg28m+XYcLG]Œ~Dk@!bȏYn7XO;R^_frykCw9Gp4%]no Cis=S 9i4$e)F4' i{e S|VpPMX3D(>Q[x^/6C q.FnIMSuQLfU=lcO=g <AizN_0K;DAY`05=<2~2S;C{  .Xu-`dahNzŬ{ q,˿T{c]R P.) ?gD=8D7 D<0))2Vو`*&m:6 l~)W0E41+y<q@&, wY{P!tQUbr FHX[̦<085t0Kh0HbQKh&Rc-M.( '.}U[``IOtOT >1`Iy Sf [)eE Wa0jGG8KBM{HTyX? }A1QS;7P"ϱ)PLzy\ y"k cZ˃ގ˪#kO>9X*PBp9hLB5Ey؇<iA1z$x%;ej6b 2Gr~"R3]o8%o8ZOco[ËSmţ<WqWaLmh܉OMvpaT%5[3H|8p21h> Gn *P;cH7e]7:X;{xw) Ss5ETD">v\VQaB7lV KeG>yo QvODLRzk[Usu dl%a&Q&<|bB)P 9CU/E( b۾g1,Hypu(^Xd}ޙ>nw]^ 5rB/ \SpoTb;ln Ty5WD*G.fv "k]]B<Q&aW`e5|prHnS&7~O*V'|O7<qgx@zfdcAN*m{hV4i9}C%Kg2]T=4ĬqZ7))CY^\+y*?ESB8` ,:PmVr|bؔ/T}MNaDbsr8E*-Z$T3ߍ6EsrX3x/bZI%<6(Ȉ%RPEwEZILA< CsB:k<'+W^+\JEurvޙٯu1?y0`6\ D6+O4d 4 >L/%Jx,G[Ua? !}7 ]k5qZ#h rHxzpk!\o<=GGW gJa TʗCIzb3[Q2j"-I.PMtC_%^K| ly~)t( B9Kk56CPEpFޫq§Nmi`Pe3] :?T2_0i8Uw S[YujXtbЫeu,t[3p^znGhӞ{~ cMzy׎bD9Zcg0ҺLrIJW{" J&y7e!7D!4 cKs:qXLl;r,3|uB@U8 H?%%ZS4o Ӥl`/nIe`]&qOcR _98d \#e,{ĉ"cjL=^[Yg}rv]AA!?‡ſ|@bt^xui̾[l` (v$0.6R- wׅX40YeR((Nf)߀$ IEWeS wZ\#4*H̰ ;@ly&R "ZpT%ʨZJ{ӌ;@7Jd<:`N]S^,Z^ /ihQV&k cd Q2}u eCP{^z?OZ*8jh(z|Tt1]!>[xDwmΤ:6uc&Qa^3:>/V]HF7kyd'0)*S!;U@Rӧj7[O6/`[m@+܌_wMbmT[RdC0# ô'w!3icT9%t_#~E\%9~XQ|Ktd>bU:? ʉ[:Q$a"8 pHx3E"CZX S? Dz`L5[5c֒@p[zgIsʦ#}m%ŶJjw^$UxF;-La+ft0y<bT 2KLD~pZ?'mdiOuoC_Aao,o5N93+x/EX/R\GGnhu;xp1$AtPgE"w;\W]iOPex^V~r8x@{bU2|> TD"r?W_C&0TV X hu sZi0kR,dHPug  z MZ,WmD= Hn 7^;^ ;V%p Y! dNGp$ HN?ITB=>[sE}@ Ksaf|ƒ6qs~=zGa{ ԧUe˔(| sWyjzV3Ʀ),;K'o/l:`3[F?LZWSL%-V--h>iYxu:@+?L $a"vu/miT}${.{ '4; /Z/ )v#oKVpn`6O?%>#DkEn'Wdd:j%6eg-d 'Fg,@fE0uN#6JMwW@aެ ` x { hU>j@M(;izF ?ZR/ vզ^+/F#e2.6.rZ{r55Fd9PXtlaD@1$02 UtY].-~db.8.6jV R\oIE8=@a?s-Ct RmLn%b4YH?""bh[_twc<R.zpc<5sI4M>8mPbBR44~am[Oilm7#Sb{,!O@nKx#PnjZߴu3{K .GP[l*5zώe~$ql wI;xgcL \ 9J N _. ; 4zEJO\ 3\Vh/tuP^L34"Em 9(?Vv`C}UUvjwfQA V}|n3" kj4*T:S "Ζ#)xmWbU(*6ShT&/!7aγye&4Cu2lnVj7iO05M6O\Ow\7Z1x4@uMfIJ&Gm *6 BznqIv&* *T_7Pu5In7WbkMi#a5~1T0?:6.{?Ƶe*M>lJ{y$eGIC[HB'f̱Og8@Xx@;c+R]Õ|Z;t5a(I-Bwn`\aPTͺ j zO*}{z3P*3KinvZ= Rcl<9G0L (A.EJ d@5`i\7!գ7^ <_#4ȝq-r.N@cjDe+%n!߇!\с]5@MXxSyfR qEEPSfmuQ q8yxqY#r&;]"X)TNIdr]=7uPmkj/cN.z ze>T# <\FPSWWW3N dYz}=Y%C0jPu1PuXڇk#'0p{9K'~ze= F/rx;f<@23c\|?^VChkI?M@wV;:7 =2ϐ-h$ 'e0I[uTCxEz2T4_y5Pj\BJ U[IDl{.=ow?L"Y`?O%4(hlTWXOkD ;kwSJkU/Q$dZQJn~Z(HvrOP]h_~z!H;w@chm?^-pb`>cX~q[AJzrj*'TA+vZg I%B={< 3n pY t_M_Le̓>hM^}0c ~_ @$Nyer"Z?Y#- xQ{%tp11OEf͓g3eg !oG`Ծ/ /zuK^T83FLP\Qy,Dw#Tzg<t#TQLw=bzD]όACQSʼn IǞwCy1&M\6i( N0U3/ ZTf>i;!Ӻڱ4E].lJe*q\w+!Dh9pO-wک?FQ(gP:C@90hC,6"by 0Gzu\ h'WwHBU ]" <MmMN12Xj6*<D hH%ҥM9 H%Ƥ1mP]r}X]_E[ާ!dB^:?A(gInőҀ7# *bݰ 4+X|#+Sf u'txŭ   GݱSWm[l0s1]:Ol[@L i j DT!p`Oޜu[=cRŨ%+i0j' ,DiK"y!W?'#rLEAW+3bn2:w 4?As%'1^;|&M/(`ִ'=\ݒbW '8X] U:Sz'{pPM44x2β+,(zH5Ly*Ek3~}I+H"!a*Mg}s4 mxDc%,WFWN ;f!_4!&XNwה6'SRWE>qm45ŧOR~d'a[A s vXHC.UaC.XҦF6+ZG:1KT:/CASe3o]Ab$NH~pq T<- w(]/5,{HgU AhVZh{Cڈpr1e{RYO0*VC|N.Yi_q)WhmSqխ"!q+aT7ke} v/5`A) 'tpt_`FgLv.||oqPj] %o" B~kA9( *+[R<OBBD54^T{+~i<m+ۡ vĝ?pDV?4Qr29ONK8zeoC:}Cb5 'Nb[pX gfxpV\"bތzt22Wȇ^-8K}Wz14A9AA(K&xl"aV/ۜ5)>% DJfm!=_ Q`&l. :6s'TCq 9)g%oiDm aJ00p &XN[TmO7>_ JUV> xctz*g~Ù̦A+C!4K-(S?grp00) `4t1t,4;RrG-X.;`4y #G)vcSlw)-!&|i|wGapmKAE^x6w`Y"9S)@l{v \y_^ެ/hjac{Q0.t@ZfW$=zR/pUKJyhf`) ӿFA> >ݓY8nJ?M0$/Mj]?`m#E{L dv`g !iv?#fOW<1#JAR|OXY:*vFJ>pS\Zdd 7\Wj $G1wpk'8;+;Mw%!7Q4+N5tES]"Yp}L7[;6TpBZ̸a>z^# g{f6-H&w׫c.O$FLI9d ,8~?$M,tkJP\'ܸqq+^l!O\k'$A(oUH~[VjiN_lD75=|2 0 xDv MDȷ v3MC|UrwM@ejz2+ .MƱEi l$ =T Ss?|#ƥ={2?:mdL o* l]25NIJQa; K9x˾719)6\7 !hZ[Qq2B}i\biE]x|Ja*qU϶J<L/Z l>0U:euE E>0aGCL]1UeEUk1'MVC_{QT5dT&@+ 0o]zw^r#KgF[=Txn%[cqgzь)6+RJs\ǧ%|N4 )$9Y%"+ p1=!mCGU *h$?@ozAOT 0EɓQ1q%d.:~ BPv `^Fxyn|(KB#SUf`@Ѽ8fuTTpq\ ,Gvǂ6w7u EBq 2tO_I8,p:Ahnz)PF$GU U>;ktuJ\q>Gil3Ju&i\9ySqTHˍJF23F&PU&s@sS kFӪ= *fDD$~Qr-' h(r=U{i-D?2TZݓ?StzG vE5>E%'9ҋZM,pW A6 \g3.1|G\/]5Wx/{f:p~ľo~Z6PR9MrveԩT)vQjCS%uN'%{(U}-cr\ILZKAv5<}`R]`.jԛ%3{i6z8 10uC>r҂O)?c+_) K~N;<P~ɕ4Q˷l>M \kŠ[7p[c~w>-a8}ۤ)8H{J5Il3`Ȭ=:X(9#,F1n+r5z(A`W-! v@>CPlsQ6((x_I ~nvH&Κ9x )va0iOAFhkVMa>EF%u#W zr@;(H3D<-'~BÚbr7>0*'`Uq{H0#oa?6kYmE+Vji;D˔JD~RT ʪs&~8գ$e:hu֦r]@&۱ h x ;Hr" <-$Hd2|D^6"8w3K Řx1."ʎ$ .IlخÜ;CPzfO99HR NW;mv$?XFm#T'CCWmbeik+a`spFV(P/%0XV9@q3%I%/. F\IɒUo[b*fF*5& M"0FKS{o9*oG! םaJg4|B^e@]/Xu,BQ{ ~}K.K Iwc0{n/]CKMQ}1 iBN ka"9w99]S1a&-AQxEYK 4'|IJ7. T /zL. +(%Lх,H{nE"+Q;d>hY&;0N p%)B[C40(bV +> OA_Rҟ9܂͵?Gwp7Z7k(#0`AtwC)^R/l{zJ5L(MHH  yPuO8 ayK`3XF+M|f5$w݊nx˗*jZьe0:DInڸD?g~+\mJ{sWz"nMA'1m)r!t\4'fj{L\ Ie G<).4:HMV\HFE&NY01I7x?#k KJ5>2eTзH(Sas#5/y32%[^ C; ur1.!7W 7>o1B*3`!ѷq,d*6F&YX v?>,eA)Ud=L-.w@{ ucg]OQ7)mCxp\zyi9JO< #b3>(FB߁ƚ5,Anp/ ="g32t%2Nzo_#j_a L j;-3j@tGL+|)*g&/?<: CSV(b  oCh ^ Wrng8<Y\LhN$<Ԧ :PJDhA ozuF5 .S#N*Q  v j[ jތybHclV)-D1 5>}ow NbvoC3 @ ]SfmDXjstlL}EEPoZ:}2uZ`K9H tmR02%Y}mi|lXoy|#tl2YF"kQio a}+|z:EDli ^NM{fFtt blo $A;f4 SIp4n/+|*1uXc7V*E 6m#'qQj01L8^֋'$Vi/%S{9ZMlϵnsI/>jK/y<ɛQ p79Uj|_3sl(H|5:! 8E3-U1dF)4'RCDߙY8 qkuP3 >fg{mDh9ep+BgMbxn(ߋ݀).^'X'(//iS @@fOtCڎKCA%nWzP90h/ %5<)O1^9uXb7~o"_c0$bK,)3 -n-{?{l,xe$XVk.4p@jJK؄&4yM7ĸBj #82([tK d(,{+Wv96c+"2˕'ex4bUGrS$E2i9k|#2T$-*9CłkљmH~rT5pFʏvd507Ҭ|U[KtwCExGW;VhSdV*Yu]g2g/ R.N};{׶ywm>j{hO /\nR&MEw0`u;*|݇^mz^7ӄFxM?dڧvV% AOME6>BK=MxP4e2C\Y6(/cq)<.e|J P4`ڝ[Rݧ9*,nJRm8G!1$?G)Y^Wʕ+Q U) ȣpQhKBZspb?L؜_K}l# _EÃesHO:zO-L2Fl$^B6BZ3HC9fzD 5 C}nj}n?` XB'@?!ςnSv1x?vG\v} *dfE]?1:-ijHITN`[n%æYU=iĿoe}mD#L9]؟-4C!) M` b1Cw=Hu/xFKIq>4:aiE@P0 = |09Ew{/DYԞ oIvTARR>j'+A+1d"8ad|.Ly;1S-!Id`i"_a i$l [z}8mbGqq;E4gq &XR;P^?Ə* qmQjVA\}o#!7=#D]451{@!Kl}NY 6Q ;4N"AMy 3TDm; <,mxSs*I 'Yp&Zv8vN:<{uQO+G]sBmz~ǵ Tt]mf-Y6!Y#H Vmzk#"$%JAL[*0QRPMMk n&nRR5TxVM NK qL1{B"l- _C-PٹKg3 BAlh Y[NMPg,ark}n y; >T Pe9;s 7L]w kh(A4v^fJ$X9:sgZVmHJ^Ryf &>BU-1\X^L?ʖL@x,xGB;EQ/i>Y,Xp r=U$I HT Hp\c j8j8m0~H3U!R^U5rQq)jfhU&VVpJN nQX1${"3i:38<ϺϺYwL֡X@k 7kS`Q^1QMsu4\{ MT}zzy HMax>TbNPc8iv7%I0YK oapwW14kCSԬrzsGEl8}4w)@on-J^{|ԋvE§\m<;dTuE4yO`>FDU/HnC:Mt=+ ʅ9l'AB)DX=Z#=~S*Z:9 v1%>&Gq9x{XYA$yzWFzJjB{ Z<_ P3 N*dC{GZe:<npQXV4) JP#EQjoE*6@ܚkgu& $L`oWNrT!F@sZAN~ a>??"<_}aFsɌ'  yxPicҿ;fX&L+]qD#8U/9H tg_L`sOGcDھujQgb) Mz\&]!&Krld"oLi%\s52} 8h>JM@Cyҩ7aAMR3S#||e8h=fm/y&XV_Ps0BTLxK 0__.cR[3|ӓ+; e.B7T@CBJ4-! i&sX˧  Av X]bÌ{2y9`8'=k /"P,#S!ȸיBY*WI 7<*P* F]2m3)S5O(m5N}&|n%?Z @|BpZafl=J~&E WM}W48&91EFfmP9$^^PūR&I8ъ+@ЏH3r=cԳ/Op `s?hOĮ I~h^/(1^*TYykI@dXfMtutzeL&"2yXW^+e3MYIH&39Ci[ 2n@Gq2yo r]FfHwicqV::@1bd.TpWA_DL {r'SU+w8&z>CA~j70|{O#*vbYoR-]j Y99X#7P< ()af ;hWk  X`,r4QA=W_4bRMjH0m#:ݟ 0e3Mʒ\aRR6)Tr0:O"*Oo[ ~!LBd4CqъpY.2%HN ͎FQf0Wy(B5~ bQds|zeG$F|ߛaOa+AlS{Ja3Az=+vAt;:ba|٘n'GB!FYZ[jy4†#)`P}/̀ s$kkyf_z9I|LlO>um5{&FgrB=VKS=K `I54 xFldKù`|"J'lX8u2 i5N I`¤qtՙA' iEu/ 2}3p6V%pY wGYK@? Jc]T` FWdČ_{ggbXwQyXIR-W4zpRNFV\Ä {4d9&w*Z,J*{@{n6.p1(U4V=u8]b-Se56-LE|yF26QUkoL;t_ RgHaVT ?:u?:bu_ĉyHB<^)QgVT[LO8ѻ:C5as5ʅ,NbHR"%X3Hw(ϭmP\ jMC}FCoU |ɉ"/|rv74Al-%2G= fq}}HN==i.'y8 CjѼZgTm<},`2FC[Y8~/)"v$v!`I'ĸ_TR!Df۵7[ǖ+gc{o DkR f7m|ׁxJz@xi0BH~cay&564fh(W6UF&+{ }~~E 9M#Qx:x VN^g&W`(<l;oB`JSB6J[Cbeu\ζgmrD*in,qgyf@p3EH~iqXm@iy!JPmK-v ]eEJ,EM4&z&=\~&m9:9ch lJTi'bR^r oq(c!Qq^#ҞeW ^;"L.>'[;]v10)eRh&{C\Q/Ep[:fL')\EZE6.Kvv7ֈ6h#IJ7t\Wn.O< }c~0 7* FW3V=^far?hU,",{e\wnv-V3ѺYQX' MX~4$ԑzۀbCFi^~H^W{Ơ1O3="yT2]}&-CS?> ,ozr+/<%r>eb-~wK$0{߿(9L H]f&q :W pG_n{>͞#;DK-Te@_s-(]<:v}pnrHB+ڞ(*~4@cPvPvE3C(yA^cnL_ mh,Q(bwzQI 4?uyڅqQI<'7F}6Y={ePRjj WV1#U_(e_/F=?HN](bM>4EUVGA8џ lչrS{kpX$~o-0ԳR, V_I,|hJ33Mj;'[-woDw<)D) ( +5  _iUְ2Gd!כ !qM9QN''WGyFBl 97teZv`9O{zb8ˏB+WIS_,:pFY ʞ/0<Y wzUUwpKjZ_СlWxf'wf;b#gTfZXm1294Pw(&_E~'_:ó<X&tl%muVڢ?~Iv{yRk^gXUrak.$j^ ޿ D/!B=TpU` VvGoojX-S1`&~yhq ҭ1Rx;`SwE\*gԭ\aƭ͟KH91:[ ,՝AauY |yyTЫ W|^AbG"5.tzp ]h & ]dejWwmp.D @Y1V`&hbgt,1EcubjYd6fť*lOzj)NrxHQc,q !4)[as+(I?*I'|'$J >M1{Y@ "<[եy\־*8D&4P5_$\oYdv`[F#c$(P3=3w qN>p +dZCP-U9WɱU;n8`9,ʟ m[[;~]tQz"-REV L TҖsL(NBmOcaca sUni!8[cg7KtR]iƶiSTu=5Wka< /X={&`?L&}uC Lq #AXzA X&dsr:3vb pߒ79;;vPt;8u}LU0{QBJ/{nt{Z )o[$ Sv{14ZXcw[lic&U/?DM<nviudD4w*CRCxfY+DeU$TV_Zg&q=\QE0PvG8Q 4fUvbmLc-F"E">? h|7:JMDyPr~U\hcei(DfvVj 3nFd>ce Ys Dg,TFQ$?$40!up]2Td, &AZdY'Kr<:>W"][?R;8 G&uh#]qv\}#| $ %4 t?NL^g^|VHcYgϱ=*1Vwhуbyl(u?q_vx{6;zH;&wD5GBm}r^>9uLi2(dn!nbW;Q9Mddw'I,1OR /iwq) +":Zj& }YXwT]~b6V|!e4# QN7T6 X* )]Ac۳Vh0(~~"f΅H!W(BU]'8d h| h H:ygA.S!ziePA11GIw`|ƙXBkqilp`{k&&8>DxS#(.W q2V9Φ*&C2(JñVmy|nI]+;($fM 1/%Y+r0c,|M^ԯa>Vz'#t$Y>S~7?4ΑW<qQ0 NZa)_TRnOE <I +;g%ԈN:5)Z[l5x9.ClK CpD'MWf6֚ sxR[?Z*0o!fnLik(G@,/QbO0(SUyXU![Lݭ^n;AYlRjEiL@/U_YtyzĖ6u~rTnE ?^_-`…wzC z]!/cӝ O. dbOj'%5&9:xCD'XijEK$O@ `(! ǽJQ jQ vs/NxItc3#K B3;b7}.+.qy"Ti&VTnjO>nh +61F XXÜSȞ˷<i2Kb5)2th@P"BN;[bjNyݤ<@vRsX  4$ W;~`d6L x"[$-6.uP /ifX){h@2GY:'nCFArN*0 "\ /fW\+M^W{7uBW/hܟE.kq-#+e6X%SV^M<&YtiӄpF( kT~ax[tmw-J`+8Uf1FzOOG9 &BJzĈxT|4q-#6)FX Qz|ok-Y%'s$̲jwўbT;. ])v#$xnwrQRkQ-̬YD[m- j+~ װ7*}W>լw2XPs^VwZ:2L%d|nJyQ>q= =Q nxp6iUOab)_Af+hoN,;>M?.HplFz.uؚ K.qe; 0:/"*3@M~ڒc$e_vB2:j8>:,S:y.dAeR* z;J@FaG=;* 45Tx'@jv]2}(]ngT\?#F%"0e_S?-|I 972 #S"<Ewk}/l:1x,%Z1v҉F+_ۥЉ_me{ו"5 mYj]{R</)!]Pq/??V2e@ Ļr;+_>ECcDy) t wtw| ~[*@x 67Ŧ. '{`^`mbf4%fl6K7E3Ɣà\g,A 8X #{HvSy<q[#M]&Qh|ZOaAܼ AZ7e>E eQo9)( FI<}u/hl gpƓy_ -kUka-+ 9%L<w}4iMea/kU*n@)Pz8qUl^wMgPu9 ;@ZMDrG,{l`-Ќbi#D'\2@Oc` m7BoZerpjFxc?hvwJ%J57#E{.ld?uӌ8~(4;,S 7[@[WNW׼`m?{i m:]|&UOjYhnP=WGa|$!R1auG8@]\5OR_.{`TO99;+go(L?e<jy4'}Lv ID4GmGh_ n(9~J4*,,0d)oGR=HÒ,apVw2˟=v[bnz{!a:~-$8{Q>'zOkPJS^q1Uz&8Z~$. y?3~4ЖH ; YVC6K>N#Wyp s@Z4 fcK>^7? x4iPlrtTYi#Or?֦p|,T*`N4R4 QL00PLb_^fFu\5]?/oVKldKj!Gfd\f `1@]T ]ya&~\nt=7oE0K2-4ߗ7-)?4(<uvj!f΍ ] vh3+R+i< { #xy||q4ڐ^U 5V;GEC\A_5NUxk$0rkfG3҂q1[Z2zB$! F^LNY,9fv" 4< >1 2Mo G[oP۷)?J+EƞGn7^( x(E22[EyW|]1\++>lnJ'aq%UfzC+qeKMq h]p?(&-u@z#̐f&nYnOp)I5M0.j6a iɛ0k%b8#d!|4Z %S)zNjқT9A* $sek1hO$m.;_IT_$T$[ܿLaX  q0`/# |du)Ϭ\<-UA&39nT~-H~Iuhȳwt0^"i۟i z@e#mk)#5,Q8[ 0i[fρrlĥx%-Ȁqex2'??9V8 E|czq<]`h!PG :eHTwSb-8mՖ"6ǹmr  M&o,TSAy07anPb`՞rIIP;|9=Iq|)0 J[BUD<*7&`GWTć6c`4˱ȜdX, ]|nCV%&)ÞlD!7E5I(+~9QAv]yW1u8R$ e~vDV.:/Dp$N%h@g hϒ pBt/"o8XN>:0C!gK0vޣy4w}L>M1zBT3KX6eA5"IlvNl8g"{c*JDE; Sx QZS.DH\l_]w=8;CPW(<oE̹" :.Ď1[_f(f۫.z.bw;1+5 /?n G6"UGnC4/2Xb PȄ^2aiF0{Cziayx){b0*@Uthջ#$Y1*,wF1d$D@_a7W0x/QÝ<"tn**W&I0vI nMhax]}7YP/C ٱpâyi:0dPlMkIeR MM5 *xU?sy1t"Fɺz|1;`)fֱuL c*@69pIZ#zzXEW&@=CBA7,ViNRQ$n%OL.:t:)'SK#hbK'/ e԰J4!--<<K;yHo]*TJ$AE80pAv2J. Z*"_A,f,4k @3cnJ|`gc25d}@5OFz:h{B&?mUjoi?b}%GE/ ,؂SDH % _;L1)y'NMJ <G;}&o_vOD& F9([a_&&(l [^L\ZNJ9IygI(Vـ]&=Gt8,]K+@Tw0 Y[5R z 0 Ņd&?GW6FE*qA&ޞw-ph/Gn_>xp ż?rI>Ք9ǟ*sMIt<+Mv-x +)k/4AjG W 328 ץ}@,m 6ns9sOr_r=iz}|6nSPDN#C 9ax6 `IlEqx0FB+L<%?2%ϢKHpTpX&`pRisEJ am /5>F51yY ALk1V$:?:?DPf$i7b;K}l~CӶBK#wts_;I Z@RW;#F rY+_+pOdA{.0UxPW\WGl3NvD>okvL}T5 I S WQIr~v=l %yM^=TNUҥVW4'y*V\8gfnC8Mc&_[W)*3K:? dHe#V1r kFq[n);u1ZRz#vLP8LeПb^hpxGr*r2^senh},pBs! #v/#'դRr:#tuo@29h-Byb_\RK#>;<; u#H LRpIe(uK"fQ rxi{J"u=\z&#al `x/ {Hm&A-d:W|jFZN~>jV4%~[ -:QwX{ByneR1zݳAy4CQl)^nʼn;uQJ)2jo#|pP0(4bep2Lug&7)(/Qnwrs1~ F,(آї߭,Ol9/#pIQOC3 c( w5ޞZE)sPbU6~ *ioƴfpϙüY'='=8gGC3_GFVr̖/5 ,JYiP $: bWOwrQ!2~d2Fr9jfUԈqEzql/=M-["iB'OsrWF x5WmidfE]_\h#n!psvd0oV/ei׫|PDHnO)Y\mpxiFw\C{" *P;V.i7vyg@<^2uhCar;Jh5TI;S ޚăb5X QQ:5a'6 x85GNbi88@B |KafxPem]h6I}R?WADKr,$:tn"TG~||޸3&t>@0jbW^nh$mtce3,r;Vi< -#)F=h`O k/?Km-{O_ 9]hBsз4# eV0:n9OCx.b3#4)Hf*Y[A/\w\twaebSB5BQHBnosazL 6:V0 Y9HO-vVȃJ)=|ߣ(pxJ{HyrV3WK-uL# *OABK/d=eOm 85\e9AEvA:(*-_+\*t{}f ,%'m_>uQZm,R%9Pvä̓~q7;)?Dk:!/]}8IR6rl)IRTO2/~Vpxcqs-DGI[D=N}[' FRzj6pt2ZdQW=7< W>I4h*KEme;r3>" BJwMjmp˳OSG ;BACp^߅;9%A]2qMs0Cn Iߔ!hK"9$c$pt+5ӑ>B 3THBdBOEhpe {WfD@d #x3 ݒcVo*Q/F~QӉ7#-Z„^\x==#]=y[YTF7UpҚ13Rg̎N~Niiʯ"I/bSE-:R +h &Ff[̹sPS4:xHH$t"DH<]=Z;&w1Srq ȟ%7){؟`@vԓ!;sw*~G[e=aKbIջV"2Qޣ6ylSF'"}5v*̵ԦTt1>Vfa7jhƁ"W}bHFDP_Gl?&=U-}[qS4")ؽxs\.t|0R1υ|y|}vAt +T+$G_|X-{Bnr p,$^yrh{: R(PC8VSA`B6OH>40UU;288b~|~d^>Ws'e?M=G/!Fv˗#ofCA+}4ީ'ɸZYGCZWeY^q si1?!ne< "4P.TEqj{-x I3 ?Ô9$nv߯<,xte3hX ,%W\kǘ,uyZaMnU&P\ nv ".35?~J}4qC8SwjZZlIB]@;R#p /'E+#\rXWJJ$[CkPW¦UHY2Lϲ}qGyY:xD1c.wD$5u~~sGշYGJ-]4#)1j:5SZjuf~HPh&pd 7j~5/r-%4\lfi6= <9]F!lfҙM03һ$R@) ^\=UWƪ+\[Fp:H~*sO;Pu`\Fv3BJvOUdLs~*rpIA6, jj?]}ƌ|xoU4 -EBEVW]ƮE@5 |Wpli L7 ;&"N:Sra #kjڤ1_0f%(nCa;vT(z"5xC&f٫Y'D ^1/@ZvzrpCh1B]f  jjڪE*a<KmɨF\l< ZOT qؑQ{6Od{]1:g.||cX^iUmN"+Bo{Ez09YN[Lb/b"X-$etyrKnYؒD(o{sV Q@4;ѹãaBmqqZ - 9|tLl -8/ K]+c6He[k;؍Zd}sɊ$'MQ]0?c k]US]n[qdi+"_BPY (@N pmq:'?;Gj['bw ojVQACc- #$FZ>D_+"k+\FCPeJa~sܱp*,\Z>]_7D YQoG;J"-IjA0sNJ*"$W6$)XAH9K?.7H9 s A-#kYul Y :էU,[{xG-nGo8+B2<$#6 aDg-XYuO ww jv 9j1}'jPeYrr a.Al&5>n1T-{tfHvpiH'33HśJxӲw1+&  f<$TFvEI?&I{eJMkuQ}*hU>oR jgA]_<XHM@>P`crMsǿ=B|QQ!>Ð@\-! ([.kvndHOXdxq.)qK.)lH*8GE[hڻطېb.iGq6V>+%j L(1Qg K[ij 0BtzG?P :W (Ox* /ЗM.aܸx4#a\}& ؟P=\@7$1+N,:DQC8x0@1aU> fv;,X[%TxLqݳ-+'aԫnPh*#A=bNn{ G3 f*!F>N)Q\ԀM@'.% }5IT[rH;EaAű0J<)Ez-RYCDWYHJ/ jD*,DWrgyw8Vʏ4Cg G 4 Ea0D/rmt_zΑ>q|WRE+6pѹV4>iwY~q 9)iIF7KxN1OO; 8g8:[sfx?BK,vn`&I YjYfʑhŕ9_V`}7!n ?k+geOZuGżƯ:Q7H6&] &e*w"SuKS;t7{ aFi6YfD\$<R/VQ9cwc;' ([\@R/m>_ >@n=6!<VR$%YgXj]G""".bֲ.J{cN5G"cMO:KWkrG=91Y>"}0u4 I~lh=5q <pynm`s 6$D ;Q !e_2ebE>  Qf[ylպSEG>`nK p0;q{{]Z|z98bM@^+6q*Z;SBL[I# Nu,a;z@H&umC(&@pwԸȼ3 BltT!H"P*UfA!Paa1Br5#U #3J>[b@տŵl>Ds&g&\AGs^X%T8eC,t!F#4PG- zT}Aڷit=$`/sl}\lVs vPz,=BMG{gC Og_Ap\*)xJl3~5OyOEK5X@u wO8U*G=0n rpLS,WhifsjZ*xG=blKmvfM:+:FƕYzS#-".JX5,|+~u W0Y%cvp\NB6mElk 1ߘw>N2)jRR'DlI waMVQRqX?f:a#<^rn(?y:qoj-2G@mo6*2.K5VıB=k^;0%)I(Ca9(L2|=f-A+y7o r_ \/Z+x=x2$=<+Ksj)z^P2ZRbVR4"Z\.s#9?h{2^9ɡ~a0\F1Wd?=b+ /buz9jX@SKi,ZyG,sRJn ()F{)(:uf2pFQMS?!yݱ  7?!S`bI0 h ?RK$ϩ=IMOfjPI"Y %O Y / GQ;idX 4ͫ_=70^Tu,uqDG|ET)- Fd *)6%"57Qs~'1۞tOI}X;ܮduy/1QG;%[-Z܅n`6Qy'`Nf  Skn/Oij!5=H%NzFI~Ǡ[h,׭m;r$&@C?chgJOO:<<H۝ Yb|}=toyb|M>4+VW2. ;ܷƐxG 4s*FZqVXr-q oiRsh.0-cY~qRL 8PZ1*j\jmT;o}T;?J)e0%sx5$V]]cHckY$)Sٟуn\+o=4F]2!Lڙ k'F[>]3WHtEG`;˹ޯXiCA]I>Q"rVتeKHt6nF1R  w3-OyxF?(zۙ-=y)~qo;{K|wB]82Ʀc V7>Ydhx}ͽM *kLV5§3H>KDkHlkɟIњeeH`#[E:7 ]Nұ^l%8Qp¤l{N@8[Gyx"-0S@p;&A+Q7D vf3ewo'J-|Ztl7mlLbdvCJ63`j53rـHLxҝ--Q$>%cj~c6 f<Yt~sw~UB?TuZlucxPM8ilt!k9%mrbC{y`U1\%!Wa[m;YLSii)q\7hobшmo,@pw>LS?ɸhh5}&I~6slB?}ՁRc\ x!6@ayzqgpHz*K\SiT=$OuwH=GOE*\l-}sd ]'Y0VYLE,~ai*[L[cGy9o[r4ӭ"TUh,}8|@7 ݵ́I%x$>N-~\1<6>c4t"yt t,` ρSe@6Y JwDp†${Q))7,"|oʠ&DbȄlI0K:Fn|TbҌ^%MA$1#_ DQ| Wo0?:v{~Zw7j}Y`ke}m?RC-x4xI %RvNHd|}MDN5G4!K,&fEsx->Gc4 tIАn$1+}) n|/Dou؟ʞEг1XfMl_Yu e|':k ʟW GxJoA)vy 5daۯ!c4 9~8QY1SUXkPČ A)Γ7<uPq;<`+)X >={<)3uGdFHy(wUק(o+}G7H  3!7`Ovfp#xf.P]@;TqI)6_cR6mH0/nG\//_ @HR{jA\n*OSIuRYt|YP?Y4 ]vݬ7G, yO <iW Wgi\?Fnj9s_LvzMz_tg:*hq7;$">5$I3 Qn)Wo>hQkVu8_Q% E7#*yg'aoU4t˯݃|~l,j Bal&ȮPwyIJ>)F[:۴?ZD;nD4Z!`Z_'#+B/]75_'+҇LE~8++WYEc-:Z{}~adaf|ŌݎPbU54Npp9f[R }wnx#֌ m؋t{L1ӛ i8e{c՛DC'=l֌| /uDOHCmS69I[w?WnE/P1MK }Ny0!s`t0GUDµ}B/q~(/EHL+V4QAJLQcY,ik }S~-uD L%rt $FA6# |_ J*U]OWY`IYY9oѧPJƕ[SWokr|4vtåW}WW,1)H:A:#b% -eYk56RF8^ZQѥ)]|tO#[[4<1*Jt<< N3rv(Fs0n%-~bIsr'QMHV11# d7:Ut\Zà{7 ]jE/D\4al&;W ϮDf,л}}n7ElM_ -41dLE-X@D2|LH̕;S'TIn~څF#IwWˋflj#N$>5=ZnW^KP7;14p|irYOB7e"dgIj'Iկ)eRlBtBx+) $C1ҷK, z BGd72=[Ic?"x4zIi,-!i~y-0sgVNB'4-0}?ل@{pi= 3$Ai<ޣiXW ^w.`5:Vx]ih(r'$lpd%PZ ;BhTd[]GO )U_Yl+l+35=tuM6b pɒ'Vry# qcmue[ + J*9||&}<7;a@*/SSolanP˚,}26)O^eI$%}OZ`d5QR4'| !$$tQ6}uz3GCtޝCO# GUe0c)bw>k9:X]/blFa4bn:0(qR{;x+Xefoh/| :?c~gR,)rQu;j˟*.>Wu<;LB01 @}5)Vkk0IMk|Ti^a"$U sXEccST(vl&V*Kk11S T]S@ ACW@QiĄnU G Yt75/_o@Z22~]6CڦH#]ŋXvo@ =Ê3!nu18v(݅!>492Jal`W" p *ua|m^OϨ2mSbRlaGN-Y<8ʙEB?}9fUD=TW\ñp},bB2(*MfOSڴT#[hnsMs9 KK6OOxn6}FDA'@5`Uc;mo3zƯV|4BP*(Uw̕-{'JPx7 p "=11(ҽB ٠Mi{F>EӁrajfnQ[s}UysqE^m~ AimM:bc~ cH.7lvr C,OM){:kl%LY1l'l)vn p tz{uF u2{Bn~: ksd qe9;_ro4:Ҧy _SI_n%J)z:,^QňZ6]E`jU!1&JC!(%R?5roŸǠ/HRfXd 'b!Cczn]5HuJWvcYt'q-?CT 1KePWR;4T,c',L },Xa\EzluEGAD-@RZ^ r.AavqZ@ĄÖI33׆~"M_;^k=3%' 3+A"RXaqrXc?Lags`Ģ@n@2k?INCS 0I%g á>nLYt?b9B$)/ 6{n}{4dj;8j^v2/_YiK !Ly5r YM)R+gX~F f*P^.۴NNP+ls:I *)Jfo~m:[.'X Y"_O+#i*$@qZG?!}` ;H+SSjXwoJ]Npn_A}PZJvRK``L@mPmX{Ác5 ]d.d\:UY-ݪl IyDbT} 2a/ze9`5ZդW~kYd͇04E>8H=Cp~n6G%j"wb*/+EUFUBoƵw$^;cW[v gݻ~{~uI& zaI\!z`43ERuxWB5u-C: _Y\~teBsJvV\ # JDSɆąQ{\)mDwَ|Mp z\Bu9vI@@tjc&mf-a@UM,f6 GJ2l\_rnlK6h>V,R_H"Z1r]߉H[ '(7 @4_C,S$UJE5i /l$A4Y]VBH4>z  !15A7!7A+~YE~Ľ8vN)Ň0p3g8:OYig$B($qRqQ]="og~މ(:>g ;\kX6Q2۵uwVabjP duiB6$ M2W~oAc9&%J#!Vˈƒ?e]W<s#Pl+C:f*[I5 /JkXo@nIu<Ҝ`=;-aR| LJjt[bM} ,zi@I&DѓnxrYfi-~z[p͈9V/x|r<!?̀ku krzIy$x܅9122G"tVc;ho^ai`h:+01aq8cVAC BEGݠk<{g &z/Vl#MP6 Y*\8!\Dv1u0FiRz¢Io!Wn(Jkpg~H?!)$?UU1JJC)g>'MpŇ3d"{Up>`[DӚI"($R"Z<D3W-Ҁb g]~+T[ *8a0WWSgJjugM RN,([($ 0aQghtn5NvT:]efi]VTRTTUSUwUTsSiR7R5UVWS 7?SPXLYH@AESc X:CgAm<jleEL0i~C2 *'VÙ W[\^XnŦʗȡ\dp̟y~$ɬ \ -$&$/ڗS0KxubSIphiEuuampdruL0_{O$M rd]c1AqedmX9&F]}: fZ2 uj޽ h}Zouw rA^VbPh3PF3?M Nҍ܁h%ccM7Xs4g@AenTQ})}ыG-]EkRFj7dțrFyȜ\r{ɠUuddj/ XXx=TkX+Npmmmwd>Ob4G@4c&s4S p'x]h-`ά.f8*8e-,\3cggJS .l/ʴù&{z$}w=ұ "n-L\-X}X"-ӵ`Ƌl=0Q{:|QlW0U/A Ըʾ,A9(Gl!c Y 5T-O,p9 kb%P?cQRbx PIz*czl`Y@Emv'|zCa"W[âB "y5; l,HC.h+z+PhHYIOQƄ0|\i@G\7B#$,290bK_kK> ъڇ k9iGXCK @;yl H; "TSZ.n3{mS]/,M! G K!S?CNG"`1&Zqz~ElM  cO<j!:/AZ?T7j̽uy "Vo}zsQ WB !%)!EI8y 6YMw)&'?^ݿ6obGRaQa3q\| Hݾ^Xrs8s>~̬^Kj*D07i1aM| jA^Dj1} UXE/D yծ+i,i},O1|[?'d_0 -b&p`,7.o_6?|C)1Hoa% diM O~m\Ճ(!%0o# Hdp\)iXu4+d8w* I _oS:b%Օ8m %9O' *7%c5)7%1/7JFj Ht $oDM8>k =d!'h zñ<BLc~?D\w/\Ϙv8g|-ć4p DC9I%Ax<\]m8n6w78>wD6WU&="-EQM@XhP0lG<|"c{b#2t5!9ҕD`F։4W)ihO`^Q* X| ft~)cl@3- O0"9"8lˆP?9. BA 9lޙ)}m=S=%s7RȽkXnntJPsX;"_{r \V~L*KBF k-G*]U"{#EvQ yiyM!<>mf~)+$}g[msbBv۩wZsD+$ 3%cmqQwe=63^0۷ТjV,HRoJ 6pØ.kv}?i%,CYzVq( z]xшIjzaUuF1{s=N ߸҄|k? fAmo: ZJWFE8kx0Ѯ-Vi3.nerSjRy#yCK@iiO^tgW--:" (.=\($/o3LXNu/OjY]O1& _'3_lTuW^d͉`-7jC VG0Q[sR6Cn>/@1qg/ePK=UuTbt.8}mt&4-4exnn!Rvɗʍd/"Ra. UK7}E z}>-4@xG-*D cJ[@a=%}yMW~G2D>3,ABV.glMk cIuk8V[Rv*x35(@KF\dReoppo0hHAf0I_iV<"#,#YK(S1BO=PqLj1RqXg>YxA{K-]{k&o ql_oO?.l^5W!q.Ѫ%4, C%]=NW9vOpt.@+NAf֥0>eY":W*#5r5è44ʖB GPT bמ0SeA>:uPp/)*/SȊۡ9/$S yT|x{_'O޸ݰwFD({Hߨ$`1>?;"!z[)i:>?RhWc71`'mJo&J`UqTB<>~TRT@,O4{ý32ԃs}D ]+FKPO?Y@FQ*4~q$~ y~'׼ǦrdX_NsWzakbYO{t;AUz"fgv 1VVq8H >4pa%!+/9d4$@J^rޔpd~PlZZ=6!'5c,jslʍY>T[d$J^RIch"_* &b\Wg v5 E3Qu^,bcO=?brnmh#xXo@{= #_T RA5 PQ]o]>H+7'12 +(Vf0bW@&'u#dmI%f'}O; y+Lp6+Ap!ZN!Swhx]> јشSpk e?,v. z<߁m+|+mW$'Toym^ul<#C6>3u:D$;R;ԌI. ':B}bֽpvV1nI}}pW|NAJP .LlϪEodXE fQsjP"C'l HncX^6ZKD]Pq:=!:#}σh4K"1a,bL x [lu}p6v֥ IOC=Gjq,`!w / %~Yhx@0#tgVOW'/din[a3%zq4De^86D(}tBeiUhj~L j^sI_*DO8HfQ`B]KWsP%AN}~aǰ.f;B5tT(,A/bDiއAo!p{uP_%(Od̺QE^kNz/)27-" *5]vr$ԌQj;p#P\JOϸ3Db @G ybͦ-1dtG>}VV,ɳ!v: ` $-Dúc2 '1N݈.Do?* W=kU,'ή;c.Lu!oR_:tOht ]XsCAa\NI[)v'&mL04t3-VJGZSkvL"U$\jD~D<H*85C LdxQv'7ˁ9?nG}ͼ`]]vmlsL] hU=%mFDHF.p,UM!,O]BpV,xm.>;J'M q=%T?Qs<l3n6 f2Ɂu*Z cD ';J$& q0W9bQC`|rZ$}xy"z;#R0bɊ\{^Q?h}%`7j$r S{tx„NT#7JIozQ:J@LRm݇zSooEP ҈Tu/rySnh%o@w8gZx G{tŶ͏&oo.woI%P!\@3S] vu)_[!p8)C[ 04G]R"@'J:=*dlkcsz ˟^{KmD%Y6hyylU8BRK]gaZU@xfOazH@4#CFd { ׂd)c[& /\Өr4NLUlpaBFP*J۽15F`[x՚=>,Va4g+vծȴL09e/ .yl̪}X$UrJNO@da&L]`B<%YG)(/4-E<`{ih[,Xj$YfҌÒކG5B_eTnZ{+M8yKZtC|:/m wrb2Qyu]w[<} 0Rs4XGF`'3J|/ZPxk^A@!v{-R rkvYnj?5Z13 Z,JbmEM <=81O~Pb>U5-6}Lb9Zt*ix(cXK VHyĈU.JlTTGqN,=8O_O_rvg'*PxN!crim[hsu ,8 S/N, 9bUM50bzhm{O+ZP{MLH|uT->7GODZ)  >gX5Hb|uHGBa> :?VXJZQO>h .ahZ3Pi'e(DfE!(TFHjtE x?UV(yU Hj/1GYطF$%}ȓjTyu+~ 1OL+W=_Lԁ_ۆƵd K\&2EFN>$6i@[qOC^(`X  %:wBrp`U2X_^hszu^a~%Cw bA;5< 57@I6 #:}3A A \nC)+ A980A?(3S K>((*9 iY~.dzJ(9qJ@H9k]`Ekc{`S:-#6w6 Q>G6>>:Skjca(,244])q~ڈ’^pBi@OgXNN TLE"=DJF3| A¬֞$6\k mj[P!2G{4̟E_\YC4h{M wS~Wm1o "h6@Vǵ)de>a Xbw$"SbfH%GB??wY9rݓk4n!sw : 24^P+(n~ub#MKmPu."pbD`L' z~]QxfS![x7~_u[hq ǬA`zի;\x#e$ _r&XUF&W6 6*B[[7E$>% 8Q)8Eikp'w';1il.ڟh hq`ً ҰOf.XyW }Uck&SpukIG"%e`Uk~ 's78-O`pbSu;(< $!eT?O P %N&Ҭ\k:/%<L.;L'l"e>SOC"XhvUfC{!r XWSyU&ȜX4[v?1i֯G {``*5KImiT" .|79AU\J]%<U@ۄW4Y>*5t-Ktb%$0{w'tTW!&yBzalq]XԚ~enbXE)Ag?O_jZmpN9iQ-$BTKa#B_! bp9( g#O9e"6LCzq[gY I yʞsS$DXU{WhNht@Zy"Aݾm?N V\& sq Xx9WH-t'~38MV31m{ (os@=A5Vlzte^QI[m980wU(* +0-7ZRAC7{K'.)E!!JE]qP^eX_1y",<cRt\?Pu-}2;/,m^P\@ ׹i Z@I QND/] lTU|}Yu{wCtJb'{ay72a>eBa5o'6(IGn9B/#3)̛ϩӷJAҔ7vo6q{A  Jf@B,W 960V-A G[7W*qbV2V (Sv^ RZ 0\"4d%NZw9!|JJaop<3C7QBYSnb4d0ٵd)EfF}qfs+$4lw/rd7Z<s+G)k%(?@6OMqP,d5O72pƐ.gq8%| b VhuYyRK\22&O0-\cdR3_\I:31{gu6FQ9lF{\@6<^g:o\\EvFkutK2FC,gG#̍n2S+¼+h!HvfM|D.;R#wu//kuz` P5Bet,7m\Y|j^cTl`.|Q]kXV8r+<78 G-@. $0[=~tYN%#0W4I'p*cv 'gRA>?iI*s%L׭ q #0;]Fj#iC?<4Jmxh<3/Ha<[)#m,~y(3Oo1L|&?3QZyݤ"5(a^R$+ 0Ӆٛ D qiҸʟxH)EC\FAHz# i!Ejvel*y&\!`XrY|w̓(v&7t# % MTE 3$Cl&-s<8, 'L2i#ELpSy=7a\٬|ݲZ?AcÛEޗ_\c"COmJcʤ28I{U54i8`,Riz&d%gY%^Xbu@F!!G)8"XNWJc~zOeNh1r߃vOVV$4K9BF'"`>}p:3 JQ0?u k0+V#:^J+b&qNGLp>ٷ2pySޱp/,8xjN&O#g% =..-ľ$Y7,@hWȖz$6@\&^lxظHfcPZ=rŇti .(%~6h,7x^uDzVU}L'CYi1,,U^(X}kzr@>61i&!>Vtl]VGGRYYCNR2g!Jfh1n^G|kV4yuFo՞{{QsXx qrԚ:?[2"uU ?'،ޚcgC$F7Iq\pN>[*;<7M@=ipxErVcZ5$0C@;GTVv:= E2f өטI)J6+c9_YPmMO ƌ /(h?bidb[e&od&X w!`L!)@ / c ,C6[? ^1x*ƦO|\ N" E>.WsgLHJDcs}5`}Z)9zN26nE2Z}\r%K^pJjCunީ#Jb1X PD+<&  xXG˒$xTo$?B0W]kLz;K:&7GNsiePSr?%I3 H[u_Zp^ae `ml{dfZVF@r11@ESYejW]`RPhOU=/f-3I8 }1EMeo 6lEu/DG Q P ja+;{W7NW?jm<. },AG' -,*=`S'~.rqpn>C5?7xo_fZFM]acxYcW.`PX&0Q&E 6=N S/N"p b0GU!%oD+"["^0ZQ,F̃ȕf 0! zISY((OLN- RGHuҠ5u><8;$nk K?_W*agz{tM5A{C358NI@$k= L h9y - ^;n%;Jou`[vVy}V I qRu<ZC:=sN`OGq^Ro3oQRa*To`o3"r0*/#.9 "bO%o @<D:Ic/Law‰DAr_/K(=# 9AGTmd4\-ka}'u]AhD?LD@K8  %,YCc ?LKF;2Rܣ[3N' E@@8A VB :;? :%X:fMavf\W4j!AI$\0 5[A!~TCbQJ4ñ#D3&1 )ީ i?KWCE\V +*-qZXfi}6YqfT[XH: oU1k̓5g:: :"vPgfrt+EsV3^*86<5 (G +%ullpXKRDc8`ƑMAFښҌ_InHPoH,ACES('9ҷcTa c =Ee}Z- :.$.f͡_qI%07[z s7/)  g'7@ZqfP8NXnKz~(<#0K^rbN8 ,BYWAYOjS?D@T,3ss\5p\ؓw[.C .GWCD*Lh,*hPb9sF&HB8Z\jkC-L2@,7,M*Tc2z:#,8Xn6Ab >!o 2bcr 7_K(+c 2aT@܎ze0ZdkO23s! s! (/,< ;T;;9},0G2h8KhQ9g;D ¿ab56? '9-?KMh6DgDW 6F9="$%A`g5FIRJƁ/\FYIJcY{;<;F rـti4p :zel'JF#&9[`nR}ؼvjbo\* B-)cOYjNY5:--!DQ@<%u oX()hD%F5CO0"ڏޚ=-]Y$je^G}JwoN6Bc4zukpWN2&V^^³&z5%Z# S%7E,X( |{TC6(G r(x5t.ԭFbz2sYE 0(9J]+KY6,'͍"N&>0|]GvM'/`Rw~cʔik $O)A% lw}Vd y`rp?;T &fxB]DШvB-%'0{]|0-w',U`-Wn(?26{WǠ{yNbqdq^D "TF@H{2~s?,no{N^:G1'}Q[onz%$1 UN8iuT8Pve#W+1Xb=Upp8mmyV:oKwQk!;D |)Av{@0:B$zRs )4uP9W!aeƪrEY {A7I>BDa͂.L7N! Od˹ ?Q¯c1rS9UCje`#Gzh! ;&!- +qu)4m Ws~HДxd\aR&*0?5C3)= [T( h:OD \[EL8TbB>RiTv LjGlWnk U˦~DN8<\AUksAi48}3H V99P.amz=ux =V< ,Q-`~jU#Ͻ/(OG.3*MUgCO 3*V8!(2D:2N BCHs O:+:6c(W!FE2͑ݱX9/(>uX9$FamtWROCkQ~?P Ht#t%S: 6>$δϰD0ԾѤ>g  mmlH$:Z#clOD5k;#jCCFipxB!i4-f9F=d}zp6}u[kh!N/Ik+\6L3VwlV[jFA<*=&B*Z0;mJ>ZYhmvLC^#Udk4O,=!)st w!%M7n>;%"|`JbL]N!>7L1$6]/ibyhGj]dP_ȇ=q XN;IcMTLnw-)7`7]9f3L[iO}R!f*7!D5O5ZN2+3@G|er |'`UzZ4b.:!Y 3%>?+%_Q$ APtbAFO'+%uuME@R`{xi{>Ӹեڣ)>}]~ 3VLP k#W--i Q ƴIrtd6@6s2]L@!CC^w]YZ:;&A $/Jo.l}DS| q$[!&64)$% mHj}s]fF7 gAY`YhT]LG4X96LCcNXm__"i Sg#@kPOQre.Q 8B4k+gF*JؑZJ uMBzqV6[ |+ c rƪ*~]=;2JA~?\lMgsK,y4=+Lcv[&6:FhYQE,ǹ ym`Ky} "+wqpa#P"8+}.[&* ;5^dgYq 0 &1DK/-TPF: Nf [q˛/d.Wֿv{ h]d[m` ?(& _~O0lRW>rE& * +!E $%NećEz__.f2GKS&&&!,vL"yO+bz?2*g#,xxp;i F7;b aJeq3Iw@iW2e0ohvv\x[Q3nGKzypvVhBl\IGL>3 -I~ߍ &z uJ+; $*YwMf8%  d' y&6%d/Oclwod/q*LePR~vw$hW%7-&-DTL/_lg{FT&-~F<l5$jMe}_] s'&ARSPal 2Wղh1Cr0+R#",8lL]uMHbku V/=BfFVpdE7$B]cvE!vܻtee +2w_W3:byK8/}j۱ʢa_s4V_OI)Jsgs E!1<Tkpbp`OP}7TJR ym . iCgtABJ +~P1.MtM::~?QsWO6 ga%<7pvefM\>_C<8>;I *5RC}.ƉqppLA1f&4~C!]7/$pkI`G̘tvGyt}k?ZHcjx,mgAm_ . W=ohKrRyF w6>w; ) oqvvv9~f2pI1zKeJoe8 h;R iyPpp={\j.F%"~2\rZ^;; jQR.H!-?HR$AO)I% $&3# 3^WuPaKQM,> D.! 'fSvatzB*n:;E:=$X A/7$YYӓY"(|,JI fLrS[)S%q82e51#0  Bel9wWL< W?G^QnJ@j8ɗ #e2hY&KU8'CGYUN57!6}/b.9C{T&Fq,lA6+\& w &$,hE)E*Wy2|?>;AK~=ZA1w>zMf_Jf@k:P9L3Y!8@@EL.eTRn*u-hE}&[o|Odz "6F* ._2v9DpܤRx?!ˮ_Nt(YHpqyЃ!Vv>:@3x+9'8_t;tLOv'IweDM'*D=8z1 3xG+D0Rme^%6%X|nN9-03TfոHp{Vb>d{iuM_(UVs-~s%AY}uT&MM\oLUGj_GJ^09+W9Gj7!ˮf$)1?4FM6?!d&\1.25'vzR՜Ъ_s@ yS *Q,Z.n|evm|$I>l'!VdK:\,6P( ] L Q GwGbbf~tiUz?Y|1S#55 (+97!+*3;CuK7 K 0!$+%{ %iB'4oTD E/9FM.6?&V'0S!E\@23'=,W3H\,@3U`TxU0R>2A%4 ~,O*?k@#7 ?N]]@veOڪe:7Jz>-ۀkcH7R|'@,sGmHLSwxԩ1JyI`Imno 4&2??3-x{Ia931T_V?,:'",2R?EOncUhA[>$aP̏٫ޖ&N7\L}F:5!AQAH([F="bGv+ uZ|}qaXZ}FDL;SshoIX܋bZq!6<-\1V0V5ww&#& 2L,""?}&/8YT@N49z|}{y܉)BYb%cF '&I(VHҒ c!UW8%QcgaH8V`Os"0Pcwe^- $HR@M*uN8 'b sqO4JZ7z*r{ހ 8r`fkwϏtg,pIW ]B^O>%4rt$zWf3dh`7nREK S0WUOAJH3aYtb6 PG;D$T('@fUMA18Xm=6/,:&/jTk?iT~'/bF l&BD!%J1czpD?`'QҪ^۱!6ZQ JP C4/<ҢMKT.I7YƢJ4h?6+2 +#y2RDbs-sQ2V*7kf#d+Zp_uv$ >Lr@ H  '& U&ZJd^wKO" Y.(N-T9@]Pd bA## !Cr/fo1Yy&@MzH}?n a EcXM@&.55&$0=PX}L=&*r31>ToWFoL1C+hЯY^Q֔Ր&z. -x/ /(&T)!7 +kf-u@ndH(_-r6MRE6 4< Q}M-u9+q (P Tg"xRC}  >sܩTf5%~hiKL>NDAZo՜óլ ķ,]r2}jKg:jw{G=c.`I%G?0EmKܨ8I`qlfw:EoڭPnpƽsC؍.UhA:>*=V7w`3; RO֧H&R}nYO'XQA.D*@^xQ:E:!) OF|zQ/(}HW1A*:eGdp(hCML]EK!BO9r- & t8+W' P&?T{D=Y"(ln(E;'.&2+P6L#ucto4cҏfh~hX=B3.%;^i{eLgZ<1j. U CT. G:x|ٳo1dwU #T`c5LT%-Q(eR4-9p`YZHZsm`6a`Ch*Y#6  Y Q -._)a/6-R.Vmp+la(5'\ Q lMcXp>H7H?Y%*.u =, !,,.__XvVo|ڿ.&1F *"6lW.?;%۴Ni)afh?q/ ,W@dz7bd}rGsc{σqOWHO@_K_TPjRP\V;IZ~l|qmUJԷnk#E`zyAjzT+!X,\'k(v=+$Kş5^] ] 67@p/ Q; B1i,CR/y ah:NiUjmaTT>('F2 e#0+(S.W   ({ "]x%[@EUVVFBpSn$zp`M1=aA;7zqX5i yT$8) $!|X,olOqMkkyu shK'xJ')nUrg2Aއ[Z5@h6E7EzL! ;#G*,=5h-1q",IL)om3tpB>;OI9p^nzqLODx#p ]/!CM1ZD~yj]icηIŅ6dXwkż9MGW3 mvyUmr|6M7Pk\B/{N! Pb..-RG<ĎةiV)+$'g a}umx3}*˭;X%@MfVXh>[j?nF=%" f'w@#yJ}+ڒpdX'2%%w:GUQ8A@-@Gdǟɒ`D>)E4>Y` K"J=kXa E)!k&FfDhb1f@xڕZzàآ4oJK  =*xk'3DVt{|kwhug>:1BBFJ+?6\IRdPXq5 \ 50>@UeU$4vsX8\`Z5xi_ZO\ cր & 2 f2 -1/]FgC r{ .    =,_…i{ b@5hK3WIO7jPͽ^S\^XmW]s7F2|n[=5FXؽ+ & k@ :2%)$`Z>7 R1c32=D3EjkXi;^zFf,-D0E[\dxrp i)M0.u2p&BwG_4@m=zAfPstwک6$ *b:ʿרC$P4A3!d=SU"P2=h8o I4?&IEjZ?O.ѽ/BENnm\&MYPl^Taau'/2C,w3L6ƺh\'YpVcYAGTkOFl96y_9(*!](%7;S^F=-aw%@& "}Q4?Zƚb0«)lPBw?pT+MeyLNf6d,NwLKǜقazolK<Ie֖1aJ+.'HmX|1T4,!"rD#8e83 zbز5d&E#3' Fp"6ʨiDg[KAo\a}S( < k'Kc[L.>7v)"&rWM '*:U N7[Y] ΞГ 1e3"X /?$?')?& RaaEsiOuv| ulZF<93:!W݄ײz-Za)g6 =MnWzMFMat-q 6rF”ή#$ćc 1nagTaN cŪs"LΫxbHGQ|8Pgf2_0]&#x>QPS[eGSPEzLX3KCMpf:MHv?MQB\{l.xtO/~?]+TlrhXH&#iSY. ,danDsty;+A[070P#=[jk|vTF7" s)97G>W997""/7$&e&M!v iBO'Z_xwnuq6"eZh__MKH=N`ow}/(ߨȲw[H< E!V:7"u.Q=B1'W'5XnvF:DQ)!+>Ha]pXl&p1s] 7 &3 o3 d6+Ӝ|uvs).͙e}sn}f!U>RDpߛb!*_Ӻkpp!2"o\?-!H`_0tJ\CSgK%S|6M^~'Y[YdH,! .Y= 1\;s}j?.6./}Qm\ni"oGav+<(kC<bE\qâ=2tCK64L5a%N*gr^G=N>$gN;XÁ@M:Q936GgӅ?(h@ e#V H|WDZa m`>cf e@W.kRCw݃oER 8aއh?=~$ a0ZLj.vI a~EJ./9qb % YcC#q(tAW]bL$DGG*2C;$;,@:#A$=<7Z˳޿1 J <wݼظ~x}nd:D!oz:-6,z. <94K=8H6<2G?ZKk[f\nQ~pbQgN$Z9mBus-deDk); H;9NKWZWMi)G N 9 yFJ{gzxio&0sd!5x\OkVsZPޅhr[0;ä:5'@cwK{RuK̃su\b?HAN;fMp Q@?YZ5)%/ 6T]m6#E?s*~F*]UVxO9{> GfȺc;?$(?.A>]K.+1:{GS9]C } CC+4OQ2YP~xydMiK*Ol8JԹ"0bzD7=CwWlf.)7<.( ~|2YY km]F<@ZIx(~xc;*IEbW֫e<Ks6C&"zkSZ1{:Ok re|stdO?WX9b|F[ήnl :3>>&eK" N+7(mal'a4B2. [Ǒi4!)>ęĚ t!%؎1 Z ,||{[GXm  ],5UR H"`;c9BEK3V[Z*[Sk`4z9P3YzM8skN* ^-r*y&o֭OڬO~.د{'xl3yso`Ws]qmC-A=e1/CcPo:[%Ge)غ0OrχèvJm.?Dk*I2)1<HC4!` ^aG .b[J*=3sPN?2`z/X?)'P Y" 'k3P&9uzK ʻm>Rm7&@}(_^9omMeuS̔3T<i:w)~( /h&j6-]X1yTb˃M\UFt)X yT2uUesk88pZ V0S\xo`98Ae+&+rYJnX8.e}to.yxFW .}7~NRqڥۄo5#P=FV8! ' C/iVA`@j5Y"#12-YF\6eun"7 Gґ96P8.HUENUD.% "H1 *?YAeN TR`a]zwfA0pwc*E]nqe*K='.t,B56/MdggLM& wx=X1GhDltoiVS,/`]Wt~^PH7֞K ns|sl$ 8M2(q`,&r5&.6@"^I| |qa|laGI /-y 6;DI_r~|Lx!tV\F`^)MJgM?)4 3H"%H.P2>?k'O܏ ' cWgUYS6 ^f_Mr:;>k_t_ +(ުtƺHIۣH#S,b1PwofzY8`&|!Y?4: 2,e+eG9,w"R &1DL(  ռ• p˥%BpT1!GooFg oN%7 dQ2A?"-]+ 2mAx{Ab"k_f< MnoxK -lPnR̈AMi "Zt_`1TSZNdd)̧"e}m %w i 0" l-4Lo'(8S dI[}YOC$=m) T#74:Qn3SFY=DST< %9V)=:yd[Zi}H=wGkc"!u!i.>3!W9Fbb3O(./FED;;#H% ! aY,N  zY,84b(a},[jU]2Gh@8Q$6)SYYi>D!&B9Z6G1F@8v,H?ZV >z# F #,3=#=#4.N,HCEJ:?HESaQJkUaFYLLQK?+_##Vzg,#>b:y 6;=&Tad[:lKr\#"@"+a. 7_;De4 %g f!-eyLtF7dBٿ{Nj!kBtYYTA"]-9d`'W4;87i&d1PcLQ1p7.S_rA!y]a/n(QWbupe/S8 e2Q>BKR0^TC2m;;L[dj?yqzs>\KlJ8>HUaO,$ >">"#vVVG8) +Ii %2VPψ'\V;7 !ӪǕF6JO;^L5tW 6EA:,a. j&u,.$9dBQV^I3tdʸGhaV .3)f2Tg_5>NY[\6" N)~L> :5VMNh&vzd{"aD F 2,PfjjRTC79 HLRs? M]<4%v)&7t/ o% #7(&knC~u^ pxHJ*Jr}=h``W\rݧ0X0JQfWF4k"´`"M!z׎C~(Lx,co Y>q<3AHmU^ej_QC]53zG* ]=xbX=ZB:1*1# \ ENڹo>eeN߹Oͬ=džxwḰ9|Q 4̚,`(5[gP$W =!4 I3r>B3QuZN"# Ho?Qq 0:Z#[msbPEj( , yqyzkݪDa\)P #Vu/e{DzWtoo lrRdSGo@vM8;7VN}$`؀]OfC-nf: @b>mS{$QFX}U6=@|`ڲ ,{o3baimtɕ)MnwՃ 272#-Y%I [|/7HqF@f.F*OK?eq |{fQ *:f&h#[ i# +prt5hw_MʢA%1LhA6qP@2lN'?!*M5*M /2B)%k&%j&w_\@QLfM)qͱXvI.>fII6*Y,h+-ExLT H&Ds6\(9f =V6{c ~جsMj`5C FVI>z+~zc2/ Ak@|Oj8'Jiݴ:?1apt[U(ieUOY0c'5D51Q}zIj:%$;<"vD23 "0*X/5+/YX+A]cosk! ~BJ:Gq> /69hu]%i7YgVH>))&'f<MO6_52)t;9?/$QL\"uٱۛ",M3BWti [\x }\o=o26|4'{DHf{cF24$O KfAm]mw8l%:kn j ,n223N6 A1:{*2.YsKn]uK"~pj?M=&C7S=3. u-ECH)s- ':&F/Bo4F,,!].{: =z:D;)0#d;>T$pA#S@ W2ghMKRYi8/>%%yCƸ<nd&+0>(&0 lL+OTce'N~?(;(.7#D>4_$UC\"h7Le+{le@ZY.B#FZqee.~IieO_sg~lxNP>mraUatCJ%8PAJR*}2 ~9e/L>)04!,9Qw0BFIojoNeT3#C ]9 0-511yĠgߒ%/ ^^<O$ro6%G>L oHps:a^F'5OrX>z͑#[\)t<;NEڪ?- 1Y3GJ0-1omc]}&y2qas|g߷P{ZȩKW~ohk |ƑT7= ;3kyi%C*4D0)X8:9mC%wT5VJ ]f xi[K)+d1w- &::&t t!`7G_[RB8d+Cf n9C4t7KGY}ziuߜk4L,$CUTFLC%AF_^4^)x f>@o *B4BDi2NYec5QM=NWD\! |´H}<=h 63kkmY!+y%9BJC^\FL QpC}zF8"=78T &|2lvA5%W<T Uf^ /N~AyS{o *!My]WZ09t@+91`;_ )X~qgZcrSLL3p:'[S#;g)Vs,@{|!SQS{`<' (D 6DfrR^2tij1JPDK(ɾ.kv)/'+)96V' [$s;4Vg=sYB:R/V 33g"F:kKo4`3FʿRx?v1hs˺ڼ(\3FHSJDT9^*\WXF&.*Gb͆vlVE gu,T=JJ T;& \$@h2:o, v^'R I^(mUAxUD5,4cڴ"v! z+hlG- e_ "5QUaVgYMK5P6.=F]E']  ^($/-S'l?D /' \-)"" i, ,QDC,l` '  R2 /-mM{@t9^@@g-x~f?&(n*6&9o%$a{E!%.T|zRLuu4ԝ'>LX\֧qw)3!#7qiI^%DsXlYD! !5A+KL ]g}|5`N(<p 4Paj2gGS? n> !H&A7HSjJXYP0e ; `Zo c7;U`` D' \D]QRP,-a(BF%a!LN Z9&;5J'A} G L~_eRw%Ua#%z} ϲ@ -&ud Z&c!,n3fX/Yw|c5<-:Q] 4hZ{*dfYmFwRBRobvQE8S8:)E0H+%,?RQ> jl 4]8MUe'OJ ϐH^E H$ b)& {&4)}3@wWbBY2 7Au MzuUX2~ u%'"[ #:w %4(LdhSULIO)M ζb,Ig^s9p4X5'  "wH _̂(r^V?( X 0+DF-"(&@)1 p\/&$ם'؝:beo2&/9FTn9R;s>rMO@&D$%r1J YQNa_Na[0SL0*(-43"'n$) c%8e_&rmK^3wmhUmqf }ljXcPJhWq\IWE7+  N}"\ c)1AHlO7-ho#q8qqpV 16.F;-%74CA7CQPP7 $Fζ>kĖjfkHP0 Eb@G,ToFKPG" P" ')C+a I"./8S34˺NG >7p&DPwaxR̵ > Q1(_.o(,P=ASS< 2up5M2ROQfHS .C%A!-;nJSUJB"H#:+ =":U39FJ^lbLRwC?TDPop{ʅ;s*d\D~3E'I'GJfOr=D*WqJyM W$ BD5d.8 Lpzs5"f1[Kkuox.9#P3|5! 6n9M (u'--]P6`DO==e/9:JQ9.53fB3+ 1=>o1u9 &(EYUS{-?2ȑС I"1j?MQUlWZJC2ƪA<b:H]rkMdc[O<lz] 0%HzWB>D.M ?pLmN-Z ofwfl{GUWq.̕+GQd(\/7{<60 ]Y??OAS[jGL='><9+Y'(-=][| nf5bR`<80e}L'dQmrg;R4; 8N"j8 /jA 9N8cfF7@Z !#rt ((,}D{G@Pk:R Oy|"hS4, ilR5R[v u &i"adz5Z$ |_p  |T6[JQRFFCVfE6."#4O0U#=<Qp]mI*E:<'6`! 4%Uw-^>:LYHlZTR] d3tȜASúCbrV;: *ݫחT%hID^ec[= 4IG>5y+r<rAKpFF"?@$_I #Xn ( &6?hCObJH <:UMC2w2"/KJT9BCRPO|O3M='~)& A.[<;A:;,! `#X2([8z01MlR@I~ȃef34ݳ֦/Ja/b*J1 7%u<,9&0<:9-&5&*.2J[iOI6a R1MQq֝m8^Xp*5/?#>Q`ӼeO,#Q4MvGJe(b'GG'|C;4޹"c:bPMRN*Pw6 Wz B( 7OA1G3 sxZ}  :-o)dv%2?:(]&[oXIlT Wl T2vABJ`"i3ZM:8:yCI?Z> :@&HKPUQSG5LK+.t2.A<46D@\ c]".B4f. >p-k ~3g`G+[ȯ4Ⱥ{5 7P&ZmS]D) ERRt<P(S@YFB) P!by}jWSJ]}gl{6  s-1%KH:Y !1:-14!}%8 !L# a`' 7Lgg\ F3l q+)LdXNJ'2|G#$ddi#0;nnsM_DOc˖ϬCt9/Ƌ#2u< (),tO%9Qq ssF]!J8;+<"M(ZR3yןb@܇88jcR+c | ,<]cdi>U:j*iIJW 2Vsե=ʔ EiMV)D9,KC0D zC& 6 ca1l'<(p/"m(m*;Rn>9.ȿɶ4ghf2׽CC߫E{DDQIE@M)*"PG'*x( C&'-<$EzUQ@F>>+}T)DF7PUGA(Sd^vSXպоz'^B,,>iq*#gFty)F&) 7Iy<H;A8{9,Z'k=8=C~I2SEEmN*Tafk?3>6q"+w  d'X)0d$)" ip8 &;L:B 2G Q%)'"b/2.(W+"=:G?W[Q%XgsW!~.+.#_)/?>M 9 xQD $#!cla',3 `$z5[<.1H; z3_ G>;`7mV]C>S$N %;.ShrVBP:}$){ fS,4X?V$qdxyvi"Ri:t19Al mi|chdQp%]Nv?3DӧS~F4F8Z  $h  (X+(sjF**MN{Zh"P# [OV[n.aO c W 0|.SIuDE^NOCv<(91'+Q,$*f=CCEH\RX O\XT'Db<x%z 6<RJ*( ,R)? lºοZbBVJO'suQql@ +`!m5E > {*:-4*EZK0IW%VxRVx]\L_->u9x?PV?V< 4gw!= =r~2r 0q(8#:Y m1 z!Eu  NXv&_o5,\#zx8zp/~<H:5$, f :"e  aW0"%$i`H+$s- n J*K2:BKN`^V.4&?VP ?-> ]9pmR0ºD%/ ACfLj'(69Ihwù&%2MOgɪ3JZeSS0OXi NE jM{Y1'$/<125*$>" $E_g?:# Y $`'WN)'?߻߻֡ͥRبƦsy >PdZZrAU")$ &F" 1*K8-J@$DKKp2?"{PW %M7xZKs]xmQP-* "2:wH6*J$ @'  zo .?Cp||!+%7~ B>%&m%"a<5 F V#"Hm?/L(b&!'G#)%M Q?(~;=SMQ<!DS)m2&x5O_aQU4T4P$,G 6!dyV3pS/ I229z. 7pic2ݽ=/ݤiuK8fOnUiϽ+ t  n]B?Sd]=TJGC>`1?SiIfMJ3#$+@N#;1$0?gA/'!.`Ee.0Rt#QAkB;BgNJ'# cl %y0IFQ<Y!./ &  >"?t9  2($@ft!>X.XC9ȑ{5 'tZ0iB!V/2~/'M/7+e>+L1..8N3pE#Zwm2dJ4 2 ;"*JF#LuSM3-u= ! UZ1/"G 3jwi8_c8,00[e) W#+0+B'  $l >"j1@*$Q}'/8.-$z#2-\]  s]-Et01y1 ' /M<g-h)\A )%A\c{tO:+ , M!oوxm0Q04N+g(%5-FD>P:& xd c 3FO pTU_ahʫ "z;?A@=8\ Db] $:BR0H E:)-x'|%9%(*"7CQIjnj/rvKxhO`6/ A (pq0%F*,;%4@Ev:x^T]1 I@a@S5;9E>0@z))FTI6Ts5"8'*,! Rv  yՠOb =J˞Pd/:+@+ vR\7ce8GBB JBE&?2@0Q:P[`dZW3ZIQL<1,c"z*6dN*PakOg ^Q4DR1j(2|"uN g!n_A2QOK&ֹl(aq jbf-JG jw#${]v$)b(B_43+35,%+ ."1o b!B W^^n&Vo"r%c' 9hhhXI+-w#6MH+UZI=86&a7&*s$c |2EԺ 89xZq{4|iºV"T(lu +IN\SBUB?;3-,r$Qq|0zWN5!& z #D Nk}2kTQ)  ;=4p3 aK& P n0 ""T &{~ -G>.K97%Nr0@d&|1% /5$`_2IY"QZcknBYfD 'mZw%&/8H=IlAB,s,.  &!N*A?KG5SE?.-5:*9?E0P]9al1FmBp7NP^i֦ޢ3o_OpPZѶr #5.L0+T1k+z )[=c41A,3|(Z"-O#-b&U$)! Z4!" V:H 8T.@B 1' 9(~ 02A% T(gP2$&A PC:%Cw9 D)1I(KdA-i~s;? g daDX<:&4/I.J/T]?)::8<<d&/+T++*+-%#,%/z+_.;0-=WKQYYb?F+ )xA%&DrD2 2| L'b/ 8&mݾ ϡ$1M' XZ'$'L!Fx 4 0,0#04750Cmh#H&\ CS2-6DE9>;'G @Up%H^*\MJ7,~=F@8 5>M"  ,*(R53 -H%|((/!58/0i#&*+g2@[=K8 "Uk_ %HYafq'r̳f,yS`KHmwET 9$' G7w1VW^ 1< k  23=fU1 [4 z ?  r~ |U j y}  UU*(* )UUV,, W 68]  &6-  # k 3ba N O)(7=8E 9#28Q RR==- f A !R"),wGmTB41ck$09M*  (_yPy%,P$Cl< Qb{)o /G0[UBD< $t 0l>GG?<b<` Zy,j' 77pr3(<>56y$-pc 14;FO H GH*Z  *O*r!# kZ4A;55RI!L@r:a $rw:x"Bh ]R%)|/)1,.)P'Vh*_"AhpbZKbNi722!:.;7E;^E@3<.)* !d LK7#(t#*$4&,tR k6YWKDj c_7K|EZ( C0 I&MJ>0tWx{ JPO>*} 1{V +$&$! A Y"%-.'5!(-4\!%!,/!"((+T!" ?Q Q5W#K?x} q M#.l%˵u=>  _@# #_> " p'lGV6 ~-AQVLG3Y'o{ 27@n=c.N>  &d-3))3w*,i)(*5H#N'_ >n6"  U I-/V:J0O <+jSu !1 5 y5xZpk":;La` 6 gj5`sc _tQ-.&b"DhS&9S9!@*<>7* Z%[m:OP?<*^!l#u"T]|![ NB ymR`-fguJ-gz{Sb9(U d#*IN +11-$6} G% B L 7K9'- r7 F,0 f X. P I m%7+*L'%N| dT  u tedV'7( CC\~?/]z c|[k D} PD} 2qU!Z''Q_=1GoT#%2hl4u=qmW?g_.ePBŸ(cTc2 vx}SgZ -(d6s<#z%+ ro0<&<o4^CcR n^= OhD!/$/"O:'w )x"R2..a&r"%*n0Y;;.0C0/l  ^ =}A6'@B^% <ucXsjq !<ͻTyY*\P34[?AieXs k\ X^Ws|U  G!&xW(n) v + ].3#_*#jt."[y#-U'! 3 u m q K "  q<^KMA)6c[%A<?4<`I:O4G 6$M4/W>Ts*&Bg0\ ! Z { a0y<B^0p'C#"ql +34v1G+!'f)*(mxrainL GJ\iC+ WSw FiAf"  R#NKmKI l#H l!!1j,BB6i !.-)BvS-.)   f  _L)h3" _!h+0J# 65EEbJ!B,(!N|oH&*(2;^$ci m+v(%-#! Dd;F-YvE<~.b)n!6(ME !xR;S _/B)  @5:%</#}J {h$t*06rT"hGzSrW'+B*;ӴE sm!~7)  #@[EMPth@DoPNWHb*[VdF?p ,`![}%!\"Hd   @'c'C !14dx&*4975'|c H~9\;KVVx|ZIcP[Mٱlҳȿv[a8*94"9{.$+?5 %+p&V!  5jJ  "(!*@5Xֶf4;~;X44Y/F}& abd|/%=:~75j(" %+X=M>%;7:/-p +#A!t3&9((3@41& &##JSL-` JuOPgs9\thuh0KlS STv= qD!h oV I$03g5(,XNc!N mWIwU>V x  t! ? X,f6!;T2.(c _ *"{ #-& 'FO "VD(~{rs7Ca07<1K\&.--=T>b0 680,,-Ji(T 5 6X@$X_Pq 5(fU zk((7:+$RSu@ Aj4:8. ^VP'5 ;mG"F P O#(V96I4*#[w rW(2>r3R10# 7<y  Ay _2n5"'<}hyY/YZ!X~qa cd/% "6i -##1*)-r&{_ k  H  !$9 Kt{v(N}uR E=%7Ak!U. h _9 & Q'F1?B9/-\ ZBI,7 !A ^\++m-)5bMJB l9 y4CHG25n[. c7# 9%cCf   {co 'Y A  { ^wL$ s h; " W'+&)"~|'E1/26./ 'R+#G&!!$$P\\g&,z5 "rbR)*e -G!<F*@.S6`,!_eZ*   k |suS8voO_9H^p& '9{N"xKt#?"*n'*) T m*n/+H3O dNC%*)-Q*'S)Z0 m s&4&- U MW]iZ{l bBE `)"6& 1>#9/D::  vcuYX i4'q\qM)*%UENDK ,  :MQ` ?r o+3v>9*Dp$ X-w-7%@. 0HB:pʺ0 CNo$Nq')q{aJT-=\5<!*9(:'L**#s+"6 S> / uH(>~8bHF5,B`>I| S> Q( .Z:y i= |Zs ?h~ ,Q aPb=C/1)4]{=A`C˻).5ot<3pg # v#[M&Y g w $e"%%fw Kx ` Q]bm,-j:|d[[{U2 Keo_B yMP R D L|O W~ ' fn + ce`d,& -R@) oI  hQ5 )' !.E4'$v wq7F'e *0 Um^bshJYh-}7&Z  q ) + sq] &H@#*;%{ F1E^/ %%H# % ]8JeS@#Yo sF1 eQF;.=T2` , K0\& ,:3k11X5/&K t | \u%,.8+5o3*8*8:7r15;0,!^3 (-4,.s$t` 9<SI" ]~[^_[3=FX>E/ gp. n $# JJ( T9_%#U DXt$}dL~mYX2-"*Sk}N  $'C t r8-rh^7h@`x +%=zu Iz$s0K+(e I? Q d 4)(0**/r,y!  "v V  > N 9RS`ZvbLG0UW*RH L(D7:x'A'$w Fo C! Y~6 k W. hANaJy3 sJ 4   hrjG7H- aqr owbEC M79  lQ p!]V "w)>(.Z$;(? ~h Z!Vs{MyN'-e*h&X1j1t9# i-riU3^Sb76L - 8f] " N '%N.Z z}'\ T 5 E  WIFC_! ^W  NQ'x$1M #"'=*'e  .  '&*%! . i}@ s |  ^oT\x3 zw) ? 3eS l, -=^Jr Q $"Gn V~ t! W)"a${$L%r~Ov$ 9O }h1 !y jkM3|&+"A  2}5(k %\\'l|}dF|IAq.iW  z~GZ6 w}P Z&3T*"& '\  Y  \K I< /x<b[GY=xT=D _*zOTGK415?wDEB:8{_!1gC_ coUKyiF0WOyf L  1+_Y' ;'#8-$&D#LR W Q +-%8 o-|Q T $=@#(#G+.,!A0l8J J#!Jo\9_6 kn 9p s\ uI h2ef fg%"m,$?~m X@"= ? j""`:<? `60)'83*t15Cm:AzL! G9? Fb{7 96 f jG UI b   ? X H/,818*5!am]5 |b$$TZ  & gn [ |6, a l) o!S--y5' "Dx N 6%!L 6" Dp(nse5_Wd8J'B.>'Aj. W <A&%s b8C M&-<' x.v` 9H  \x)S~Dj] fsb7NQA!@;*fiN]~QAR)kB*NaZfcI**@wz0IGL&:b Ex54 v*IfkR?MY!'G% Ml 10B % ].?X-/;u_J$b=56ur jL$~`0G0p''( m` Fw  >d +]bK  XI 'J@hq3J F10t,vpdC$8_O(|Pos[(ZsW  DP&Hc2w-&z ]'s t r3S b^~   V!= * S Yf5  S y".$ 5kB! %c#)N y9E#"+0}"( ' y <x"'' 3<v$' l 0yd'H Tj 8R# G!L&*Z ~+odp ; :G~ KU@ 1@r&| |!6e",)'I Z-Zf  6 P?:>(4$s!Z"( +(,X#9gr a Dk lb )Qzjw u_+ YMPt]i@ -.D.[ __ qEs]]- rxw+w#R>;v~ Q-?)rY)*t1c&U#(g%'Eq*:Y f@wmZY wK=|p(~%"-$qZsEo#=v$i R ] F  " b-H5n%7 'e& [2{p Qw x$ V Z=9 z g 1 C\0}Tb w,FW}; Cdx7D\p `?9`C FT J _ jIs  p<b < g Ks s1[12=2Q4Pc91!hi KY6 [m7SF :&_i>hR|',x$. %tX/K;j-1)D=^u1 M{ mA&<s|&(&Tw(d sYQ!GW*%gwL'4Pc qWFY, \e /xm!!))$-O `MYW iQ E  .$ w?[ F@:HT! M H{2! !+|`"T v_* \>VZ  {/B '( P\}$K }P *UCSKS#E%"p|F" ~_#+(*( #f$2LUTX2|rKAOx w; jcdFL_n_0 wr BC &[ c(u/k _  Z;u H tk a[w t/-?iTFn n^<N#W:}s . Q! ^ux~?hV,qq/BZ! 1Z+ oGM\ <|'Z h"#=!;B  IJ A k dKU AG?LNSiUV}*"3-^'LNu> p {|c[1hG$r5@_14"Lb@0)2p u/ ZVYTdqrRJa;hhuZGmP!0  %x #v I a  VXh|1{~L7 h  = _/z , =xhz; * eO1-xCn x<1/NQRpgJU.b#>TJ5O t2 jH* 2  .( }+hfSt  B! I vn;feM4AN ]   G\P ,OSn`V;(.Ow7 ,0 &P. H@ zqC\ K,'dG_!   {X%$Q$ *?%*V : W [Sw@XmJ]{r6#eKp/[iQp+ A1  # lQ O N rVt"'\$ T_] d  QPNhEq9+I 5  7k V  t8MvbOcM''v<'Oc:OQx(GP  uR ^ |J$ % R 2Ta`iRWW i=  hNXRG=  OXwec H24I} 0 tWb dI mt" BJA;I":| |cL  W9.c*P`  zT^bZ~,4A W0 V<V vY Jk-!  5T*7n6H 9 < dsg.@ MyhdU 0 Ut-Jh@~'d[A4\I#t @l9}{J8EiJru1 vg1  5]: P & z+? 8 tahG (4 gc' I0K!}uHxz E+ =p}z  swIZZI  qQ31JJi#l.G:(  +=j< }% D x6C I5:d E H~] _~nK  X Y =6 TiXiS^ VAzI7_]5/UNs<U ta $[tWTu@ h H#s(/yG+C;HDW 2 " (f!  @ejw^ }w.I*Pe6\|$X2:u< |A8vdk~ h  HlE n GtMr\l7v!0Qp!q#6_=zta..bW[c~}4^r18z#$IgH8UyX | R H 'o  3*eQ ?w*Yv ~dFX|[[dAQ0Ej5QJF^ DZwbYQ{ &!] cH%  ) <G 7 A .    -YwJ[wJ9G 7{w9  > 'xU& : %; t| &,)hH#v | O -1+2v z~Q_f? * ~C  3/M%  ! *R q6 [>y{#"N'_!*[YB6 J*@{,P`:v# ] v kY2? K') :_c i h BH O l2!z )2v t e ) " 4F _ E<O 0z71Apwp7n $87 wQC&pg/_z ,dhJ*O 4M#1   $[  f*B_P6apUe=t03YMh;62zL,D\MV t(>;aK F K4b u< 88Tb)  :W5l 5D6Zg I x  9  ZC  fhS1@TXv#]P_qv"T]xe>?P|SL7Sxuf@yo5J~>I=  $%@3f8 c|  o z5;61LGZ s eR[_2EAe)>X 7 31wAaw [ h)o0vc $ SJ@h+r#` C%,Es : b (  ). !s 4 N uq 0 gM [ ~t N ;w:E)Mz_JQ ac8ZZCP{y  @o E!mav* S{Dpx; yD CP ] _o6hUzd S3n|,{Rjb#o^?Q3[@W *@vPMf&`J:B  M cc&  1 6>K~ J+ k Z=0vUAN/vx  w R'yOM*RR70Ux{ B4"  -[i(I\ J YTHU' 4sJTn1,V  JlwUw c52Z}{E ~ bQ}qzjpi&FS*H_,XT=; g0HP a h i Q   h W<K;Qt p !  QdWQ  4ZZf  K> 1X>$~*y4vkqdhS9SW q X$u]T4E ]d,`#9$cL  /O_]n:>! qS 1 8.5}_i,a :9p*XS j7D+pqi0A D?5@B3I  uV n( SI@ ?xNAb~` :FtYK^ emsh_>+sHRFC84mi)n"(I2c}^V?  yzVe g "K ) s ) Um<m<aa a0zUJbIU#&bJ~!Ew)7' Q-SNbo+C_Q08H     >Z"Y= B. 9*2::%X".qqwY;X5L P P  xQDX?Nc&rip| !E ) 1 2:>>">=`  W / b" yC}%C@. M& X cU O M.3=($4NXX,[HmzMbL2dq3EC"7"Q9|fuhhO*Yq  pY8 qN[ ]}!RQ7 ]$)gz0N4gy6D8'zToM>zDHRP5v4[&ff?JWOiZ[:+F= (,FpR2wE d0Ikwf [? 9}'3pR%4}m;05w tq{/ws[I#~tvTv"u +~>%UN\2eY$l 3 .N Z4 ,d :"n <[K/ gn Y#C8 O z7ny7{6o?xAyn%|]iqk3iWP.P{#H3H#0</\Nj : % FuDZOH '5!xe' PmEVq~ o^DM\T'\\{'H r}*a}^ Np^TqhP  IboYhh~] } r N ,r ynyC` C tQ&OBbR r~+zmS@2Q^ZQj)i U jkkv |e  %1B 4[#-  F T"g`#C f'G  Y 1[U=5uy l , 9 XLb s\k$N`6wJJ|]RogRx9lMl|TW[uti:zD E( w l I |Y5C['U8K@]iSjRu-s_W ^[wMn!KU+R`tX iRoQ32 )f=Q2ee-\ %> D-Q .21e$Iuw:AjVRl2 j?R/na;ndP]*BMo93GbSG 1PV{PIdNe 4KZO_~6m\vHt+M'm0XTmw~1Lw4$+Px;7Foo^"4L6=D);9M;=Au=Z!)aC3SG)FvND: C  9 7`Pc%80x+QZ&#L)^gtv57R9}\a*h%6jRaw'8A:4BLt[,TAqg].^Bf##0zCn*/OgjuWn:Giad(]8M}svJ=+D'_~uBHm   d v   . J  I  { U G  N X @ - 00T9  G_=[q5 ~^)pz?)l1[5Lt|EL[rR$ H1h[dH[$6mvZYbPR`  iEa=EQ6)lH,c$p92  F4+/T;bxKs7[}Oyvztfw  k571K5M_z $ AzRCe@>RT):/`=r#v<Kelq4r$blY?7&H6';_=5pBs z[yZ]|qT $$A70 S? 'tZ" 0l0Q3xcrg(-1_hKL\M1u3\bmBKoo@m ,X J  q#?-bN,$#wT""" ttS&)|7NwCfES}Ezvz]pJN=WWLRNf6. TzCG y2GG3&8@' ?? !1!W$=9`) "/h%2P9]92HQ7p(0"tA19c(Qaixg+  d3KViQ  O z kOp <["{J8WVP$<^LoI$dQu0$HY\n N0 jro 3 ` Tj J   V 9s9'.tR~OPA^?7'w g`j+L{t;BQTLM!{DjuW )#=nO"1X{[r D, R^yuc#d6' &>3m/YYa$)m`; @Z|8m4z,hR6#}3C 6OA|5SDbx%,a%-jbl#k% EY/ \7 AlrM Yv4}eLt*' ofE(3},X0 3mPgfgssS.OlTEKV?J;U*bUE&ZCarV#I,|;haRoo~a[kXOI{ilMA" 8W\e<SfEA$5Kzrr}zt-jwDy/k 8gyPK:B^1U[jx[i?=R * v.C{Btb ' oY [3AFD O=KP _m o0qaYK9@lB<?Fkv, r/T;~P I8T[HN2"KSR=(m'^l V '7NG:nI9=id]eNXh$Njqx6YF@aH8nG1%@F-A m]UWTn;OjIGPy)y0K;@vq%vf5q<pb5}[vH:\"5FT I>*+~hMT1 )<t&ZFC'M&u6"iYe$jf%Gxk6WL%^x^r9yf:` LmM(vO| x3NH<)%tKZ j=(4Jt k.:Ftm?QM"I#IJuSz6 Zk_>1)%ibpp>Q2+=$@ RFH7n"fLC:H*ua'Yd$!C*k5$V,QQDkD|=jZ]J[yU$BHAr =g n'h17+ye{_n)MWl1c`2N.1b `kKL69zi,$#g[C,^#42g[*`#pk e#MGjL6*CD7< WF+m4!A-1xs { FI2Rh2%8(&A6yT_R\?NQW46*EhVE)iLt)ACZf`r.I(frI * f`QU"DU'}|Pl<q[h)Sm[tcrD=k|3aO}-wpxFn^GdJ~e}Xk'V'5?D|}% 8!(,$7d6BHU -+h<r\;;u&UqPE*s d W_4"uD{IF1+@FnS2= glk G : +B}  f@v%&eyc]`ms~U~]kUdX% *NBVExP)jn>_Y_0 o_EE{ TS&d?6wVt]1I/y6UyTa"KY^D).cl<m/3 Siw9bZn@P[43oR&M=!!n2: "kn;jBm]G8-V,_OaCaF'ZZ<{gltx28!.hcwyV6*YE 3QnZsCh=rrV *Rq`D( v*OwCT,.{Bz/zvK(~L2 b&OEgqSlI15b&&N(8 gID]0"o{N{w)UP4,,u%43B!Qs[+aoko$N88m<JmmZ_P{/8 0o*"';K6 !=ZvhK^QA=dVAHM7Oo&A9`Y}e +wsTAxo%ANNDkU=uM d:y  ]4t#>+c`=P~YQL=}{zV#1z1d6h@M1Drm!gne)uZ# t4cDlt{ N`Syko9XT0UYTPCX ywDl0XppK]2qbWQlY %g:q{m\9"45$|ohLfjx:#7F$}>Qv-$z l]].gU8& B ONM/pVt[0~&A&MYhcwT7 1Hjd: U|i&3{.w{?w3{X?]:5WZrXin;wO%.Kl k ">qtN)T.CLZEqrL7Hv[F775B A$51F4,|4+~&h/O1cfEA04A8M x$8Sx|?vGAO7bq(#R5!YhMqYrWx\8lh@@UgR@!pkD( MI3_#NnWO'4rZz)Nxwe/cj)you]\e/$b*^J'BZ^fGa1bz j:]us>BXm*<|e /sj}M]+:aQQA-~; CS^&1wRJ=9ptR#M:0[v*.kso#I'R,<BNV'j4yN'!wxBN08eGK4Vi%CC!K,T^9!%,TJN2O1joBc>g/o``%C4*K&r_D;-+Kw< |-59mLm|Lx =mHx+dq|LT@/JU.<88/HE~zGGkDTgCdQqW#8ErgYQcMR\{)^42tTVH [i1I,N(e7t'^?IIJbS3TfK >)vUfP3U(F`3>D" &V!+ 'nq2%NGpsG.yZI t,[(+/yL(d .?D0d|lQ;0`3caq DW9j? )0q^@: mM MQ^) ibo_S/`39RIF E(/x>gbo"_H_nd>j-oiY# 5( %{82r3$02MkmVwK)U9fSi |;D]+d =arrnV&@1==Pbb_n>w d$ )n5|)s>Op772}LZ<*y f4FT &(0Gz+b\Y-mH#`BHhh}H QL<kO`r'3{EzuVDaud[x G'>~%Y.SP;5O wf`z:5+#2+b(&+c _Qx~v))\4o? #O>1"5@f))E!i`XG9 hqc3eL#AX;|8"<.jG] @&HkKCJw^I>$R$DppE=(|cg!hd7L *u %-}JWQ`>D^b?219kyJWrbu1$11>geHe>'c!j[z^;y z_g/bo8\PyJx |Td' P:a0)^Gn1_Tm hH_[{7%g ~ qg3=80RWx9/"}9 =J_ ^eV[~k&8"4{ M#lr#F&)KIK !${c-uhqfmTRTRbO2}}W>(a}5*gVr2g_%kU*W@m 5=ech{(e|CLv*7b@0 )>Tj-hlV+tggd%kfa'i- L5joRJ|+^WN3$HQ-*d[&B'1x. H/88]T8)rC@#E>}>>Nw~-zg! 5[0'P;vf~~FeAkvC?bY-V@KfU` -WC-h[\OBn:Pazb9Fbgm> S8H}I$J].WrHQq~PCX=!M{73R }%%IKR|a &&gWrv,{*&Pw1"q h`RfxAU,1WM .]y[u}u{ ^X"=f`<(|ZHbTSZ&`C?M3Y(UXKM3 e#RB)//J5_,?#5v>kL|u Bi,$yU9*[)ABtv^4GS3 KFH@ i5_ kNN<M7 "1wy QK|\,xCg_,;|o?~N(4BUUH*!8,3XmrC\5!rjSt+8RW`4$|jXSJk^$>7xaXI0%7i]o90LGrd#cS%cZn8&y{wp VH$0u}5\xB# 0M.r&]VZ|y-!+Y}iLFDv`QdgWf? 8&! BD27|W(^DDCj9O2PI[$p2Ew!Q=VBya dVDo'XKQ'SPtsJG%M}U.;~(ypDQm^~)vzC S@|$_:\hF>'mE! 4 ca :%(,]{$G#$jN5`D%cJwM+B)Q2 _6H'6@-9e~5ujM^[*%?%@TBU]G G2(S1+Gs3t)+V$gE}gbE~Uu[: GgNm*{=)kztC=_?(TcYYxq-7IKjH<x"@^+*%A/Th e#S?GBu+"7@Mh?\eVP|*+2wqsIN]}%|Tb!*62=WN+Qx.Mk2<_>u S&fGrY"K^pD =Q ]Ail#-JoxuUvBU;3 A*@3`3%8TGBg>n4%% VoduGxbjD5P)W09Um =<ey!)${J%aZ#C6<,x-L^TMV )vV@0Y}&S$JAOFK<`_=&NlX B%Cw^ T~|~@]1Tqif+m0LI!3N e?M<+ ]FyBC]^#'fy?2 #{eX`z:!.oX!j6+ (^-9\qt|r +-kL]G+{k<YS.D=.NZ4O(`d`"U0V9Mu3V?0bsJT8>[,UsF;=T9}0D1jwU_b^UY /| vCTM;WwFNv7u7OKsw  %w)c@u`m DrlpUMyA;9!6mi;= fFJ]d@BYSexneci0n i dYx?5gvG5:j5 +k. .2dw|g$"/gj@3- *`O `XW2 * hycU[PIQv}D6%.uO_VL5};c\1ZivMz~D3N9Y}dR;!=vit]c!<)*#-'$48.;E*.R1>ErEK%7Gu\M/lm (  ". yvQRMsa3TLsyysYkX29s,+PJp\3FJ16.-.-"Ea^;8 !;OPV>!"/ &  N hzL[S<.(:Ypzo~aRfZDb\; #+N?,@$HUL;  /<0-J)%:BRc9!"'+ $"-, #1' )#&(* 8KY6{x BB@pC;-39 TcYFMG99R]XJ+":]BDPhp_J3$4HF*A6#"7>0AM%"#/'8C4(K:7, &(E45)P@  1E:72.# "'LD<`yXNTMch8S">NHggi|r{ySO<>HDGG5C  +/1+  ;8" 54 *aPTIIc#-&N C\[z_VdG/* BUQ.2TQkC#  UV *1#,%(*1CK0FFN0*(>>44DPTUJ "8"?I69(8  (/!    $$1% (+AC5. !4 # &:+4 ') 0"# "!    0*!-      **'*  ($(+#!      (#   &*040!#((0  '#!$ (880   $&)%$$     &$&!   "'-0,-'!                                                                 SAUR1, 0, 6, 0LISTINFOIPRD99 Drum SamplesIART 99SoundsIGNRSound LibraryICMT"http://99sounds.org/drum-samples/ICRD October 2014id3 ID3MTALB#99 Drum SamplesTCONSound LibraryTPE199SoundsCOMMNenghttp://99sounds.org/drum-samples/drum-machine-2.2.0/data/drumkit/hihat-2.wav000066400000000000000000000175371514070543000204430ustar00rootroot00000000000000RIFFWWAVEfmt Ddata$4~S2CSS^,!=K TFTqN]3L".>j"Kv3i׿x[76yĹHD&?X͎̜)m? Y際1-!: -.,0\3 .8b0Ao4NV7@wʵg'>sĪg <43GǝK,{Ea̔5" ^#8a-7C[3:((X!᷀ȳ /;Ev;;G=Dr^rci^6 xUqBWJc'X엮OCBu3x9,m^> %ż*f+uGB n巌~&@q:J@D? Ngi ƾ F KL  4XGVa!L'oLX"i^<Ro7H(iAä+&L Q#C+&M!n0lj WF3ύsJc V3[<3L%Fp 6v,AU[JaD W\t˰W |\2M\Pu X"ּf'$IM&[((t^2 BMiT@VT_ gnf#NOk ERK;1 ;iy=Ed]I"A< IFqoMvZD8S ^(S_"IwK`7oh q͖-.mS,t(z) u''K(ʚ#lC /<: mX1 ln s;| T% [#I?/f~Yio?R wFf Ϳ6N.A4 yP v`W4`L r5kE  !ضdQ Xo2"k] 6!ٓkSCys#Vr) -;,vQdNӚȡivNE1Km;mWGBPlqs|px^`f >dO{_T#D{ C qJ c7Jkd} $<GI$r$= SmB_*DR?c(CB[>;VN $[R*"Hyd>+rp2 m<(9;TiB IW d:M%T@YBd]z fU$IrxwJM܎C&ˁo0"5|,]]q3U$b{ 1>hmln< fZ Y9m{ 4gIB=4VH52:@|FVjip[m?%;r:i'-Q~zY%Ni'A1wJgQ3@IZ)=]:deOE dc}"VM.N 9!@زOM=KhGG6K;5:NyA^- G'N67 %Q{K tJ4[ Jmy=p`;( 6ŊjzJ$>W+!lX08;ʯ$* WZ+!2`.GB,hSds#W]Z G͔ƒ&T9wX=4HR̨a3.X%(EsZ\X4tvG0E"\>FĈӚ1DW.E/16qe[WODn v"l-Uv΃4-̕&ѳPhOCP20 ͪA)0j Rh#r^3QvW[Z>m}! dX\D}!yGٸ@0{A_ֲӴbnso\\4dKJer [[sM2,V(:߆>?1;,7W2O`2p:Lo)A:VBk1WSaj2658WD`+%Im[;O>z*xQNpxF-}^E+:}2:>p8U>LWp uI' >2Y/j4\]tEaG\q4 l$IcZYh}m;DE)%LTEM%7Q/QC`1!xAV)rHKcC^ ,FkexEwϷ`;<Lm<A"q/^ kf,j~* G*>?E = OV ED X a4e\ggWaD_ SAUR1, 0, 6, 0LISTINFOIPRD99 Drum SamplesIART 99SoundsIGNRSound LibraryICMT"http://99sounds.org/drum-samples/ICRD October 2014id3 ID3MTALB#99 Drum SamplesTCONSound LibraryTPE199SoundsCOMMNenghttp://99sounds.org/drum-samples/drum-machine-2.2.0/data/drumkit/hihat.wav000066400000000000000000000503371514070543000202770ustar00rootroot00000000000000RIFFPWAVEfmt Ddata@Mg_ +OT]Ε<ߑ 5{n \f4^#l`C5:68@6voXܟw'ߛcߍ1ı( m M?Q>Ę )_Lj_Bv + 'Atcf;2v_+B8 B?(qEط̜ /?/KTNЌQ\B_"{8a,01T[ZPC: @uח ?9&;u Κ&D!LayZ-b4ߠB)7 m ˔ãV ^7J|"_(pĊ?UDnr fo+_ap|7ڭF6c-*e$Hv}6Qy {HxQl}<#cҷVnFEw SY+{;4Jم85W)pw&L)'\k&坄V 2$˶E;˪W?ן=LXS݀WJ9r5|;C([^)?54~Ĩ~m7UǸ_.O,[Mj9ַE:Ua-aGH =b 7B+|!>!o\#*-36 hRUH x^P^?5`0>r:WMKtZ>'EBpκ*[bph 0u|sY||!YR_AD%=tQ3Y iۆ40#ٶc`E֭dwʒWI,#<&AWOHs[(m%gH oa/*@wg@!/)] "evNy4Q "PO6 4 { &ZF <4->3!H .nhI *| 'b ] Xy1|:/P"^19*Cz ھ6-/$mzO(ElnmD =e6:5A)w 6Q9[k6,g+P3%2GfP0.#Ukp,l%RO j@dTC x vcS 1Ъ-BkeF)iZ?hgz nD\xEX%IVP8D>'c ގ?=vr[\7&-04ker&@uMKG xbN!" ;^q r&oQo' *"~1Z (HO4$Y v2xbm<p?Y ;@h*Ւ"WQ;hA:S#X!Q* 6(?~w>nq/  d)C ҀU Z׍f9%'= !re A_Ʌ_|9Ƹ+10+cFܖ643Q۴'s!,$o@Ar.i! aZP0sgx'iJm cP0vA&V^|M9# < Puh /)6bA#Ay-]z#|2_8 (>TfD> cj!SAJ JT4u o-'~ %!RM $ p c2  +L\nfXu!F}]5 rn,]:bs ^5k78aeM'$Y,js "-b| l1s 6 vZ 7F5Yt#sVm &z.,䟵r"FXV`UX0l r FӰ-kr/Go- = e u =nDzٍ&r; ,8c9n=4CI1TkCbb*RWuHZ|&Bf+eXKڈaT,7f^?c+e`G{])?1c-uLekۍ&rIQ26 -'RN)f5PK`O؈R8^偬^Mz% dO4E <Euzc F+1r}#5Xs# pb ?qO^ .2@ x&|SS <:#8Lb"yBr:,&p7 lS%ccy@4.oq'y'6dli@P v,$`l&|y=]|?BYJZ(SM/grj; <$aF~sikG7 <5eXIl.I  ^wbJ[ mﲶk  o2iKpV{ Z5S\>M/=}|,J 0e oDMG ~| iZtmd2 K:d%`4j5l6e 6ܲPeupr|"bI_XnqPja g6fTi tR: I>"nB,^> GxwKm js9>%z %9|Aiu)YAԟ xJ\mA / : !* t ۝[ |q`UAxI.YCP+0zu"_#XiH67JE %g ԼT(Bq;Mh7 peT j.h Z% o,;5"kZԥ8{O}~cBki׏T ')x2%L[RVukt m6B8P}c|d _ ’ [$; @6/pY@d01N>M"eM lt % j? ݸE# VirqV@Y :xVY>G SJt K vb&q:_F0 -=6P5U<0Ks jً  + zln]֍:hc(F26O%ӍBr_a $*'FADXi?V N<X̭(^fKK@<qFq8"Aiw K'O % F,VVbS6$C0 K.?pR.m z|2slIEu]L"rJ;:13 Լ ,~ia Ҁ ;j !hKZ*Hlmmb2O8 ;Fl5$2 hMFOp!G.9 po.;jGDmZmS M{˄ :ԧ X'c{`oЂ۫J]3vqO L6]|5Ue #WQ_'WҮ+ COuH4ܒD3"@<ɯl i_̡)elyxi\ibPY!(մ#oSʈ ;Y /y)1YZ{=]YsYm ̠:C215o:Z4#El,^.jD DXO( Xv1q u28~Ak^*+?oG-F oYJD`,;F?JnBf,,f\AGA*o;|%Y9KBEP&'HmV1j$@8e`7aU@6QO n;< I4/w6#Pmn^.A4cjPY!؞(& /F3% I]~a\T7*N\YҐM1dldkYps?e3@`iJ<`Ԣ %;Ű}݁ͤX\bC^;hg=hk}[Jj p ]R.t|t,%RDmz*A=ʜu8X91m+n 0EhRTc"*ay)+;L/ag6 _O8JU[6~I{߷;Y\qV)uH%x_DUC(1#+[(aH<:~_jTo;hG>.K>. Hn͜ KUiۺ0Ff,CXQ>Jk2]9SJ 8S[xTh`.?zBIG%>:b:\X~16bV w|'; Wg8@jK74fTF/<1<;6[W:dS4\Ы2ZdFRV<2,iaow!uMR'uJtq0|cU~J6*mOAoL6+ Ap&L99fs U-!Z9? UN*7d8?%1@V߇aQ5Be[{־9j(qLai_Fn%&3hBjh&2C"ߧH C?_5T *O4PODRZ3B+{K\xyiX\){NcU8xCI ݄$o3KSYpnz3"=?)U!|C c*=Bx4kFkoVϥwmD25#:8`fFnaO(Ԁ;y2R  KYyK? ]Px I0/u(54R4Q ',xPB=$M,˥g"}DgX,A/Z[Yv^)Q*P5aK(+ZDo->grjpb߾la&19*ϊlR:H9K'ZIS3veTlb[v 2ewcoy8SX(ê7PX490A1_#n #ӷWȊp)C'< ]Ar\@692ĵdmE"a+)3;_9Qz1L zFr|1tJ; /QP1/x Z-(8^SCd2W  ɯD@Rnl$d  89C' lM`ޑIm418jBGtr8b Q`$fiaN&Si5p Dxr2W _#fPitJgѾHwo*!@c@GDQ xHRWZ -f@v|Cu N*If1-Uw y5U9LKx$JRn9Ue[>n(J:xJR,Sv"n #D;]-ff@Wlo uA^(Db(}K P_|>)܌6[wSnYH 9NgMRnDDCcD ez^!"#VBen.{-;р[!G)0wHeeC+; 6~>i2`6\ORtԴEfMR[Jvܤ46OH{BMCƀ-7T!CFP#Dpv c}B1P 4xxLB`DIwIBxx4|i'UD:/,_3kM%^^rmo\p)\.M )yq =o[ .Ab6UIS?d1\M!(6RiA X1 ]&*1 ^1Q*Zf1 S vw/""& _g#"ʹ,r[p%:)^]S06 ]4;X-/EN~Zy}U!a5Mk@ KTP*(xqQIWna0;j! prH#[) t7`xo^Wz8r2ri3LR݀;X+KEB2"si+KI^!krpA~Ȏ'#3l4yww ]gb*78Ѵ #L;+I3-lwgxpk[ I[*#j*4yWj >+?x }]-4g݀QS2 s  UEE I=^5-kpaqѴD9*WhAѴe]w['d>ͬk )orX,tOVz glZ e,w3+,jY(۹ <v_tw,-D &A&nA"#"[D%:kj0 Dy42cAl0* Djt cw2+K$%A)v,] U qDAuAh7j jzv <tjj&.M]0DE#XCwN. :p4(C trsgVt,= *$T z|)|RA'-^h t9<pzm v]'E4P"@k 3znSt sTekfz! lp%WK D`Q" ~X Y 1a J; Rqh } "iMA v|n9NjEDX &ACJ1>q =6?0WLwlo q5yHPa0HYK{J*/C(ZLC%Kk %>&-lP,z!T<ojogqhf~PhAvuy57^XG$3& SAUR1, 0, 6, 0LISTINFOIPRD99 Drum SamplesIART 99SoundsIGNRSound LibraryICMT"http://99sounds.org/drum-samples/ICRD October 2014id3 ID3MTALB#99 Drum SamplesTCONSound LibraryTPE199SoundsCOMMNenghttp://99sounds.org/drum-samples/drum-machine-2.2.0/data/drumkit/kick-2.wav000066400000000000000000000546771514070543000202750ustar00rootroot00000000000000RIFFYWAVEfmt DXdata V%q)sCG7j7Tm]p9-NT$n"*B]L:UN"  e~ v!PSH*]z"A>2DiaH{V .6TA~b& 1 lJ?#(]!) !C^F'1ĺr 2 $4ECG>3"/iٷ۰U0YL\ ^1ajis`XQN @!ηe.i6PW(OD/ 0TԆh-Hà  X y 3 +I0>;=93.I$3M47C57"2MKCsC929K20'-t'upr(:9m+d#% {|0f]%"ѐ?)a28} vߴ`d?=(tƉ-N_շ½飚l$|dd=uė`Ġa̐׽ѹŶ&9?IԏhEÎV:ʅD K"+:˺#\:= Y -W{  }V`_P #51k776,n Z-@*$=@A80T-2/3(_C!-,V'9--.B V TD&dN> #y1z56E-Z&0B(H@3,0S>aZ\d^P`@>GIrEDND=2$(~'6HHr=5%?)|0=,*[-(* g>w|kF6]kQő7y#ۻy̫Džƻh%֠ )gWԳ/˟bڠ:xްA9gMUHG_sv[ 84Ӌݛ읣pޔD}W;ڟT6z}~Н~R4xڟ:t_ƮFκLBĦ]?#u:+>Ŧ;o4ՙؑS!Kݚ<~fotS z ( , /#P"z. 1+))<+2i97,4MIRZ\P?A4[.mqutrssqppBommmkk1lllBkVgc ``e fcdccRa/\VV\^\9[YTPT2WUSPSPJG6GGK&LGC=;@+DR@a<<:4///*#%-0+&Q" Mb[S \+>"=_+zޭ¾.Ɓĺ081+IꜼҽw.^zՎ3Όt֚bi {3] 1Nj΁7sׅ@҈3_će/t7UHP\uay YψoΌƌچKȋލg44ʐcЎZ?gNӖQȓޚܗ0wܟҢgם͠iާ6{0K$|UKQ"i7҅CїX"4ۦIjrVN1umV g!U "ww w+r&y 8%.>C4&*O;H}DG?@ >=?BD.EGGE%LWXRI?FcSeOfFqJV!\\@]]YO~A>fR\ VjX0^]]]YRNAV(ab_^pYRP!V \>]s\AXO&P]Ue~b_]'ZTkPU]"[mUX_7a"`_[T"OS^i`z[XVX[gZY]E^Y5U8NUM-YJ`\WUUQVP NV\"][_\SJJT2[XTUOSJMTU;S)NQSwMJlQ|XTK-Ed@xKXSNKAC/HGE@K89A=1:KNI?C?;3K.*R%*687=@>;7#.MM g 8:54,E +*",6/./! |n'%~|%"%  1 X k s # Y _0 5 ׏W|1ۚA"̩Årrh:+TX{"ԣɜʋѸ}9$ΌO; {ېЎ{oÏ>вXȱ&ȵD 1[׳dۯ2զܥӤܥ2)ѭ$Y 5)?=/ǩW7>ө'Cɯc:֧cIUu'|x\iȥL\ϯ3ZkP;7հ۰Ƭg/vjL,gN0+R>Ŀɠ4T@s!Mʨț2aЫA ʟҬHۆ֙׹f$@mA^id( |*- L W j"$d l&a%v01 (vl,9:-y'b3i<4,.+',&9Z??6<\2x.9D>4-f.CLA9 CNL{@/)8YHOY`]WK:9-7K`[eGcUUDGm``@LBt;FceUMX;eZg_EUNQKHTfa6X\_+Z8Xbwke[L>jK8f/gO\A`dGcb`Y$NmDQYi`hnb e\V9X VZb`9[_dc9a>`_^>ZTKpP`c_ _\Y:YnZVS\dQ`4[hX\Ecbeb[?SL*LV`YS X`nc_W PcI#N~YZZ]^QZT!QPRuUV|T)S\RPNSJXeUO}MORPIFdHSK!JGIPR9MF@HAmJLD\DhFDGQKJFx@73ALD@C>:.:T730~6@> A@;/5< :>74:}<71d 16..F1@/I(#/%Q-!%%s$&6 [r% N 7f% ]\ ? =srЯB( V4 ڜInђش!H\Hސ",/Ę#hyͧʶn𺻷̗ݬ=d{'?ѭi2ϯ*͡|P<ډևQ;G.X ɴ˦ʤպҽ@Oأӧ?0)=㬟nu|Ǵ뱳N#ũ$ NK&_ͳ79ʹ~Ե\ꮝZﱭhXۮm>¦wD/ E2;mkmƶ0%F|xq G:¼G̢N9+%Я̾ʆ81ҟQYbwK-OԓߎݼBr.UbܙvM_9ܡ'xCJIp:E~Im%# 1" * !-72!3$BEw*,+(h&z ,*7#-1W)4|-!l%+6(9y0'# 2B6,-./#'t8FGE2P"2)Z65=$7. *-,D--:HE8K.)9("+'u43*/vDJPH3:f+&8MaSP&I;?%+FzL9HA?:9?.AA#DBAAd<525Z>F)D99tAAD2>5?,L13GNCBq:&2&+Q772/5?Bp>6637:5j/ /<-b*_55C,A5:4&V(:<8L93))s2r6o3i06*F#7-9-4.d0(e `-&8{70`+2&"W'7./4.*$,?'*;/#z">"%&" "#b"_-@7+"T(b-!*: $F+"o F!j $"l pW!G O: Q+"jF1w .4 oP6yh6P# $H!^%Uk3{b,US-͡ՙUr[V܍ݧՈϦܷõ@߀>|йȌɏ—φ\̙р5ΩWOèʬ"ӡ՚# ؑӖ3аe͖ʘmCj 1ܷ",һ ~Ɖ\I#Wˣڽ@Wʧ׮Ƒ,i |_ڹ1´sZJ^rTjoѦމv +& y԰` N]+ʵ@TfymG{Xܺ].Ф|7s:g}W0kjۍ"jݑϣϯդ^cԉ $~qҲ} KWS ܔ TVgԣ5m5YfWkzt@Fn˒:{%޸ F4{h=xڟI)gKٯۜ߳;b7bLV9Wo~lHV)L4 PNOh;mf(Z M X s$7{> (  $ ]ODgf 2 C *iV/+& $)~"  d$.(( I$/*2&5.LC1 /:;6,#Eu :6?M;<1b%%7.,$'}147!<;g1[% "v'1.=>4+{']-:7C&@:9j2f+3?n>3-!7C+D;R32,-;RDA/DD?j4-17xGKDg=z83 /1?HD=8?6679=>@:2O0::yG MJC4<'R'c5 BD@;4F~Q@wT@4%q%߭Vڛn-۸޹h1ٱSDjʹӮ+-t@Jѳ۴}i<Qhq1m^ٹb4A4EZ݃ft nS֩!^fؐڈ =$ڠ'[dO(rTȃԁ6`87M̎Xg0'GMx^OӅԮ]#߯֎*xְ2ԑ)7eӘށry,RҢlC|zHu2? )%}QpwnFߠkGٍަH8ۆo"i$ R)5ef[ElLv1 N 'ZN<%U=}3J ?S h8Q S*\s e8 X v? x ^Tv6d`C>*o#JV+v 0S j7:# VmgF |( i =8 c m DDR Z )G    AHvG !  2=@b Y 9tm B2 cs !E N pv %%)b  >A  ' g^S!7J C m%' G 3  xr;1x(lJI  ^P+   XC? `$ "A w$  0; 4 S D p "  u6 |%& 7hJ L  / X V|    Gc#?&i'L > orMt tz e {+ ML}   aX :3s7T7jEyoV4|8  } P  >  c@ R23   W-4 t cV6 M 0'+H s+w bqpATJ `!t9 6p| %K 41;( Y$r ]vG{l{Tbnuxp3J3U~ZBAxc89!d`bJ ^ ++]f;FSo]@ 9-Pnz{-*Q! ZoEdga7nkY.2AZ27K553p'[5([AW&Y+guT{\f o5/}~;3[F)~t@>g{$ n^  !alCJ4(mOb _~I"`t4lRn,rL y^Cldk5c 7 ^o"fdRQ|V3)|w@hy(K_0}0F</1Q}a"N 4 " X %  O!E |X?_ 3M% b# DD1 Zj E! 4x # ^ +  T \7F 9 ! } iUM`L U  E-e 2;c  y%X1ITE$0'e> K|DTk1r*:EQw J\ S'EMr[@ _   Gj;=2y z#.^WF]e`u_\|GQiw:*q N) ( [Cp+8?IxcrGbaad1GA+RG:u~jT2oN8R:OpK,H $4]~FaQF)3/`-!4lOe)C uYv(sLg}-]njyR(b2q;J % T!X]&6oV=dxJOooI*Ei qH~RpVM?|q{?U['X|% b})vI! r)  R) 3dVy 3 ~Y'X3>{ b `EB|< i g1[  v * bRvDb7Qp ity4l$\W.t5'qJto' Qr nY=-zoC3{`l+X aJo&uDmWAU3EzO+c: G[T*]g:%y{| ,rmR0:<~dt26yZC!<,5L 1:[m{" *nDs)L`D P".2 :|qfpu}JGl6I}059rH@*tzcc>&vo>&f$RR^b: s"uV}(W*=BU_ir@HnC?4HQOWKlRc 3JaI bqGiR;Nq9}J05&MQLF(v<,2iqDsfr7,()DxX*DIfB!wKP}{B3v.AB!R282lVR`F(2uuee{Y35S  U>tO.}78Q,d{$*zX^ 9~g}P- a D47H7ky!C3{i{L3`0(gci  qW`xmT6 2s/f Ut :|$@DCi\2U7J .wqOQbS k! > 8bP h 7crmW|0YnQL $ . u pr& #K7s;Z"6 9RdDaO>K[N$TJxbdL$?3sFlIM#NA ;[ "+ZvX%$  dIg!6  %MSu!Mpk-+^L/ [0Cx 1U(\:z1. q %c@S }    V3 R [   R . r  ?n z  d G: ^  h$!TX 'B 8 < Aovc13  =@\P2#Y-Y&GGUujJPw]-K { zjjy~i 9oXw ZE c Q6j`ifB]"{b[[j5QXJ/>X]PQCY7js#:9a['n .UEj9e?M f%/Cmy/1EOrg#Bx9,Q4 Czw totO$-mMxY;y4f),e#vz"W jB+]34\e`<qw\iMl d$@;`MJYZ`Er}P%8_ x_TZ^!`swC;K^f%}~yKMHw;%_?~i"VFl 7C[`P^X,_NWX' h}?_s(}VWvmGSI W{CBMduq_L?!k0W!vbFj?&nz6",,Ebun.M)}AmMA[}K&H6lb:[f}yf}B{vh~q;0-| J . j lc"   e qB^*uwt HS5u F #e Q <& ?i?M GR\/S!0o&23vJ0\Wm ?G C*T(AZX4 ;,E(bE(Ic[ 4 [- X1C,o)d=] 5 x9g 5 [u`OOg Y~Rnz[fM{ <Z MW% @C&? ?}d,SY! 'Hy=l"X }DqTQ]PJ2U q5chG5Sjg * mDg%Fc(K RNp+Y j'e  #{L] ~N\W_ , efXk{@ LO v7mn^p {2!szMtb  -pkdbfK=-d=!A%7|N#9eqR7!F3KNw c=,S\*scA7inH 8_F%p?Y&e{ 722'U9sGs zqBceDr\>c{V{%GJx={u5S-:=s)k%(v{]7| Fqx#\ (R;5Dq%/af wcTE4/nV 3:S;m@7@Xk>/_ONx40n:H+L=l`Sn3V`vB?du("f,ti78utqQl| ;R8Hg/#T=P!\A[Rg@E0:(d.NVdUayhy=O  d`e*pz*%[yeUIVE? +d2zuT *j! tjQriPI~!{^D1d*^]gPeXvUV!pzN>$z`V?,Modws5e=l .j_'/q.,Kr ut{QaZn.rdelK=+yt (E_k]i* A&>C$0 5tz> b?Ggq;+Y|oZ`r78ra k2fD7e6,hw/"w~sAQ~TG a;TXkl{R+.winjnQZVJ( q[?& i& o?>  +5.tKCX%"j}fy<!&VR[WHo:|~W`Ruc5'J-r()% (c%J|U=ROJrG7:.!/ c}ZG7I1ajVJ6 +cmsrT//>B^mjprjpuO68%Klnpur5 NvsC7Mfy1DSXlYvGUUI^iiN?; ?wi=ZJ4AiZ -''_tK  #8NO c\$`Xnj}YEJkWe|t]Smyoj{bS~dcmpV6UzWDie9?d_N[cnTTd|}icu|^KerZ_rz{aZiqllkfj{}ha{p}lWJW~p`enrof_{p~yt|}rpotra~xSAUR1, 0, 6, 0LISTINFOIPRD99 Drum SamplesIART 99SoundsIGNRSound LibraryICMT"http://99sounds.org/drum-samples/ICRD October 2014id3 ID3MTALB#99 Drum SamplesTCONSound LibraryTPE199SoundsCOMMNenghttp://99sounds.org/drum-samples/drum-machine-2.2.0/data/drumkit/kick-3.wav000066400000000000000000001432371514070543000202650ustar00rootroot00000000000000RIFFWAVEfmt DdatahE K.Gl(ose+%Aiiy lg;\c`Ը!T̵8w//L$1~O| ͺfCm +nzՃk}zuQ !1#Z'0* .ʽ/J/"/!//...(/S5//.4-,w+)k(D%E#Ew!=yVLq  @܀ؖ{6VRm 욐k6ߺ݇ׯ)֞SԁҪ>0϶iΙ̧1v>..b`220i̮n%m\s~ZVx/eJP@+Ωު …ycp/v|{N%Ė^#.<QLθ&&U'R_eSw)10HZ H]>tK!$p(??+DJ.z13o6+K8H: <=G?@PAkBECvDbRD>@h;>HFAM(RRMC%5e>շ{ h&";E̅NR =e,<::87+6-483p1/L-.=,h*`(s&Q$D"|Nf[G-* mD_HO1]9UX@ZpׄͅǵùUZΑٌgBWUM`  tڏCfUsBmF촨Iٰ#25UxZµl_մ< kz$۸q﹙k;оaпF<šd"ɵ|ʠ%N=3бj+?2Ȁs;GݵxU'uL_ϫ~oGJ'xr ,`p%,N)4 s^g ^JZgڥ>&0b6v]:)<0='=?5@@?R?W>n=y<;Nw;H;);8;G1;-;O::6:988 7 64321Š0v/b.d=- ,*)5(&a%|#J"6 %V&Q[F@ ] ԰Yy`N[NO_}<1v߫I Dbقg 9z%φ΋!cι "F&˖p"[V5ʹ̡A4ŧ0eͭRX! P+:ؒ,5Dsӛ=#MLE5,iȂZBnH-=ׅ 66Ͳͧkγ)D%PNCҥ]ߜS'[|<ێj ?[Y5]=VnfWqF!<_7  D g+(";${&(*+[,R-hZ/01&2l34D5@96]6n77f88*9{9Z99B/:W:w::j::::s:rk:UK:#:9a99;988, 8q5r2Ę38H:j85?0&~-+s*3*ʄ T62 H<!(M<-0M2<3w2N110.`,+**ŧ)d)q))a)W)($(OM'T&xC% $f"k!4 <I$w|LSS2y_5o  {Sͻ~9:X)Vۄ ٣`~ѢJE͇gLɵ$GVqGS9ÊFivRþYDҽo̼]W,y ?廈!Ddo.ټ ^UFv5.HYMk"``ƃ5m@NLݲ܃y\d܂{)aȓi˵W̸qMe/ϙt WPэҭ_ӁՉ>/ ֟֎V0@`9nkR,u`:?,D?{ N]!-$!Ŭ$7')+&-/A1Q'345d17M8P9|;:;&;}<==^%>>>O?V??@u:@ [@#r@8@@s@wu@Qa@E@!@? ?[?M??>h>n>=4O=<x<<;_;: :~9m8W8717q642 /J1-5T741,$ L:W _$Ao(+(,),,Y+3)5([&$#<"u"!!!Nx!I!Q  5ՃVVetE  j :"Jc=)8|"xk℉Dn7A4J Ȅ{DZ >߯}0_<۾IýMl,f rGA'ab=P l9_]ևy2yxżLqн5~D>c=TtY`Ɔ ֺǁl!ɔnR?EPuw.C:M|mJ!%ߣ^iBXfWmT홨e)JY\R H"%“芛NFv}_=p]#JCYky ( wCzl!*$&)4,ԙ.|08 385|78:;#<=a>@y0A1B#CCDwEFF:GȰGaHyHHIMIg}IVIJI~ImIDItI~I IIGZIb)IHHiH-HcGlG G#FT6FEJEDIDCf4CB BOpA@--@ ?[>U)>u=tFrżN!?F9jz  >a &J { t\^y 94 POش'dw3hq0G$ c.йÍy>iC[@P9H׃CABPG#O ZvhKzΏ>b 5dϙtC$sb}f?@kAlBdCDXLE#EF4G1G';HHAItIIJJxUJJͼJJJKK"KLKKfJJBJRJoWJJ=IIAIHH+HlGRGFbF?Ef\ED_@DTC3CpBA=$Av@??U>=#<82ŭ170}/.-,A+@*)(Ӡ'ʎ&Dz%a$rF#='"!Ut dtd&)mG 3, ] ;V6SWf} yy!m;LbH!~' Ni͏ǩƇKǰ ő0Yp½Oe(ȬIȈ¡>VϜ|ӡa,݁P'ݫ=o`]E3پnHw@0u֕Օ#ԋ Ӛ ҠW$+ ơ.ÁÇJɋU_pҾD7cC$6ϻmƺ聺Bv߹iuvqKqz2+&Hւ%ź W]pټH>6Sg;HƿU $QpĦ0|>*^P#`}M_GDX- iVxgq(ۚ>܁YJxޯ4R䡋g UVzF7PI{b_MZHk>,@om, | 8))Vf%W;Z "T#%o&(so)* ,Mk-.+/1'2`3-E57n977[989:;;G@^FXK>PR!S[QPODN[LI*H`=GՕEC~IE2 H3|32?22B2^2H22t2@3394t45Y5e5&6t66=7-z7%78g88R8&9}q999= :WC:9d:;:!::::::5:::ݾ::,:?Y:/:99΀9=9Y888G8s7$7t!776@6!5I5r4>43x3Z2Y1|I1\0/sM/2.-*-m,+l**L)z(B'N&%%-/${H#q^"yp!% Ή9|m Z3ɹ+'+g(DɂKjɜK \ɩc4ɲyɧ>ў ʂ/[X>`˹Y58˂˪ʧp1C>_7ѨNɎoQcj?@ABC3D\Ey0FFGoHYIIG[JJfvKrK"oLLHMӨM(N"SNNNO[SO&a&j&&ۙ&&&&I&x&3&h&@&}&&&&&&c&&Q%%g%S)% $ $B$u##1#"c`"+!{!*!b &vW&9p?&wk!jTK>yu'%:F6O -S {Q I ? h-.sְ]Q!M;QI#IApL IB6E4$Md]=|۝ԉhp03fk}̩t_ y= !gQ\θ6(b.G4 z)wqb/V®|=ҭt`RF1"t$3WHa~Aǭ= nS0vĮDQԯi"rưy*ر9$oܳ,Mk5~G(U$-(*r8@ùO&޺bmA,\ܽ^Oӽ]9Esy÷$,5ھHݴPyĐW=ƆA'aX[ΨψkB&s̻_͘5EFpսB?ޙ,뢇f*:ۤRKIfq9uQtB<"$-BJH$q[q;q$ ~3>ݭQ9ʶl^6\MN+B0tǹ:X¯ l>̮$& /۾SR0:zïq+:svՋmTA3G+ ( I+ 3 @ Sl6Un3>3\}s{ )"n#q$K&ݯ')V|*+fI-.0y12:4256G89':K1[?oAGKBpC[DզEFGSHI1JKrLIM]NNhOrYPQ'QPRRwSYS:TThU2U4VVVy1WwWhWW#XPXWwXzXXX&X(XXmXX-XXX~XxtXPX(XWWǕW ]W8W;VVOVVUA\UUT JTSSSϭR?RQWQPdPOfON~]NM.KML.LМKKqJI>@IɣHH,eGHF5FyED\)Dg~CB%BvA"@@b?>#=C= <;S;c:'9818Yt76b5(95y43272u10/-/ j.-,,S+g* J**5*I't7%$#\$%%%&eu'̏(Ni'&% %%t%#e"}!A" -(L`;%OwG" bWtR  vk=8N|b0Ccך2J u+\\^.rIBcаXYmZ$HِOJg4HNV_$a+^S[C,#VpZ#U?W%(N[6OR*累Gߙ6V/ p#t!5;|_P夘dLܱ0uZ<OC^5 ˍihCȘTXĹáksi(ffkvq=ܶ{3Tix0WEְ)4R~s}뭑h x >!(i<ĭZo6If֨ݮ쌨3%%&wq&S&`''f(^(7~)**A+1+,$--v.#//Z0511)2U3 44z5166M7S899h:;;Zo<=J=r]>`>T?/@@UAAkB'B}rCPC hD0D+LE2EFmF=F8GGRG(HpHsH H9+I`IIqII JM+JFJ^J>sJJ2JJߚJכJIJJJxJgJQJ8JJYIIMI;I9^I-IH~HHIHHhGzG.GF\F97FEEi#ED ]DJCCCB7BAHAy@;O@[?L?>?>´=,(=֙<t\TңΕ(̌>zY[$:u|Ƅr#ÿpUA َM~Rn}&z8 ۷T(ݹ=<::ls 䰸7n ɯ&Y⟲z8ҳ!{kഽ^䛶Y+9GغĻ讼szT\T:D?æ\dG@ƂBdʪ-ˮ̒dOk3 1<:SQlU6ԃY1Yn_>~PY0=ם]חxjמ׆Шݦ׶Dס~lRj3gi6[$Qpն/0ԪO]Ԯ>ӛ{ӌ,ӢhҜ=KJeLѣ~ЅZ ж6n ϒ'Aͽqq/#ְUu)<-̵O.mr?˩˙'|hzON8ʕ$#mɁɒɻɆ/Lʪ&ʜ9ʫO$iq]rʅ:HgˌVO3l̵̇]'rk %Dΐ5Ϥe#?2[`*ѯ-\ӚtӟYԢG>0֥<׭CطQgHۣ6ܙ:ݨݕf_j@40m[ UMKeBK{6kb(_WRK  N  dL 1DZJ< xJF (H9D5=G t0. .b!"E"#E$$%h&''S(W6)$)*F++,hM--.I/K/091 1~23;3fX44[5$66O77s89'9$::/;;:<<<=T=E7>9>(??@@@`A1AA5BB=CaCCIDzDvDP)E~EE3 FmFFGFGމGGh H.>Gt>?e?@09AcAeA@U@d?x>0Z=Y<}I;[:n9-8$7o7%<6n5s432E10/͒.z->f,O+=?*.)$('[&%$j #"!A )t6I`}P"8Z""o'{hLк2a0B E 2s  j ?a  "  KD d i ! Gz BS 0  ?pB?  N8 R To ڍ W p 8 ]  u ! 7 AA wg F V C e  /   6 O f "} h d \ ( : w  e l љ o Y > " w Y  y P & q c |, - { :< , ߵ o ' A#LJ@P@gi'Yb||0\6\F7c1j:I[i\rvwjxuonU1dU":D<02o/BR+2P'~ W0(p7D譭~N儶b'RᄅSލʅRѸ نڄVw؇&اֽ`4 ԳvIOҨѓ+ц {Gί^AͷGsk2˼!aʃĎm 7qȪ ǿdrĚ3¿lMŸm„*[3AԾKv/iA,n%Eѻ;Lk[)ZqU7˸f8 ~l=K* %׶_tf\SKMFC&BhBE[JQMYeq(~)"̶o4S~te[n1\aOH|_ ZuҺ=O萻һ<Y<9/xý'\em I՚%A2A)nK¥S^ÍĶwqM8Ź_Ƹ'ǐIǖ[Ȓ)hEgJ=˿ ̮̫ya͑aA"^ωCzЅaѦJ26bE$ԩ 8n{@nfbYWYn E^-"]!naM6y(_@wJ_US>(]^@j43dsjg+AP3Hk`#ID"%+cOFQF@hDuC<^Xo *"dyi;vPy_ RR D B != ]=Z9^8/(> @HgqKI&-@^GB F!!"7##e$${%%|&&e'R'5(z((A))8)t*Q****W+&+@+6U+e+p+v+x+t+|k+_+mN+79+++=*ľ**j*;* *)Ú)Ya)s$)_(+(@](X( '.'%7'&&J&%%hR%$ $}Q$#a#O#""H"!!>C!S  uC 5I"-V=n6" =H/{:G(n=[T@gCe!iЂIpO_PnC9]1*&;$$M'*0l8)CO^^m(Y"1^R3t)ټ0 .7,cue"U9 /iXu\uoT_*/t[M_, x ' !`!!!FN",""B###89$w$$4%w%%]0&S&&-'''*(~((_')z))P"*Iu*:*4+@l++,^,,k,J-1--3.../v^/ /'/50|001 I1v11 2L2/22\3<3uv3334&P44[4'45B5n55v556+76;Z6|6e66#6]67!)7?A7bV7i7|777֬7D77777737777J7H7777W7w7774}7Wk7V7A7*77g6p6666c6UB6655595g\5255454{4K4E433|3F332Μ2 b2b&2*11l1;-180 0'f0!0/u/+Q//.u.l*.--B-5,W,)S,,+[++C*^**)GX)Z((hK(!''T8'-&u|&&ǿ%^%$q$<$#w#$#"K"!ȁ!!V pO ЀҰGtr #6&`|a }Cyi)9q LCfzϫ< ]2~ -H-ҽL9k  I Ө n7 U r    ǭ =sP[Px,%=Dc-p2SRt-'mtK2p01(ºMuA 74I]]'W yLz|yBts yApuGAeXXS4*4q|T-8},g 瑱gWk?Jn_Tg=+^}h- ;R9l?۵3Nܬr'#gr< pohqٮ٢wؠآT0 ]ٍ!ه(u sы ׀ׇX׆|vY.Xm/ֺյի4tԴ[v6K_Z%r n GɁb1TjWeҏfҖw ҙ}rК?dmΝάn?` d |\ʰɖ9ZȘcb ]lM\6+pzz{ڊZ;ڽużw) oQ8 j忺s ef[XFZconں00aһVW=rLR[:}>[0%G?VCOĹgũ=Gȴ#zpʑʭQ{đL1͵͒vϋ\bбBѢO?Йӳ>aφդ)ipIűQٶp.ۦfݬN1:.\߷ߵ..iBLNEU8~UUZK9!T4k;[) fh!i|S(~w"kD[ IcR+^yAtjg+/Icy;?@\:z >mf8f{$kZI38"%1hȿ9iEU:?e(qcNrt]FL0T;r]pJ6$qCUtgYtNC-9.% LUsd% g!+=5c?"JWdbr>:/*+DBZp<'.2QnG8[&n?hb_:d7E sN.21d8++}^*/)d<4tW](@|ɸ|a1opK)f#$_dŤ/'!gU.@p7z?E%go`Wɛ,&Wke<9  Su%lkIS/@ 9 0 Y  i , s N gG % W ` } f 4WzCXLˑ|cd3xSI5g]Ơ'(9mӱ8j|ÿymF;b OlU@XX]WזQR4 Jf@; wP)abԜJ#- c К   !X?!%t!\!N!"kH"|"'"" #I#w|##X#$A$dq$$o$%/%q]%%%/%?&A& m&&[&&'B'k'ɔ'н''O (4(0](Y((y(^()?)c))#)))*2*sS*Fu*o*E**)*+0+N+k+!++++[+,),C,[,t,{,ߢ,:,,,,-%-8-dK-_-p- -˔-Ƥ--Z-h---- . .v".1..8.B.K.0U.=\.e.k.r.y.. .̉.Ќ....T... .....j&/C=/R.^.4-3c--y//-S00R11ڴ1*11A10&H0//'/o/*W/W/>///.....U.-,z,K ,7+c+z+`+N+(*s* m**GK*x*~**M *)))H)|)I)si){)w)t=))*))ϻ(+c((,,(ߥ((h(aM(''l&%va% %$=$$h%|N%%%P%&3&6K&d&v&&p&L&&'<'k''''(<(a(~((((((( ))),)))))c((((ۘ(v(Q( '('''\'"'&&eX&W&d%;o%%$f$P$#@#h"m"!!! ) V.-*gv2Qk$f`Uv0C?3FқSGݜ /E , A J |2A[!A~EdO c DM sB k!TfB7 76<-I]_E |&;8k3G7\;S,R[鈿}y6N ;{?Vk;t ȶhD`"ǩwaLG:' g> TnH~-\!.-=N]`0r䩄. O4M5g嘛并 (Fb??IR<\{笜H] @a#/Y *Kl/餭=/:Po꺎1^ ,0Jhg뗣1LNhGL-4wLd{킐-R 햣wknZIh7%-KG쵉ubN\:%b1멬֙Noq[FB1>*?RvDaK6"V =陓~k6U@Q,_ g.ތzgT@,^*砗罅sa}P?b- *ZzZjX[L>/ >ɴӨ冑]ymbWLB9-%rpv98cUR[䮣䧘䧏ʌMπ}zutpnLnmlkmklj^kl$mwmoprtOw0zr~"亊j&Ǟ+5䆵]k7KY ('4>JJUTb=o:|匤G>~8!1D/UfVyG۱:/-{BXn烄:ܲd*1C\u[蜪My}1N:k%?G8}Wuc[s5Vv믺*!iCf얈ܬr&=`^w"eAf( Rwﬠ$A{jet9H 7;a9 4_׊P& y9@e\@k` /M$z}s *V dx Wr@:ڇL[Cn·U7?) PN[s> ?X! SpH'!bO7.v9xMv&%gJkcr`pbyv0+E5)7.+Z$l)SFU;-+o,-,0S,gv,,,,, -"-`7-L-G^-o-3~-_-- ---e-ɷ---3-B------|-xm-\-L-9-#$-!-, ,,',,!m,M,,,3 ,K++>+9v+M+%+**z*Dv*G**o)s)d)XP))((4{(B( (V''v^'^"'&&n&0&,%D%s%u3%$IJ$bq$.$_##g#1$#""Y""o!!E!! tu / e0\;APrn'T&#=;0֯j$Tdž4B|uZ4;m)Ƨe%)d[&i)7r7JIa)S8K\!s1@  q > o y [I R p <  _ |1 y b 4V *+  \ 5 c5tOs+{WR7/@=vxvX:znk9t[Y_>x#a "ħ2zb~L7 g `6ޑr}k"ZFn6%!j)wj]WQCu6)rHZ[c6zpqiabYPMJPB;4,' A X!,[6q?>5 -p\dO<~|zxxvutsqpnkkhgf@fbe7oۀrcTICT4B$Yyiq`O@/9 } &sb;P#@. Jzi/dl\;J7&pL<"t]a%P|>O-m ,p .veRAw0i RZ=ˠ|KkXF"60#C]CWwXCr`NO>8-% b#A-of^L;w+)N H 3Stc"SkCD2#(,|25N%MtMeCV.GL7'(|fM TWb8SvgYWJ/<- .YPϤL|n|bTeH 75)'S쏖`{8tZbB>A 1z*(22($뙾 BRf]qE'#Z)*4CZ6dʀތ¨t>Z F&>gq픜Vn Z;Vi}@~G Z-hH4sﱅ$%$C6cuHq?M'&4iR~n{I߱  &|00D:Xk~ =s&.3 7:==?= HKp Jى L7bVLbܥ|-r=Y~ MDv_*qoA;nHό6aTz[0F_D]NoVAKE/M: &t l 3! Z s  : -q C  QI Q} K  ( I |  ?;oc+ *9XXհ 1[g%&OtbA q.jQZtn=k=B[zy#*EPa`{{(@wV0le0T 0@Q1cq[L¹hz2Y  (3;XCKQYl_ej!pty|v8  =xnHsƑO&}jxtjpjfbZUNHAx82*G!>b!+OR<W}pc[WI<E- &e`{ lQZH7^':.vQcO<*=}9ݍ!zd8Q":'"gLm ~iST=1(k~w`#J4\߫S_ph4P6:[# 4j@R;}# FǘajOQ:P#4   t .j R < :%   2 k UU > O'    3 : t ^ I 2 |  : 5 d ެ l X RA -, `  V  8o GZ E +2 }  J-йS|gUA,LaY4''p^J8'=ڼV#wfSC 3N!EPp`PB2#LG+%pivhYLJ?i2$  9kDsQgQ[)OKD9-k#d {&H@uCn`ypf]NTKA49/'G 5 d)lA1BܔU+wpKiqc]W Vi 1YɧyM2L/ߕ$4 }TzxvtqoUnnjffcb_\;Y$WTQN.L^HF_C-@= ;E941.+(f&"}:Z A q1JǴwϒ}~xsobkfa\"XRNID@O<]71,k(K# oNa1]!ȺڵD4!~wr.k*f`ZSOnH87~,>CAH&,ϩ(eK6=@H6OYZb`Qh)cX4LDDFTVY\RTVzZ6XWCVSiTTYzV\`\QRTNC507x=<.-%| `VջRxkdXJ=A,cZ2 Q)q[N?1#v=c*> v`PHE5qaE˛ewI9F0!@|Ncxl=ςkr_,Hw0l*PƊ|n^.QA3 (m$d'F.x"=&b3@N]l}X0nK$ 0,AnY pFݠ i9TmܤKh /[J5h6+Eia}[[U4LgL@ g4G\pTBcG=|.$0m<JVaktm}δ^ַ8(8F\~ wmcZOEf9+-64zxeSA,YHa~zjWb* F]byLiD-1F1`xԒ7\-"G9alz|e5/XI0a{є*/FHVayZKi*wC[mtz@ `747Ogm3Gc3x' 1D H ^L P U Z ` c h Lk ?q t w y {|  U 7 w u Y 6 O | D & ը թ # T " 1 Ы 6 N P ݩ ԧ  r ء Ş Y  ՙ 5 ' * x N p J o| x u Kq o Pk Oh d !` \ X R O J MG 2C = _: 5 70 + & " ) s {  x w b ߨ Ǣ d S x q i b \ T O 5E > 4 i- & !  f  ~  Q C ( (  ˧ E ȍ =| %r h _ V M D : 1 ( e } y Lfީ#][6x9m dRZOD:/%plk޼ڧ]'|q0g]2PE=+0%_r<Cy<Y! Ivl`THC?4I)j Hwla WL@6)0 HD3*W4%g|`oe3ZNhDO:-.%U]< 9<@Mzzq|fS]hQHY>3)b X76%Ʀ!~MuZk`yY*NF<2) )=_(קnRzEr)i_:{>gT U2FWNҊe}PytqXm}ieuc_[XTjPLgHDB?3:752.G,)$!Z O &&Cs 4-rR!B*..)X$~ n^`Z:hӷ,z-&Cӏ|}}BE'`ޣ{U!W4`,W"p06A7=zAF8LT ]e%no'u"ێ##(F!2RY]$_ !%OKgI9z4B|na?4|P?÷Ĩqė*}Itpj7aVdJB5Y+ tjФ͙AjreWIG>0?#*t5M}reb[>PBw8.i"2Q tcIc+8jz$uplShb0`A]`ZXVUSZQPOZOMMK PNQQSVXu[!_]b\ehloptzT"ʦֺM 2(2->XJiT_jw?oxlnueV)7D%R`nF|_%CCV *)L8GVqd}sF6Bx_$L%3AO ^alzډQw`R -;VHGUap^}̡!Q  ,G7qAMWfajt~?C"ܵ{8&'O?"*1r6<FDIQOSY_cfkqvzC~Sҏaʗ6z)ұ<'ն6طն0T3Fɔs= }Sxv0q=mid_ZSVQMH3C?9V4/)%V AYvZǸ=" ц=xUqh`YQIB :2w*\#ap bٿ =6 Zygph^VLVE;y1) h f<*}ϩMJzr)j`0XNE<=2* \m HKlf4|6sjcZ;PF?56/!%k{Y Z4ԭg8kS_}vl+f]UMjEu=4-& 4 g@H:|2ǿDm^/}vpjb[VO"IB<6&1G+N& ?4VN 0qXDݴί;@Aہ5ywsNplhfIc_.\YVRONSJHZDB@> ;i8`621Y0\.*)@(%&$# 13$m34 t . E A 9 02|Nw@!!7#u$%(),k/0H2F55n6a:>uB)D GIfK3NPRVX[^`7dh=jmnpsw_z`~Ào5> 0*$ߦ/] y9o!%"*069=sCHIMRW]jcimsXx}Iog:_1V-S_RP&. O$T*06*=dCIOU[bchn9u{;Ǝk@ظl,L  L!'.,5<_C`IOV\bipv}a9?xn e "(.5;GBGNU[ahot{P[ 8TVqE}',1A8@ENKRQWa]ciMouP|K)ݮ4ET ZJ $).3:?DIM TY^bDhlrv{€ɏ%otҿE vER#x|z  ,g!%+Q.C47:>eA5EHiM^Q.UY[` dfjxnkpgux{( MƗޜamfjMC0ַEμi`Y ;sOhR8oQa& 8 Z~bo {!#P&&'%)k**-./022C44788 9:<<g>=K>?1AABABeD$ErFJG+HG2HOHHHJ^K7LKJKLMN_NKMMjMKLL?NMO9ONMLMMML9NM%M@M0NM LJKIJIJHHGGEGGpGEE-DBICBA??k?=7=<;:/:?9;8v7$6n53931;1O0/-,+|*)I)>(a&$#!: s32$gN   J {M=inU0żعȷ̥ܲk>z,RN~Mz!x~vtIBAJ>9l61./c+ (e$$` h!Kr(43C=Xg *| ?i'Yk:D=S'RDMhvdsNEc&AT.:lC o  gd}6Oe|( H!V#G$&d(f*U-/01923579;>?AOC#EFKHJKMORTU+WXFY[\`^`]aaqbicdf}hi~jkm'oo>ppr.ssss'tuuBvqvuWK5#h(ggčU[v~}|`zxWw?ut/trNp#nbmNn mjigf[eccdccNcc{b#` `u_`_*^]*^Z_ _]]^?^^]F___Z`__`b cxbccRce_ffigj6jjjAlnoopst3vv!wy5||}oUtכ E̱<ͼCNGc ?*:xb Xq nzU g"%d(+^.2b48N:=@NCEHJMRPSV[Z\+_lacfjn[d?*xةЧVOYKΥd ޤߣH¢ NPpu:+%=-ۏd5Zn҂y%~a~{l{wyxvt&trFrpnnllGj h=gtdcac`A_^v\YY WU$TSRN\MK*K*J)HEC{B@>=Q<98d63U3K0/++('%%w"b  bum } eO+fwKguK#J}nJ| !]rŷ޶zTLAMң` lʑC}a|z/xubt[ronjigec` _]\XWVxSR+QNKUKHECNBf??=9{9574200|- +)n'%$# y q N Tp:X;82z|m"2T%?/At]2&û%|eE*/08`ԥy9dӠϞʜ՛Ěݙ*T>D֔'b@ގvȎN9 UGׅq  *D߃ ځL AeVC,Ii!y%h"߆UÈʈ\1H7`{1`jP|yʙf $KҢ8aY Īά>C](=>ս|p(ABHC`yhF|06O8fKWUxZ, dD^QW!#$K&~'n)*O,-`0256~8g9:;I=>?DA&CDEGI;L^N{PkRTT VW=YZ[]_`Zb$degikmpoPq-stvxyzg|}NʀK؃|r‰*NYqז̘_sEʱIö!A1%C%D0vxA2j\"bdBp- M ],?#.{b !p"%k''),-2.81!45 8:%:<>?C@BCDHF}HJL7OOQTTVYYZ\t^c_`cefhi&klLmnpRqsHvw5z{|$U@ԅĉR%[sjاϩl3]6KHbQU<(*A"!9`v6 0;V$TeJ*HoNNq'}V`y-r    ^  VVr@OzVoM4:   ""%""!"$u%'2+.023 4J3+32I1001323 4Z43?412l010<02(11?11<211010g/.0/02O11Y22/10123\44475785X75 549:;:e<<=*=<<<=.@?AKACxDEFFEW{W~V}WU}TRNLWLQLIJ)KJL,K KNKJOK?J3JI}II&JqIbH\H[FFDDEDD>BCAAA??<S=M;9856H432 1-.l+)]'&z#i"35*i  Bc.5QdA"%LVxG-!E#8X}Az~R|.zwuFtrpnl!kj#i1hf ecNb#a`_^ ][ZjZZZ#X5WoVtTTT"TRRRlPP}QWR@RMQOOPP{POPFPhPPP[QnQ-QQRR4RSTSmTSUiUKWcXXYYYY[Zn]\]^_Sa^\ZPYWVUT}SRtP OM7LJMIGErCIA ?<);9876H4{2E1 0.N-+ *(?'7%"R /OKt[_I \  CL{N m 5 }wx@ot0 qc9o֭4^?AcRjdDϏ RoĀ~|y{ zHxHwv&ussp*onn_lmkjgf"f[ed)dfcb`^]\#[ZYWV&VTTTSbR:PNNNML.KKfJ$IHFDDsDC CA?/?(?L?>=';::;W:86666u6t5@555n42'1=1x1N1d0.--..-\,*****)|(Z(('S''&U&0'''&$f$$k%d%%w$$$####f#'#G"(!!/"8""g"E!b D!)""""^#{#m"!7"! !!}""&"""!!")#e##5$ $#$%c&&&f%$$u%W&'([('l''B(;))*y++H**)*+, ./.t.--*.O/V0t12]3t322{22345,7\8(9Q99888'9:;;Q?V@ A1A`AHB1CCDEFGwH(I@IKImIIIJJnKLM'O%PPwQ}RYS"TUUV~W?XXSYY:ZZ=[[{\+]]^u_I`MaSbYcLdGe(fgghiRj kklmmnEoppqrvsItuuvwPxyyz~{O|4}F~iĂ׃ /U54U+x9 K]>+` ¦4!X?|̲rYù`z޿n>|nIQJQH y){^6!J6d}'G'}lFnu(Os$Fj5Vv8Yy @ a  ( I k  0 Q q  , I g  ( A [ w :Sm+AT_\W_x8NVEv`[t1Ut~JbNn2.>i<BvQejPY9 c : R F g ` " ?   Y * N i  D 5 T s  M6<gn#QIh*1S, ln5g4Ss&~oFcPPK3..Omv9?L:*5G<"XCQX)7i8:>*?07IT+|v5Lx_mQ{gId$ (-57B1OOS__FhoZCQl_bXWlj}kvesx|sh{vw^ezo[Gatrink[IgfZ;$6GI3!.+}|zhOQH9:9(zvohP?3-!weTJC<5+ {qfYNB4#{ocXL@3& SAUR1, 0, 6, 0LISTINFOIPRD99 Drum SamplesIART 99SoundsIGNRSound LibraryICMT"http://99sounds.org/drum-samples/ICRD October 2014id3 ID3MTALB#99 Drum SamplesTCONSound LibraryTPE199SoundsCOMMNenghttp://99sounds.org/drum-samples/drum-machine-2.2.0/data/drumkit/kick.wav000066400000000000000000000363211514070543000201200ustar00rootroot00000000000000RIFF<WAVEfmt DXdata29&z44]sA~/*k0ڎVj!+1c6841U38?A?7.($## po`K\ҳ+L/s-SIuF ').&1F N )/a%\[\$A9m[ԑ՛Hɨ)Nʼׂ ?MT6U$hZ{5vvdgH4$ EVI{Wya:3 +< /[[  ?$j$AmH]P@h8!4 #k1DC-iH ʹ$#iyv/`?7[sxvqiGI=Kzsϛb9׊C-Bޗޗʡl7:0̩j*۳6ðC$KȪwn5j+#E6=V v5@#%(+, 279;?DE@J<>9>IQY^`b``[YVUPOSVWZ_gce;]TQOUZTYU SRVL_+hkf] USJB=;ALX_`DbEcZJN@HFR]irUy|}|zvvtiTEk>d72x, Aq3u/*Xǿ@.LԫܪۛIr+Ж^e􋃋^ΎetQd;4֩fS$ _mqǭS=YSx c޺'ﻳr‚ ]æRý!%EΏϤ}>AۏUج\2S]E('@#!y  9 JA6 "$%5'X)(H''*-,-.13e4n4469]<;R<@ENHIJ.L OPQ^TVX Zc[\^`acfiklm\prkrTs#uvw8xxxax.yyLy*y/yz||yNvs2rtmwDyzM||}|||{zz3z<{||zHunidgfi'j`QzIKaT\`at^`'eilm~phssrqrBpmm+h^_VNjKHHH?2&Z"!h  mK 5G9L.>ΘIJ`z`Q*%ܔhq>Nl\ʧ;ZR :ƽgJԄcSyކҖN@qhËć5ᐧEsvkϚ}щA'ERH\aqRyǍ3Χﬖv(/ZݮBLл9Ϻ׺)½ܺ,̟OBzz: Hx,jݽJH/p"-m(Z A s d  ?b!G&$&%Af"w5_622!2B693C4%&+9@@@>h;96[AeUXz?*5 S|ieJsNhT^D GS*ot{9iJTU?NoS^aWKK Z_UOS`3g.ZqGC3Uk@paRSHVSRYd>c^?]_fkhk`QRM[}k'm ka[hrnbadi,rVs mekh{lzjms^{Y[Z`c_YXFXVvWM^ZNZLLfKXK|T9X8MG CR>=>YFDTP<7=9+68:j8776>35.,,)%["j!R(Su $< L `wf=@a ØǛR48ϵg+OƷQʂ_$Xzϳ9dRKњZ`̻nٯގʕ֪0ϕi %SJ ΒLّCDk^aƄG؉} a͍ϖTߌ򈙑 ב#֖ppj袨m2 󫵪ަܑ|Nα˪r*yĿŁ#H†#òˑq1f0kV4׏ J׭X+8׀)PZ: K" 5Z.-b(*; 9G..+5i/ 0&Q8q>=C8/)+%(9A?Ba?( 9OOK:*H.GTPL:G&y3PQHNP8?0j:RPVfPgNQ?PC7Ee$kcJ($=^oxo]>V0BuN?1|? j,tDW?M[TfKLTfwtZ/D@Lg pY/DL{NINT^qyn^I>JZ=eZe}[Zec[^8^V*V^^C` ahe7SLITbSP`\BiOgl[`TUVYpX,V#ctmNCMFZ*bdef'ghihd]PUyfnk[LSToeGmfU4KN`gTMW^S$KPgSsM M].gTXJF2:8KUTD55?7U>BG#O/VE(!&-,$,3D2I.+/2*gv }#a*,|$`@h  9h9M[Yyp&I#]Q RW>\r9QT6ZH4[#`ָBMė㠮 tEٻڿ^󨮧ͯR?(gbʡX>*Ѳ^(?W@iD=DOɝY~Ц*]ذ ֽQq #D52mϵ4ᑝ_cPƤ״^SТʜ+E͔ۡX9ɪǘM!`_b=$߹}<5㻸번2XD ڶʶܽ1jlN?»$<=B=mҸC0%ؕ֯ъיݒ#́ۇ1g|XhM(F~vm W&Q!C_%E$A_",/K-,(vY16H("190* 5R@@C=A /f_W3MT|>)5=4eHPROJHA6'7KcdL=MN\H=T`aO#G+X,eciSx92Ml(k^[|YZW7D6>uUfl@m|lkjfRS:l7aJcgmeG_beeqWgWcOakWSR.Wcj_6L6OhsmXA=Y*rojkZ_mPOSUCPP^#mpdNKZ\]d\MBDGT_\kbphZL+>4:EZZ?kdrONQ[0]SEH>>CL5SR TVuUMD;{40:[i+VFFG9+1OPV^t> * 8p7=IOH!6*1;:549@6@`:n:5 S/0'&43Fd;Ua <J)546t%s|#pz""] & (/&   J4` RoB)zQ4aR&vLܤ=\$1ը]"p{,|%/ֹͳyt΍Peե_u ɑ>ѼӸzlŞ5m^<}psS#pZڮ"5ȧ񩫳oK&٭C-e}wW,U:g8a۾¯S{tn첫+ mϪޥ0Ɓ6rXC;D4å^۲rII˜¾Ӽv2w?~Ͳ&ߵƩEdBѽZ2Wع˽Ȓ6ڇʡmZi;ҊΆ՘۩(Ɨ!ڽgRZg1:3 C#׆׫\V԰>G9ӵu=o 1$ DQzA  K. -]u  WO AJ725 K2R uV"{*&/ )X#$E o| '(Z"]"?$-Z83$#-..,)'-7<;8/m B,v;?@>29+.Y3B@EA)9:DKIOIH9IUOHIFDMMVRONHGJF9BGEQW]A[MBDKMIWEbI%O-NJIFLlLGCBDKE}GNRK?>IQ:P KrG?9;=IrO;KJcKE3?i9^7B GA9;@=8)8-8t7:AE@18*32P69P;:4'167{/+B33=@<0${!+5<<5*#l",K0t-,+$ $&&'B)'$R"+Zz"4(%-z% u!o )G  '$4&a80 6xd5KMj>yt6_ڐ]2& U]u֔;ھ8ITMNqsu͹6у:QŜĝ̰͞+ɉ_ ʘ}̉?+Ƣî6ŋZ1ıqO1_%f{›"jmS+ŐԻڻe4߸ODJ@r&Ùƹо4Y-^"2ʽH•PI5 huÁdZAr5:ŸLj;+Ýo7ʔk dīŴ>dғϷ.\Ȁ͹ I4́VUaԸҶsΧӭD.ѭ:0B(ܘްaܩ܉Fdڱ'$W gQ&.>q(@*?_E v*7Np(93HrG$s h Q)oo eW + 9 /   r \ * m E |  Y~K ' - !]!wQjVFi.&K!}!+pe.!%$(ZK"!e!! x - "!c3hE ) !*$# @l? 8"&$c4! !  U! _; ! !""~!%2$:Z2!wjH#$ !Ot$& R% (e":!%#c!/ 8 $&L"\R $#FBf #"5f#$Y!<gXL"# !2" e[8`2"" z!!m m :&n#$`o(|S/VcT-Np0|,ex$I9^ci&M ) l|;]p   e i { ] : g ) + . Byt  b&a!pqB kB&]:rVHY; 28Hg% 3FN~Bk-~v!x:?[zO}f NKmi177<:Yu(?Kn-! 3BQY1sf &ue&[T"w|@)?z+7=[ާipp$F,A.Q|"C9u5*ߐk)x@/ox31, - `e\TMp1&3ffbdtM5 ~^?xYgzm*M<:*TcYJ/EcV8XjUC_2S>f2A~dK\%%=Dfz h_gF<{Oi%s2{XPP&n1kt1*&F p Q` * ; O i { q d N  = #T 4  T vt Ej X _ $d?[ f| _ b/*aS8* 6`e [&@`L wR3Zr>g8<dw@6Zmy00ReBxM^3x6`.R4yckc l8'frxu-"OZ b%_b\Dj{t~%(J 5]b//Cps )QYwqY: 6T+ N M   2 I 0 DT,U  q N I GE  g  d u  $ I n [ _yuc wO; und:qdV A<wNBX/fcp>if" v2\ kii$I 0nfjkIlv*auY-uw\RL,Oa?*Qoayn+uPtuh | EPC7@OI{*.oq|G8a'.m/ #R3cd c3wWmcNO{RZTQ5Gu nW|T> R9[,.KYwj.\|$eWcwFP {  ]  ) u  #] ? U5  [  q  6 + E  Le p ] Q l   c  ! U$ d   X ,?'  v ^EI ^g@[! I   ] A4  4@=e $ J & # Q y ) f + i jb  T  ] q "  %  j h C W + ~  & b 4 @ G e \ 1 < #    } __ f b u  \ \ W=+ I+?fC w@"LdcXCXJfLy@fUvzv!MLCoM}](R{X- SxjmM !JQik,kL&tzf@oM6waK\#)r4@&O5ZdAes&h 8krL*]d zA}KcXslzQ2WW"t&(r_~rgcL@4.nmj>TZ7a6@_ 0{J/y,#*: 'bRBQrM=}-0\&%gY,9Qo{~YDjq$S-spJ/st#O,GR p4Gqe+BOc&O_5"vp_2\Q> >k}-r2-S75p5{K@w-awd>L"clmpjQXLt)[!Ny$1TRF .80QSkQv.WaRjPlGY-w$^Zq-F $lXp)22/Sc.V;iUEGy$ouscH~^{w~/I(]d8g@XskV /5[A^U 5C~+f[;P80]:U~=4U XQk \FG6=;}k=&J((j]86 *-.3~ X8IScdxA:bD2#EsFo)/KWx%>`$~2K-eYjae*8jqMO-/jeu>IzZI  a?*7y[)9ZC.Rs_7az`hK?Ca[v"3 f:uE[I54$*BL?3Ibq!1 8 mWhAzqO;Zu}K%,I8'.aKpR'WK'q4D Fp4[ $TDcNb~n\2yiGs.c;UeL^D7=8y]+&>cLZY7ZK>TA).,!'7&=&%3- (6HA;/"%,9*&;@117131AF:?D0#=A1:E=3CG>DFGIUXBF\THJBARRDIS\]QPRMUXYc[V^NEevedj\HTe]]cXUln_deVZfnk`do_Wc]euhhj[eq`^hdkoejv|oFMSfbeibshjzuorpjmoghplmtywstmkx{qprlsyqtyt|xq{~y}|xxuv||}}SAUR1, 0, 6, 0LISTINFOIPRD99 Drum SamplesIART 99SoundsIGNRSound LibraryICMT"http://99sounds.org/drum-samples/ICRD October 2014id3 ID3MTALB#99 Drum SamplesTCONSound LibraryTPE199SoundsCOMMNenghttp://99sounds.org/drum-samples/drum-machine-2.2.0/data/drumkit/meson.build000066400000000000000000000004741514070543000206220ustar00rootroot00000000000000drumkit_dir = meson.current_source_dir() drumkit_files = [ 'kick.wav', 'kick-2.wav', 'kick-3.wav', 'snare.wav', 'snare-2.wav', 'hihat.wav', 'hihat-2.wav', 'clap.wav', 'tom.wav', 'crash.wav', ] install_data(drumkit_files, install_dir: get_option('datadir') / 'drum-machine' / 'data' / 'drumkit')drum-machine-2.2.0/data/drumkit/snare-2.wav000066400000000000000000001025371514070543000204510ustar00rootroot00000000000000RIFFWWAVEfmt DdataH uC2D7O $\Bbi *LC!`{%45W CAu ᕇ 3|Z{5D<]-;oDo$/"E491%u)"'"L0ޒ]2%w.00]ج. W Uh'ۋ"4LԴM:C>H 'I$#]~Zi `vYMZSF>(nxS6k=``*Egܳ !m6:Ug SZր2c *P'nd◿j. yJ^lS6!SeUr賂|P0s)SfC?8o)O LY2GBo% |h7ݪd'V1V!xGvl -|&18C F>4 0>$9"!#`G#@:Gf[J&Cڥ89*Fq"r'$F3m:@@9N-(V@wl =-b"B=PL:PJ<=%AgK)x_N3/2U0}0l5R)::=4U,R#c>Y@p3- 'Ć%+.%-)%"oQ:;ǤBE!"IM"j)!K$S_f-s zLx  t n  JTeT n \Of Y,Jrl-yk? ae I *lNN(R Ii yn28X #䍠,%]bC3uCIҩYߑF/ܗ"Kɍ΅O׊!ωLYG)˚ǷF-$X̟G!S[ÃƪQƥ AT|ʈH0Q;}&DAGU'ᄑ]RXЊMGнST3ȳe&ދٲǓHȀޥu=ܿ6Hl˜ɜTWs JK/dAQ5K\Y(ZtZ ,n\E7Pн{}h' 1O(YLC6ZdW+pn${" G `fq(si ~cUc$ 칋Nn?` K"!AS)/'irph9'njMLchyH |+Z { *PC%V"r&>&z $$ !#$&s(Ϡ,2v7M8;3.^9!G+Ji?&>#'>9|MQP*bI8OP ZIcm< PMSP3I.?839o<;_;=:8:>C߻E:FqEEDlCuCpBBHB@v'?=a=>5@.#BUCC$DsBCx?K:TY7;9??CrDe@;׊9;?cA9A@ACXC/?6J,i'k-"4L7A4C0705;=_ N_aH#NA[a˱ΈS- ጠع*@;e[ֹujy0!Քpܳb́3yG64uҨMe'CB,ӜaVէsd .5ٯzO۫ҒdY:O( #.ohm j1/mj-okzv ][OÊ U.^"5ǥnq;gK5udʂmAx+J_-ʦ͉y7b\ R˵_^RI)"U ndнD6ԗr*Ԟ˵Ա0,թf zQsmq֍ ؛gN?܇u4LC0ue`(|k4YcBrpsYnxS:Ҋ,\NDмkdF<vAiItvR?inw46&M "2ss\@A{Cv"x<&U)$X+&4Dg->DuA1B~[ Cd t gz"1h7K693K5Y=h>BBt=vI774405M"40ý,r1b;@&A>;Ñ877e66̛8a6;1=X=i===b8>%>.R>l=c1L+#C!i#^$#%(, //Ջ+&$'_+u-ZK-*z(>'&%#!]\9ec_{e4pp+}u4?(%3LƹOxxR 7S Y|5, { 6mpSuEOe)cББf4tSL?IB#0Aep3 a;ͥ6L ڊ0̀ZyYqeʢRw5'uȧ]?3 *9eqMrվ[@;ҊR{tp(νNhֹ&Pq̡z6̙ɀiȮȘAٍ]8.lƢź'_zpmd9+&K.ݽĄs̔υnwҺDӅџNϱ-qOlf1̭{&!ߩި˅ 8`62Lku Зuڂ`\ ߼&xCEv*)֒7uݕ#*5D d.oݬ ~%T+.IVNWzqXu%aq=)hfC<8vmN),MoPȊ-(+sD:ztMFxBU F fYDDδfY&)(X#]&/!ls"'E.>4#66e}4D0W-;+<,*!'a=VGGBS8/߶.Ŭ0H1<11{4ٹ7:=;;;x<4>>.z= ];<:9٩99 :9 9r:;;I929*9;"=EgKF>_-H>A k:;kA?js Xk = u~ u'ڨr<^5X4hy7' !"W*3;\@Y@;1!'+"B&-|1<3"5%76 1N^(` t@"*=3m829\U3(   j *wY/p0k00.S*i$ v !"X""/r##!LVFgf%PEC!Ic"4@y?",= udyN8V>_7wF{JD?>#,%Yơ=_<ҽ?2 l#16&M &QrH],z w'<r_gU;XlR 0@1ۧqU^1ۿd]ٶ-u(Tᢏ";߻ xHёZDǡTۘalSpҘw˔wMte}˶)Ϧ"q@leӭ֘'r̸AJЩwzbldP٭;R_ȍAÉD1*ZDװyۑͯÆ3un,Xp`r:_lrҶPͻJ Ȁeo52k7^oϐ^k Դ<^iP_t݃J wXdVU#SVEXD^ 7u-Y ډLF@dž[]t VHF욥i{j 7re頛 4z9k`b*dG@Т0eU[jm_Bn8b9aq.O7+/ s_)|Ŷ Ls'ihW : ժ N B8m)5u5;'I0 #x>7x6  7y#'O4(O&&Ν(?+C+(:Bv )ò/22X1V.(0*!!06"@%)/߀46U3(2#2i:!9kz33.5.P,8%SW,Hq7;'870%m"$<$w"#+Pn254VM/6'&l&$%,ˡ131,'#&e-^1/܃'xS|> _M!Y-2>250-h,*$#} !H!"U#k%R%kZ EmM!%$٭\GIY\"'W+T,& ro>+wZ$q%(&y!FE YB߻u#[ka~ܤVB>>pKL9O Vn,i3`"gI K h 6Q"a)uҿ&L]%N |C=|&Fzu8L8[Ӹ.e`K7/)F;J$]؝;ϸ΋k%vm㙻ȪD蟑ͱe;(lR};Iھ= cC>׈׀Pߙ_wR\Jםo Ѱ8mAEذ|1`ۖ&9%ނZ}^fhwrݫray=3l 5Ѵ-$tvIMbPdۆҀDx3Gqв0QHwv?KΗ/~쁆/$?.U~ 1",L ᬓ w3jp֙&Z"Jmrx:r ]_TQI Բk#B<(r~40'C3 iĉ IIC:/K\) Q$*,~GCW*K> RMrpt Yc۰ f`)J /rnt%?(RI,Y-@?E[+?(2.r( L3 OǨ7:'mV | $?Uo; P " /#(o(!APJv}y+&"7&'o"t &#(w(i# ic3 (!~#S%*{(F+*!*jy+i,3i,*r%}ԏ4w[>& 01_+*\#n +/p/". /TE-i%Oq zk%P)%" QA7x !JP єS (C,)b/A1."v  Z!Op+>^l&Ihou.0#X'B**%4kY8s r"M# %|##Ek# 0͛"B[+m١e6yU @5|0:W0=p@_#$ @Υ {v%V8wnaF3Ӯ[DR:6-wL~}2xKOsHh/掗"4uf_Ia྅+aI>X@缎Em'=q՛0i-ۖ^6_B^KYb-|&H5OǗF^K[}@.,M⹢ޢM 0b}y73W_-iX)mbhx_kM-<3 ZAfxawط,E>USvAܹE} p<%ހ4֖מP׭sn'a` {gYӽfлݡUkw}!3*Y8|`))2D03%(pmsUDJ!cC':N)Acw1B(m*љ "R5E-#ɹw$7Zo#y%$("] '! Jy Oj6"/ڵ2-#tSW(6D,#) *'w$ô%ɰ(%*:'k)!RY&F )*D,3.[.)\q@ Ȣ p"ÿ49I3*.uU4k'(p)[)9$Ư3 9TJ=vu7g" 01q*u>سO?s5 /-]` E A@& 5S:A"Z2"x _+[ "V1odʂ ,aXNgd(B`v#  Qpg  5^zmvZ Rʈ O f E` nt.eC[T_8Aѐ.6ঢ়XPHd=P*4ou鈮2v Dn6ox3Yn+HB|ڨA큊Ʌ`mGڥ٤ѾY^g_&j䳕ރRSiCGsvͻ-ъ['W"D&QּCɸzͰ۬܄67 0Ao[0_ީXLoPr٨7$$G" +ϒL.KyTMF`uXwt袨Jc|':P+լt:,}lN&S:̃څm{]"`\1n2 P6Ek@&&x$6~](3蚘e$^U :x$l*!Y|.\{/D܄G.^T/ B 0ve;y Y ^ X! d 5 vܡFb ^| M#y WV}uXJ AM٣ڭ] L|u$=1r42&-&p+Vod te^g ''(+%[m $Si; [ &y)-Sj= +W2--y +R +yaJ h0 : Sa|!)_+e%&Y)a#+'(4Ol ZzQ6-Icb|pn w&d[@|"M 2 6: `B;v^/8] 3禯=$u _V:X X1U Ncܖ3]Z3 Re}tNJϙ/gfym|ħx2:hVK^Jj}hY44[zK1BE+7[DE2֓ի?o,:U,%WyH26Ӛ6X O&ZN抔谹7h䗺 (Jo{V2YmN7I]H2ܯ ]`ꧭޛڙW JyƠ5Rm9ܮ3P=Eˡ 5]<&gP0\qF,^vGSM*/ m޾gi L n.u, _{=_(4~'Bh7F_V:GIp%w#$lzNMixqd*B7l\ P 3c9gZ :[) vS$ K">''5%c"OJPF( 42!z 4=<1\2 X1x*! tk`"_$" w h/8f( LRc"u yz0pB H$'($]<u4+Ӯ"'*(r!#=B58c'"0)$_ N.$+JujT"GH#T;T5%3yˢ:J' * :J \K5Y1 mYb?qG!S$Iq'Q/&͘.8GN P! ~ * ?di`{Y* [Vj] U .2߹ ?|_ {_ğ*~[&3]/ odr?jX3CI ) % ͿnеrQ厸8SL )+F"]z] o ;i~5dxqXRKÄʷcUߛ?ߡڀf/$LB!EЁhҴ݈Q|q8sOحЧ#źC % l>a||-_ UJG/۲#ޤぐEͫ\+@ռWxސVM 51d]ϔ3!㈽v贺aG v'hAdH0.P9{g?eZ xLFz :/a@S]h$~}~AALE'!JQjav | N3m?묣+|>nx\< E'[ 'd.LޱTV. p,l"u%6C\cw՞&.6aP"^0'ӏM6h`jL  v ,4 \G*P_ }A /S nqH$)Q#ne`$Q[۬bZ 1iBNOSH _Cq+VNPdE *|=2%:*D, %'y3 As 3(#$M$l!Tƒ : R,4%H(V#7 4r <"M7"ISRC /Pjnʠ]w}^qV8 i3֥܈"!SD^l'8s%h WU]UG |3cv7#u MNF*߫.mX)Ӊ*q0e:Q5 W* >j\fav_m6~LISaT EJD  ?52dq5u }  Zi2q cYN3C{sJ0=tϡ~Bc~}XKD4 &K{}Yѭ~%'4 Z޾_Z;e+ R&ެ ^ZHDݯ464ȍwҝ UZ o桊_h_>x|ꪋs^)_K d뎪|CZӵTupJ )׺&f@4 4˔[X uvO;FB )uFyBޙm[+7+KSɥ]vOk؈RKHMKܟ[xTyt5xX YMTX;: MZ+GUvJ"-g\\T/PW4e?(6ް4E*o)I6H0ɽ @H  I RD П%1C G I Vr C #-3M 8$ R"%ӣ*R_Kr9+.& *(n?ق  ? De/3Z9,U|> .RNC!`"VI(,) !̸f%"cOL#` >2|jF^F2{'"% d#7~GwVX\#F3< Ǵ UDTu9J#JL  u: W/ P X~k vI;Ut slgSV/R 83.6f5tLy?#ꖀWJT^> l?Tx`¬F)#9 I#9f)FlG3tJR=3S}SW~c\ >HXSgN7> TЉgB #q?tSPhB 87aC鉸SL$`ٌ.uu <(XXMh ]!ڧ#nnWr umsЈ#zqp7c|dO K`(Pxk{Jh$/I߳0soO-Fl߿S(ޛys/齛@NRT-<)DE97c9>,,}73QVۈSn?'KuQ+כ f;  z\Xg Xj"iV$> ߮Xq)Ǻ K j צ ߩ*UMAN~8i# A>7 5 ` n'  1 P rp FT> |N9P!^S @f<>,0~jW[ Lj=~zr -#Q#//k"!G97 Ae!y.eu3+g40&1&*n?5~ g]$yK]F Q)*$2b2.+*$v 6)$M/0#(Qa 'V 8 וkdZ>g>$!$_$!(B8M^k< )"Q(F%ğO0!!NhM; 1 '#f G b_wP6??bhW4N  3h%}7ћ 2 P*>6^d}9pjn``ZUs h,px&qR$$1bH({Z,7v$CC*U_U^@ũm횮yy^h84褧i,܏}Qs[ aI= sڗȚ;0HQ꿫ڊ@xqSα۔݋4I䋍W䟇៣H!lJ;W>n2sz皙1psdd,el6=ߪl2C:i a Zޡ]ۏ# dUVRXoڑF# c/(DnIBFF=TZkYe64r3Cv9̐ 2_*e%]!O )zj'#y9Q^!5KÚ\9I,y_!'$U7fyo2a(0F 8v:o+^g3|y#  s [ գGh "W{ DoH B$<(#84/ 74MNcW!%xL=#Q!/,/,$iGba  l9rX|GZ Q$d./1]1RM.]':o #^> "s `#v&@'\%L!  }x L֎% -z&04E,e#λ, 2 'UC /# G"F>#m#"& C'<f>aXE & {8LgpILsn N2 7r" K ( @ g X /t  Ϧ4\UOB5q m 8 ;! N ' QZaeI~q3)Kτm =![7YoV{ j>X2Z ?u-M 0$_&"tl`s2SS i J:OIx :  kCLA՞#"-X ZXF-n ^sWs/k\7Rk"_f%Y|\o T~aJx &}A?#P&["*<)  \ Z| #\}(1\(&%!\ 1DI&|$"Vy$ : h%'"lZGN=n w  h>[ x x;0' #.P7 JkftH i+ ٪G`4'!WG"kTؓH@B%/k 6Kv+,C b . X f$ܢuI> f R reS>6!6Cw2:jHH %  o010drNv [.\bi}Ps ܠuf~ʟ5떡|S3h'vy^ 뽋hQ;f¥/IoDAPhQ1:Y_ดpꃱ`?W+땖M!dACc@`Ni)[%qi|ap߳䄲t e Xyhbن,- ߀b ~ &;}Zqb;d"TF `ץ?ѩXܥ1d6^m q`3T?$uW촒5yUpOSqve>BYgD_l~*4RIs[Dnq ݝ0h8e Z PW 8E f7yjRyf% D_] v: KN#u)b# ]~ +HM(!AK x  s~ V Ǔq<S##5-6GcLR8W+p:.& Sj IIC:%=`1e2g %%"! $X%= Sv~/S'nJq$b#;M nzZ2j;/n[92Lq i R6 K wS #) D2F0* {QS+^G Ue<]^3 M-ERPN!?  - q Uwmyqv@VUdI%P޳ u jl6:QC^Fuf#7@;ݞ驞eAs /JNhI&_|ʽDy-z+#}0۶.{`'hNN F%7%_c [Tʇ!y9 [ug5`挊첥VhpD;Izw6k8GTPel]4 ~"1 \tӟQޤMrYN@(Y-[*to˻#m7-*i1qx>BZV-llb5x+O;8ߋ]z  u0\X8w!Q: ul hNGn>_vn~Փ~ dT )ȞDG l'saXT,,5H?*y&JtDl?\EH΅$ x 8T &1|q֪y;Ao *$) & O,FMY+鎡w ,]n[rlrQ~y7%fUDl9ui)[JSj6 o!{O HC}R6[!{gzT)/j(acuNp-!+q Z Q:*JottB2j"gǧtsi|0f: [ +  _vJ{ԧSM1s=!C& >q+N!"}HؽGxdsZ4_i +SHezzw}t>gPH:n^hY_GCe0pK( K=[-4QsIzN l] K/4(0S{P1vX%u  #] m"Y L9cn N n19G=I {ֵA^^d I2  ^Z!:zbh o .>̿ A u:hdYFL 2 ·) X  F`nCH'l.`0o-WJ ѥ Pp ޫ8 (7W8"wc43 b(qN B} ɬ 't 2 E`mͥ c- 8~=Y+ `{&a Z56uR>6.CE+M8u,i,#B=k9=)i|5 5?=c@AS5tPOUMPR j"64 Cך N] wPK= .,i^,  -$>R#p/09o*3Qy >L~u+g|~ B#p#h*o:@/L]XGZ{=9/v ͚$qN.jQy0;ѽ }#EBV̽XaQ,U=gZw :i43i]3J\SVk NOktPY׿#@5"K5]9*8Y`4I: ;YU\Ir}doK>(C?Gi5A;% 6#w:jVh= vN::&f tZ3J=]yY\3'dwJ̀?7I4ي  >KW 4v n +  *D %B w p[5M b! ( } & N=%# $~Q[O9 X(V D e! m|$8q|; IF! fE %Gpkz}) (&K2 /=0ZK̽p m C" ҖW[ ho 82N# .d?!|Fri O @ 2I V +S st .d^ +fRR﬑! G cyn#:aINTy>7TEQĞHm.h< ٍ>hMP:_*eW9 4}-^QOaym&=)g ؼ ] 9!L},cP.bbeWuhYK9\(jD1$Bõ_f1j0n. " % t1WI3jN&?"s 9BI>G%k DAIP?I<ۙy cgdt"TRL]OZem| %Y`>cK#ٗ#"6SLn~g^hjIF8Vߺ_bO*qs" B\FRl'ZRA ߽w)7BwoM s $ U:¤o ˳ ~\?4ik;[v &\8bgT1YHX-"h jJtaZ h >!qqCu Qmh\^h M9r{Q_M'] ZBҾ #b f)o X  }ú / h cĿjb;!Ce {* d- ZydU1XU$Gh  ]ig"8oU*'nhX C\jj|0ȩxx^Jl:m$|t F ZM \Py{ގvUloUd)|oD\4&׬Dz'(k6\|O|1 g(,Ck1a l l< :"<*} u ҵ-U^}(;I >b3)vcHle^&D  v0 9 E HGHNt<d+%7')t~ )o[ 3&r_$CCh6 v  - I(  yt֜-s R  mP+^A;X "0"qo0n7H [ +K`4, j"byh}[]{zpdI,sai͐aJGY)Sp;K7>H7|]Z(3&%1t6pibԫu0n AO|h/P?rg s xtM C9#O+aBa;K Cbl]IX v`F&3|uaDwDL~c ~xO9KKl]?{j]g &2Md2]vau)v ]n`ZhS-/t ia=r:S /1En#FA ZoO*+S@/Bp{DyV IN<*h")!1Z`oßkbcMrN׻@;`tA~yvK3yQ%Y~ڢfn[>_U-$ TFbI ]~Sc . B ˺~)V-wk;ђ<   o0 ?k6-rkl 3 3ref i  ڸc<<kr l0q#s`dr,ߢF Y uyEq 1rY%>eJ)Uj:,p W‰v"|a\q[ TDLd5@3tի's^bBՔBͲN% }߭[;9! x DJW*)3T9q# ix}K=+VՋ)HWRҶV:4,@-3g4FMÓOvK& ni(ukUG<[ZHQVpMf.suI!`p5ʼn,AQ~\C;}Sc}XDU4KlG"d?V d5Ik?G{H3p2dqK"iz>~X .:hlDL9 S! i}b>c_'A| Ό 6 ce`Y U7$xI?X(  . 7 sA+&-Q&$P2*l 3V mi\ކD#h` ~ b  s a7İ 6N5>? /o Z= Eh?5Ni9rpMtƲ*@Z9ޖ;{ٖ;bi]/VF6Sx".ngq lR#Oup"b6&͕*@W"пJFZf#Lg7fi 6 9N8f)p0(zy"@j`!Goեb1R$Xrw``J{bF$Z?Hy@=9kT@dPbʑ׿-`xFܷ%N)&͑IJUQ,Zrm޷d1 O1fsٝgN<w |̯h I OH J1u[ 4z1MS]q' Q۸?7H="FxhS 2Y19HT|Pqs<4 cbL_Dv1<BOCrGvҸ\?f G%r]Y0zY)7g2&_IzPggqωh#m^t44v#Fiu -h*G:%O4VZ*LYg=-s!d:4k)Ew׉8oiCh^N^g@H^PRoL_>Y;rfPgjlu#y\RS[߅XnK8RI:!9*} ّ 5n 6Dx25{wr'q`y~ce~iޠm8\Fd/'iyh&gk e*v`mTOVag]KIk3X%vnUp`>RȧFfPE KVYMS68s  |#vaK<?1. +)E$0Dǻ\{|g[VYVPECo1L QP|{zx6qye UG:4/*y!qn_[xZ\ ~ypjeVL-D.<6.$ d]bZS2Ј(}zzzzwqpos0vvwvvv}xx3xx0yyw6wvvdy{@~~$g,$vGoz[D41.^$8+fav q"r*A4:A,GLQuX_hov{~ `W >k/C2%,28@,HQ[dkzrw~mPf"?wJG?Bt !$).3:AIPTY`Dgnu|N%פݺ -+ Zp7$(*,902G7:;+>2@G@$ACE6JKNPQSUWZ^\^^@]N]_`.abceddcabdyff hVhgfgmf:g7geLedZa_'_^]d^]5\[Z3XVT[SRQ=PJMJICFuE8C>AS=;b8542 1K//f*'$"$1 P(l]/Bu1p̶5+HzG<1DŽG|xyupmjfa_[VKROKFCbA=851I-)a%"y$m 0A9=Tr,7!;ʾnU#ޠXUTSRP"POZPNMNLYLKBJI~HH`IMH"IWIIHG-HG>HoFJG`IjHHG}ITH-IH(KI,L[KLRLNLPOOvOQQQRUUUUMXZ"ZZ[l]_q`a cefghYhXik+mAoprsjt0u?vNwy{|Z %.@Ĕc#Üpz|ҧJ 1ܶqmTj9t>?=>>I?>=Z>>>=<7=<o<r<<<=<z;;*; ;:e988898A8{76677i65L543=3a3&321&1'0h/..~.{.^.?.-,++*B)`(''&i&G&%%Y%%n$#I#""t! / N"Y_no7>l8Y # Z j 3TvL'+t#y6kx^Ny@n  Tbpg9Vkgv#()0[ 9\k{nqaOL]T]lർ禭xً+( ?YEU==+KL?!>V0]DQPVHoGT9dmS'j7F_F[0WWS ?Z[p`R]vYWUPAF;?~O=VOIńGtF%DB_B&?=hx;68#2Q'"%-.pVE :+wbtzՄ-G~<)Ң2GM̎|[bU돿Y%QNs40x’_g2J44 a}abqcMv{qVcWú_uD_*{͍g6y|(m{sL;GS_^Ā\l\>mW+K=:>3e7+ $4)# "-/~[/!t*<%k <=G$Ғ$ӿãs{ ̣.دT~U<9߭a)˺eʗ܀ gЁbܓhxqY dpZQTqH`Ii,bEuUTZo[}[tU==-Qdoxtߔu^uyZxbrNvRy v o9hbTlvvvLtok3cNz`kԉuqq e vadfNbO]Y#TV$YVrSA-W$1/GK`avUBlJJêOiNpIC1ہtQăRy'u v_.ї幀C#ĭA;Ʌۮr)n&\װch|Ox۲ %<ڷ7nSsD еG_p$ڮNݒ|3 Aiںƹ4T/g %"WWfj"Ee,gO]XK4uvDj@"a@ͯtBM|},QPoRE Ʉ`ēIJ8?L~pfyj@G -r DR-GtXVᠤQMb})%!!_V3td1"xq ]6eE$A+ p( r|, kb)j57*8nJ1ny N2zMk?-(3~! d 9`&@k)7$dC/Á"(aj 8R,&/RE)뎝FRdrD&u* F,2GP:d8(+&h;;/-W%>$30 Xue.#[J6+/U.C\ 5*HRmI':0 %1L( UkIj# P q&;@NEq.xwz = 'k@AjF=U_f4ؚCD6#!ߒ!Sw*><34,?C(<-̄sj7AC@K'W%'I.3W!B %c)XK 6*"D D)Q$K={X"*/A"D6RFp 7NB`pR[7,H  2kܷJJ 堐@3M, /NQYƺTvѲ`KBR:Cހ#sŁه$dp٨A.?|DlА =?NBj[ѽGrr۹+(xG]B3ErSM6\̪mГ\ݱe_T5@֯BK VVWP@&]<:+ 0IoUD%jp8O}G)*I'iB9ON <P/!>/I:_.=7[eg+[E-U=DPDl3 "5!]:!CA|K\)`N3XF)4|QtZiK08#S!ݐ%U;5) ̈U" #pOJcE 30m H"5;O$}(#N9 ҥd p^Z$ 2.f} mV4=P2ZZE ,,_l/Qrn[cH&\ɞL6A96Y1 П }nD8 /O%2梹ٕ~uhPo==t#B^0JH {$v_#٧] fo^AˇC"ޢLфߵ) pz:jO–nh/ĉQB @{yy"P7JźV?}ƍ7'HS6MoFr>IܧB{۝kP^wN㈥]eqE^E]ޢg']ek 7Gۊ#Ӝ֭kԁȨ2/[y~dr3z Lq| pQUG[jz%V|J]k?3j 1/&_ 23>E6]T'θFN옕 v +ʾ[a(5z@2&933HD ; 䏣lj$(KLu9"&p,*$j~ڼTzEfP` e{ UՆ^LJO.E \=ݴo[ N*4D6}PE&Q$ , G F' g"- 1B+'*n#E Kgw36;.()3 ӤGJ' F n*47+=#L.34P#y^w4r"><0RRE+Vx"-)EC%f5,v22xe4J'S TN(%Nl|I++ 313z<ܻt?) H D6\ ^0+tD^4$La@9r9 #@Pj  Q6!E B"5߃~6LvvΪNYgm: }Oԯ q tnݙO<fBL_tRN3ZIS&S# BCʽJ// H!q ٥ d&? ZlٽvQ B GWaQRWu_A~%qi7܋qX*N"rD> h\π~혦ސ-`* *L-*!_j?F @ O Q }xM?}r5 O M PQj);!a"Nq ^҉> oz mLS!**&Q+ XXq amV[**$y&K&|$P"v %' ۯ(, Ȏ"}*k#樨]5l%Z*O!T H=@1 H6 @BrrtXs&{&ka !w &< K5i=3+u.6\= R2pCj%&*DLRyީ0:*p {Ðݺ݉ja5l5~S3#썵, A4S C :-C@*gd=K!o&sR?Sk p8'x%U~W}צc l,n R&`  .." 6Ezgq OV.{nqd X$|5)(Fa SK"vsJp /l@sPlvd&ip8xT02fo*a Y}΢ ɢcZ ¹k k>LmjM+Gh_lRs!o  :<' ;U7eGP PV 6?+ۜ 7 '>k"J ㈢ω9:y EFx/ge \60?sjU P8N 3$.9 P2zW`G 4yA]*n0z8"9~rE<cHY`Zn-Z ٲn#AbcCB.fvQ l%!NNIi$$2Gswh'G/h)| wK!D^43@` 0 <& :@VZ{>5z6eK ,Q9gդ> -]m&<%( ML=E ƌ<@QYzJ ^T[ﲁ3n5XSbAlg Kl O i+_#[ـ׿6h˚1DƠf"&7Q">c"v;椒}쉸<;`Id a1{] n5 ]Sk#"hjܟgi ^ z~f!s,ql6EG4vi t (zLm-ɐW *@Sshm#},X ` O/XޕiP? *a&&*o rm;ٻaΤ ZN? ΉLi0 ~l0 z pi"1P  펽QEI4-80" (MCޖ㺣zm!r!z;6wy ;9V޿X~ ;Q UM  *9 ٰ, G 6!()@Uq=D`-6L0BC; bB2`b~ \typ t/xmw /F#'V:' 1$cVX> &K~A c""H! r[N Q锣a=\f עW߿Fq }8ڨ2 !*u^D 2zcQ0 Pyƞ4~X DjߤY: ]c< Lf t XFP ).ha*cDL0 XAr! p2;, ^V)KvAe;#~ ( 6 (% ⵓ 5Ϣ0 AENXB+*߉k r.';ƕm¡̘IBbIC 1kr ;L c! xNO<lm uo H.4SF | rOQZZP-.r=]v )RԍٺoYZ9;\q*lqiwuijR g DB j' #X׺j^ > xm W%Th '^ ?: Z]PD.$5 Aؾ7ظe"kr3 ٞRhi ~9J-un*E*# (aCYYta`dFw vмZBl(X"wɚ%$U!3 }1%Iw`:Rwɿöl$2 ^&lP;\` ]H})XL!V_E M= jN^d  f:GN@9hRL C 5 ք2Y+һ8QL5!]=r~]yC))| A V%fp smfoyKMZH&"He5wS ة[d ns #u[>q~/FUȖN"gb߰臠]"H[ s[r&-ZW!0|@ Bwu g[LZaD94+gg2Iv0 hFVJhp.Rۊ ̂uƞESJ륪 yR#7밚f| xox 0])}S`a0 ^jo뎞0 F9mn50|^X;N 1RY>b4G"{S!} 4v Ӳ .G1ƬRa :HPƆ\-1Rjх:FtG#$F }@O vfc n{y." &-_x*n EB>k Nrl m" UGJ dV bQ bS$ "Gci pVN57 QG # afDu~2W'A}9vPES1+~sOL T?*O wJ~O #G smB*/M"j8ظko&* $ *onsK{0 = l6oZ5F$' y~i O^!= ]Ci,NML4Y ]fX u&߭.8Or&@ 4m:  ٭ 'xS2!jS ~ w/A*vhn[ٲq4 HK 'O?(J'q G46XyrhcfmqD>Sr H Db ,C-R*2x 0 j3(T qnlV4 } 54 9+\0&9\=Vls-NQXLE@z >8o 2@ߨ ڏZs) ~Cq:z7l  5퉀&Dt Lo U *W)RSJM ' `)e@ F dEwo _PiqB dS `B dkC  PJ 66TF 9 \m|87P̊폒m1< ra  1UlGaVLh 6 /Ew9 $\ ;Hyd=-4ׇ@MԦshR|nPN_ U , _Bm  Հ 54NYffKD kcsa,Hb,^(f!B@=7 e  lV# $ec$wd}|0rO) IYvXIew %P(6Sd L ^f]q~qFN& ǚal7Jk4rb1vkI[|eG$~Ai= +Ep eUD̐(< $2 Hk+X oQa_} T O`+v[/~twA$biߝKA sc8 z5gDC| w]N(&  Ȼ(l_6_c R,Xc Z[HQJ b GtYRyѮ3-/ G o+HF TQQJu9 J ծ  Wp4}VLav* x/ e8D N (zéEH/Zx&s8f r2y=n. YQ | -y -* '^IW$3*9's^N <RaFrӇJ ]\j؈9-6Ĝ"Q-*4Y|N/Ĝt. c ^BmJ կ+x)(m;%3&?cxo\K LBE9oZRe#5  L4V 0C+PObJDkC:ng;2t-r lj 'p ;e O h01*Y  +z߇k1ņK!%]1 [,ur nvWlz/M "~:'] w?m`;eb4h`Kzxi -yPȄQ+P@-qh!jJWi576 qV}wx -f+bw"W<.ATc\ZvrS/dU0j:j ;.xce@qgIpkΛA(,930:EPGVT% s> q lq_Cexe [~g&Ytw [d~%$  . 8'.+NMa)ܖ|z8M,MlƎi Íka) !n"O$Yu RX  O=NX$U '!(c<4~T5zPsh3E \d'>aL$qvvV ёU| qf5wS _eA<)hBR=|:[{@h `| i%"<]O{RhWl1gB 9'= G p ʁzx: B-_7lR=h\8s)^+Ѩ !w|y-/5!Oc94DL%9WLE`U e&&z /z J3WKV=N\42]roy\8}P4 > ic>b m̛`}J:d9Z <[1>Hd7Ţ=PGۛy ;saHV  =b(BȜ32 9ڄ=2cOD F,'[8c7a!m, f &5A ڻ X.{v9a7:n <2 < OƇuH=q]8-+ A b/ e&J@J'[ M DG M9#1n6e~o^2\D8(T'OCih wj'ox":̿ h ǃ\A|!7?ރn|4<yjVEBhpw%J[xtQ.'e+Co +u,o#K ˜ j{S10+ +#(Sxq`~<'GQ{i e/pszQ Rځp A҃a8 V8 KBPA*U&$fC57~(b_klU \rmb7>L1 < y=*EIzSpPoͮS.ҖdN+BYmn I>  WUcLp`>YM%y(m0`7  v ,cJVӧ'/wLs"{ 8 Ha>cNہKvN= L!~$!Cm<#SO=?m ݘ y(zJgz;s+,=;XB5|&ÿ;'["HG0[Uy#"$txZ{,1gH.4eCNI!5`I.7oԪ?zIeH\[G (>2fhO" 6(},% &SCR.4?-zV ]}me@/5*9s4m ]6Q^:LƾC$hg'QPϖTVFY82 X=|P2 J#aȸ<uu˸P& JG CKB>%h&*sc) i& my!.DRaSI<rM rwDQ61,G6[O&~h -8J :t@8мz,Q<<<;z7wXdLp/Pac~66!S`5HA,Э[ 5 *Iv]6-f&5s5LHdP |<wD(ejaޥn '8"qoNK*NH8HW34:Rjjle3w([qNNy4GT_^x {$b]{9&/)e~;gJ=lzvk?{DATX z`2ZydS4`XgT(]EaAfiƍI c*c"uP]&K^We3mzh'T<< t #PXZrP 0xR5,pb xJ:F]j$TvP0<xqC~v(:Y4(DbEZR/9>/@(ը˰,=L]+8ii4ՍWgOW\qU( {*X[ Rf^" [|*"<W Z$Ci7;iKB,{g"p2x_w+ QYT^)Jo9}TOoӗouF4Mzz^AP V/0f!D "%P6:\:[w|.4)n=W^ ;!lL?5 Z";%7kV}dX4,=7u#iͺZb NߧCv4 ]6^ygKndd; VwbC5r\}3(,H<L y׏Z]3Y7QSxO*yk}AtbR [E0ɲjz+=k GSF~~?9.ێ&4,he]b1~B|;R~t\wuK]{D ES&R NaEeFB)5^GhZ4j]@tbs~f@L1̢՗^0 6?` hBeA7|qn.0H7 sI0SjLqPG }sO6CEeHpЊgv znlY-FGSeU*9x!U `? %sO?_e<; YƪwMXN|\G 'I;s\dgzMC|qtL f3_N;{`zOӂ|Oo 5/ ]67WrL `&4ÿQ8P "NpV=*&41 *6q~sR3f:$QZgpS7r,I h7ҳY&(\Y:aW\cM;Nfp3a1gs+w$tSh5k~ ߐa*ak/GjKi4uͶ_ݹ{!wyQh8?!Ivg%I_)6ZZY7&IT9!+RR~Lw$KMe=TpԛZ,>Oe 2g%4]r)},@֨`b0R8y(hFw){S:~_Yf*\k #&h 5 D511y*,)Iq`ROgH")>l1!Jq2]Edk AbNy;9%fbk9{̤@O8 HED89k]SSq%j\|DW30J*C?HjJ;;x`5=-\֬?{E ~V7VcFm=?n5n~cC) -W%$ 9aqw6-s]?S/-Z\o @\HPa64q:% [N6X1G40;O)d̤W-y)af\wǧ;-p>kB r P\[8شMӮIrq/bw|@cGcUl!7Nj69g Vv1;.xe?%Ɲ]Dm56ZCmwxS_qkUCțn~c F n"8= ]h;dpJ1Q:!#yX-`]ژ3(:+vbN"w7>-Vs!pC .Z!RU[=hk4b!T߆6NQ B>6'i;X54"2ӗ;/"Uzbj2-۽6wM.Gw?w՚G$c6_FШG)e'Zkl"J*1FՕI.U@38 ָ e~pB.$,RS p%k<}IVt&&CJap(IUR:Xp;.TRSƳFgSx#5Vna8Ժ94_HKt?`$B L-Kl-b qo\ٮa'8y1P5RIBlS'q]\_(?@xNo)mU8԰ּ>#ƜO-j6=-DgƦC@%2dV5M?{[t9=!/9a vy1Xa^0P?.XxqB_Y\Zӏ$aAP$Dpf`2tXHn}4{ FWYF/oB =P {PU-|+Egu([6qce J"X'BVWX{]%cvu!BH(  6fwL@Y?(~^bK*0Fv.?[U#c/cq>muD{S:Ɖ3y~\i!ij?#`|q)`[s<57RAK!+e#T"zk1h"We; OpM;8sV}ٟ F{<p#ݵNaD ף,ˉ2!@_/ 1!R2Gͽ;C9Oo(LK`Juul"Uw{IRIaLIf[V\]#=1< WخV &A#'._H.lJȮ#xJ'T!Ţ*ZblGY'qTB^1nR&4 NR Sl3X~ NX"F7o>p`Y5#F nxI 6\+Z{})K 8,m_:u6u=#vxsBwSETtt.J =S"{0B+&Sõ Y={1Us_B}.ט ci^sUnU37^J O9"W+,a~G-qx0]]e;> [Cw.SNG'Kju v|@Lz/]_E?]#2k*| tH=\g>Nq??Ub' )^j6*_u<82@ie4|BD =Je6{`FWPSZ\ɩk@]fv rCCG|sV| vvJ*ՖRnC%q\kRLQkV i_pK:U~zy5#eI Kd,S39^bטt.ȩcXW/3?^j&Q^Ul[ˣ5sI|@A[%u|0u WH'MW'Ft0;RX,q>.fgWx$I""8$~!VaOg}\v%<9(ga1 n",AHA0bnϴVSW>jEYKS{K'h4(WC[kMJvM04o& Fq)fI>FNQcj 8XYт (69jN7"6ul,>:X*\ [%`ru"^9%؛:|-\GM'"80uB8M7|,cq~AA*(}y?Jz O'+L %֮5b[Rnkw ud*D^j/g$-h|PYCaOn: (J+= LF&BvUqʎ)#l']$aD`"#&In68RX63rx~)[&zm3Ӳu=7o BۏœY Z}i>9!DRػA< !mD2-k/?\, !L$׼ 1E"/q=#'m8tU_RE4C[G6CGCH4eT:.7 . _R/,M~,*] V; R0C( /iRz1 z/:"HZ95?4}1 .J6ciZ*dl&H(EJBK:|&aMgLfq DJ8 ;Jp,CK: ) O`7V$:t7O HUU9}:Yb& ELm9C2NUYN X,n'_mb&|4#Trn_|BMBJ(2&F(,# 0`]HS=8 : Mu z=Y[5hXfRZ!s|8E r-hkGEKTT :b42|o,~0K%bJmUN>2E5f\]>SAUR1, 0, 6, 0LISTINFOIPRD99 Drum SamplesIART 99SoundsIGNRSound LibraryICMT"http://99sounds.org/drum-samples/ICRD October 2014id3 ID3MTALB#99 Drum SamplesTCONSound LibraryTPE199SoundsCOMMNenghttp://99sounds.org/drum-samples/drum-machine-2.2.0/data/drumkit/tom.wav000066400000000000000000003211011514070543000177670ustar00rootroot00000000000000RIFF9WAVEfmt Ddata/&u/YFc% `1 8*MO,]4 /q*b+)('9$"1F";!(  ]m @ RZ扗=TR 5,-M#%E &i (CE8I #Xy }ba9J-H#ǜ"@aqnX2/䘺J6Ο(XΞ$h[ś $i읂>/(>%չ_Eńd\0Ȑȋ(wŒ} v k+'T}Tگl㨿/DJ?LG} 8Y=eŒ )-+(*'+n5=iFtNW+c.ktnekIbVNQKJ}LyQW]QIcR8ge&^s'TqNKNk}OjSZI`ca^w5[XS|W WXW YG%Y{bZ?\n\c\ZZMw[ [\Q^?x_=E`(_][Z,XW2XXX1FY YXрWͿVLUTΗS޵RQP-LNuILgJmHF9DwBA;@u?=B<@:a7d592 /֜.J..T/ /)-*z&A!xM|=nɱiBaˉ[Aܓ":7^ɝqA-n-eJJ.5lݵ@6ՉtGϓdunP/laLVgǬ:^t뙈9I$ij4= (Ət2foXիױnҷbлǺ#2Tު@ЦD잉>$}$}^З4&^{PM*M]hlhǻ\J&Ucr*vC X,?.J7(,*wRj+'O.%4'3 /%3*D$ n( L(04U573]0)t02]5]7864i63ɠ2&.&)Lv?x ;E "Pn$G'e+,2pO67h75[4^4U5g9[<=#=T;c.7B1{);j!hTG}"`E(+,,,-u-),Mc(Ϩ# հ!onN` k-AT?SG+  LD& S H ) h &  i N `s3r'v(!rb.yyc Fa[})xTo鲋~7`EgFzQ NYnsPI ZҵQIB1ӎR52gU}pҊ4:Yض(9&׭հι#GىJֿK@Pn̆ɖ:bȄHʎ\q2 $;RA̐Rv "o1hJoOrѴӔC:mϨ TWޡGn=!GGSS!|퟽MXPIdۄxzS{J y&:YK'x^H= lU>m tﰢmz$3?9&7Kw:콲W@XqJ 1a p$Y.q5:?WDOH.KmULunOySVYT\[`cgmnnptrQq)mhcX`z`[pbRe!gOhAio0jgjمikg>e)c<aS]YFT MFpB&@VA-@eA)BBBDfME0DA>~:8D7u7Գ5`1X-*a*d*z***-1t5o7;9t8:/9F9)9;Ջ=dڠ&֩?Ψj}&Q0rS}'Äd`B-L"ۖ#R#|s2 5WC9 Z3/i QI \ bQ58 g9w*ONM%jT!?xt_V#v U9mAY1|uUy{젩h?]Y_,~p)'ɌY_, ; T%V 4YNvf ^ Q-]*mM>KW ~rL|ڧ Y  \7 6N+;]c ={5(v"1dPE3/huDoz!ؒc܅ z NWe6Ql$io*/ РϤϦgY=1 ׻V@m 5ڽGX԰X<3Μ@ҮGՔY nئBXڢl01{|ݾܤۂEۆz߬J-/r=j)>fBk3d%HfXuZnO 7x/G  S\H yp(s "2 +* +tmR2 Q_;U$+'+((&t"4Ϲag G 5"( '+!^-T15f5.649lD:8m751Iz/f./4159(??s'>=???PAA;B)RC=CDDMDDA?W?|>?ߡ@>;\85O1,T*[(%E#& +?$ 0HWQت"{$!6 y@ B1)-:) O'M xe%Ջ|%i} sn 0 ӟ KO],%3CLsl'  [bCMri*r,bD@H 52 \G8@2' f20FMLUfc$l:5v`{WKwǴM606 Jf_WR  2 j $ IU )  5n^ Z5X,j8s,hfxz oukTzl~1Cr33g}*K-ܨ?„;8] FAˑ,ɥ˂{Η(ɌӲ(ԀT|nAxB̾/zmRӮlؤ{ؖ/k9Keh%ԛeկ0ؿvC~&4U#ܧe(= n݅.ްF暡axu q~B[K[S?oFb. 5QSFÕh%er}ϔf"X#"#&׭*,-0Z1/-/~34O3 2]1}6q*>iDuGWE_4B,BeB2C%A{v@U>:9o:!:#`{zb,w.G~"q` ^m !.t8H 'bx׈0<}K (:m^0/X՜:B<BRVws>T!Q-x7>꫃+1Co!{g^\߲3_6=v v JlJ0X|ڻwCc -q1P8{؈r\޾@^XXڠ:ޯl`.5_{M*x,] ]Xs8X <݀߬IbBa[+`SF ^mUhGTF1G0[ q`mf{Q-]NtS >gz1|S "hGm2>3i Ȍ Y ۓ ķ HNp+qL/cBaw54vD <#d%P&tZ'%`#"!Y"%j*+kX+Q*U)m,ܓ.+q()1+z+F-#.,+.il2uZ2e0-.,i[+)r)\*4+h%,D,,),h,+**)+* +-+{)w(م'N$%-'+;&Hz$W" Ȍ ; + kX#l  h%1J#  $3 ^ x e-'28 gӳ bTKRBQ${z,|xS- f 4 P u 8K; , h B L@~p P?v2&UAxe՜xtZ?S6(_BK$GQ )kv2mw!\{,IX2F.7w]@!uj1 `$"AvhS_P8,SkD D!m:3={Kk,f_#xY@>5ꄌ vtZ~L-'frKR;HҶ'U5P7_ZnabP{,FD""JSHve0'IM<[8UX )-σu3͆zT|* zv+jP3 XHCb:2&P8&R5;Yk   da ĦLmv!eDH.)uNf,` 5UhUC")IiAu3p0F=ԎMR -HLv7m橚CrwJT"c菋SZA惠@?ULi6-Η剗zvvFghpy_J4Z2EbA9#Uk*Qn #8p @RQM*7dt_h 2Ta#}ev Kq(/f~wTW QI k  Y)KTh]x #X $w͆c.f(ZRR+\y:E, 8  I0Uy 77zv1!sq*q-f=VuH3VG"[7mM!w` ,  d+ ]m [p  GX  = 5 K> (Co\H@F6 Stob; +>g6=%#6wσ=wy~~e˚=n*>12Qg+W,4boX ~N&D^wm ?؅ֈ9XNGi+pvys7J}_4;J  1hz c.q%bdDybeOlMX2q(RD/YNs= ~E= ( `1 O |Rs|A7!)?.'C.J04.-Q Ikzh 1|%2Cú0+D"JO;'7dzJU ^X&H FDԟ"%"R;}. [Iz! s׾-d]#WI |x3DAf4/Gl^n Z>,/cG"g%W!&v!(?Syu"4MC(a\NL4:HĦ/5v52hp"6k#i="%OdPgkhJlo6xB(wW1 h6uDJoxYa|s8ķr(R릌귧?莎u$OQ$%nz^#TUL/ۂnfv*t㹓VesJ a:c^~,tZ 5WЀ-+|jH3gV٪i{h[52,LMb.4/6+Wр8m w!@ x,qGG9S  kzh *O\Yshsn,0OqPGjxӟˮ}_[D+WvrlKhHq56aSNm`y}: | P _ p 8 4 S| jX Ϲ "`úoG";k~\_1 t5~&Ңec)/k 8UH4UTFl[ h% 8  /g`%s M q GX } , ;Aº 0 r]Yi39Ve' =g q } w @ o +  D h I I Ek=2ykgM1A8p2y2/ϹRuFyvGi/YS]HX;Vew58wA4Y`UUCݤU_{V~Qw23M ] ] L Œ Y {' j*NqlD/5l ZBSk[\ˮ 3 %]YUh-NlL2 .qj_\H^~$8}7s`) ^"oH3 rHAt; rXwCd4(cNwm^TFxhE5b%Z.kiZ -fzcF_MbQrL)QHD^MvRӎO]jy(fagrf~,LꈼxC8M ZmKE艗j-Aac;4 #u<_ v]j- MI("Lbv,L2C/W@LRmhG"h GzE7sD|Sk-8nZ3/޵'d=a RG"Sl c?,j#U33+3r'HAP{Z)!J-piup#0FwDO -_VxBP\aw Q . |** da z@ ت ] W  m 4 D 4   I #% T <qBrV } D ) * t M'yQb|_n[|sj"~P X&3G?.CāX,rCh / { EQS߲U+ 4g(iEAn1|q~a{t^wcu%n-dALW?12 _+y{ilGiLd.m s:*L j׾w`!!X D @ z D u י V V@ * SWyQCmfE $bWuRХ*!V/z׈`   ,( _5,jeG{v2*(DL>$bh,cdjl1zUC| 'wT> ~qL8%G_bjE9*|#+ǣ<-Z$tc4.\ lIzL>.n05Mer *cxy.ĕE".~UQty?.2y ) `= *-%l vVTOq*[,`R(f(fߡU NLrg%PI"[+DAl $_,3 I5|p^7aBё u}{EsnUfJ6Qn 8@ FLsUh Y{`{#u ( 0! N nR F" + 9  ÁK>>SjnGֈil_<m&w1vW9}G0Hz7 6 b  V B - b Z: + (- @7& t5J k+pM K(a.$XY" '#GؾdمIo# Ȍ  k u "[ J  ^ M  F}?b i S f w2Ψ , #X 4 ZmAH > C 5 l j} v  @+ Q Ȍ b } )  /  h % - " ! Z Y % I G 8 V@ i < A # } ^ ) R  f Zʮ ߍ fl ?6_0kXh%}Xr~י D 2 `  m (   ^4 հ 1UY  C(c+]mdu\J %bhn}:wPLL-X{"T~ *f> H+*pOqL/&CGXB+#/Yƒz&M1!%jxq`?}cږꚡzMOkYiUZRS!|Jf桦數y楠CRq鐰iꊃl LΨ-Qu ocJ%:p*[{}(+9Kzzv8+̿Z\p% NOk\ FH?)9CM(wW?YuZCTWUft`[[|Iͼ 6s |,O~r,qL>K`m ef8&` 5۸ #$'A nP HD9w[\1'~\7w}pD>Mj:78;hR+jn4@?.}RF[7-JD[|]4/'p wRAzbBgekz IϨ%NcP&oi %DQ+; ;Y`  QX`X7vab9hSmw?f]<%2Z) kHmfȠ 1DoFl Gɝ#ؾGB -~\Dj.H^e ZLߡ.';=WRo\.q:7XO<L>YCk + S b ~EyPRx ) ,O  KBkoNhJX,Z)B_ y9Z :)]tbUfxs$]BU'BW]ה:i*gl/'w0; yZ 6k - E   |  .J ' ~ ( 3 D7bu:m1/L̓nh9Ќv=8W2P0Ozu¥GC8L)iM'HTE/yC3ue1bDcӤ])l @jRD[$`Xw%˔[ 0*/cKԟ_CLflh^J$$?"JY$;9;|i;DU*]vd%rwB팏k9@e"ټ`lc&R28P$zl-?GA f7z#y_+|6 s7z KjW4kqzΖ}e OkWqWNFAs9?'d[QdһK0K0|-!dQ \Op59^Lsu7?)gWQKD=\b6G @O|g8}$\C|rKX617/r;t2XQ#m$(wKcҾ'3y5 ltht|UY|b?;gR,y ް֕Jyzµ Rnt|{&E6}}4G(Oc}TX=XpEVd:1xqRDP5~`or^ʘ{%~&).#2GK/'`S1LRؑ>~}l G:C K  %C ]M ]c 2 f ` R ( R c ) nHPm 4 t{e=C#\q%z m  U   ! Y D m !MO&zc qWzФ9)~ nz/ߝ:t[MD5 eg_MQ#78i9*/.6pA1wp"5U_+)g+:V T  2) 9# , Zo l2 8 <"nU=A ҷMƘ{R|wj&#Tp &1PsFFVBbZpSQ;H{@7 }jBFG;`n\x9CJ#32#NT먨>Z`hY|Mߟ# (z.9?+&5٥&AI`t/ew;S[)`s`D6bpc,bP3Si1@L:!f)1,,<iEX{!ˆaOc2i7aii Bs|X07[#Sx#j%*A7I7bj,GabnϏ* ( u#ohrnO4\av ]:M_{%G] ׷\b|D$68AzvLw(4@7 XC2 l ^YPQ@{?&79)tw#+ DAccM.pYg(kDuq+6OvV nO#KQipv%]ɤziՇN_g!V7U$evc/÷k&|i>%qTR!H /  N? Q  Ҝ " S7  " ; S? W @ K W~ ~ Fe W-{8g75 x ; 9 py 5  5 p 4 O 8c > x D  `a  y E U> Y. z  3/ T ` в {  9F )  ^ 5= G e Z 'a $  N G | 2 e E ֍ t ] J : 0 = [  9 sh  8 /*  W W Z & rr |$  J` - < 6 -D S Y+3%XFM  wD.dzWZ~սtFT-h^o pu]<tގ1@^XrB&Q7+Rv=yÛ(R JھktdHsL3@cC$H!9$k9~ڮyiz4g{WU$wz4.]bRl'4{{p{L֘HDpCBH̰֙($ݩB=0U2^ݍ!3^>Y=xRTR"k 1H]E#kdcV;*QMށY9i VPd @G¦%n3`"S]^VD:N`{wy=>9\ n8;? bGX (t\O^ !$eG $F-d a r1>Kp`"hTn c36llYxvf:W 5}XMx65rk+p&'32t N3;" Z=$^>9|KtFQ{RLuG>F7ځnɋckoxosU2n9<9#E2 $~^(wsO.\&8L-QXbٙ|[RFW9)fRHfg8&CX;͔qn#8I+uַAqtmx&MYeN{Ȥu'O NZX' +` $ pw  P "  h% ^ E ^ Y vx 7-  p n^ /  W > x ] ! J a 9M [   . r Qd T <'g1B,nMlO;>gew*7O?6"?B;G!+6 3a , j9 <}  # 1 V ) ]5  .  [ H j { a N m ) T  W ˃  1 *  4&  H ~ " 8 b t /o    1 8 \ d] ׄ ) I 3 g 4D XH  b G  B }7 x n b Ah  TL ˥ e yjjK1%AA+ X|~k Hkni8`bZkED>݋`E nXW;&Q-@ r]@:<^5lz<~!7774Ml3Ña\0w+xp[0BT}[[Տ*3R ՠa8NVbU]da9g^+ i ! lA#G=:(u}1gldB^mt"T5Oȁ?1Ϭ}XJvFrL,5!YAmIbW($2&ldBR4` Vn܄NcyI)K)x H%EjXA{8VQhMMu.ID[)ݑb#*dsN=W˵SPQ|n RW5o^;<)6Z-4"=\zΌ$^8csn˫_*m:iz`QYhu"j  %cQ1CRd9yF6C *6&KG "oٔ^>T̜)ڪ,1,Jid zaFeSO~)Y9-'aL =4Qq`Can'Yyf2:y= !j z d2 , ' , * @ _\ a {M  V N1 Hn s  < D v o ׀  8 Q t "R2i(|F`M97=a;|Tnz#G }R$ ū /b { + t b E 7 Q A  l uyK^v5KdcZLiP_p4F|uXem/{ } /XBi9o8mr4$Ȃ pA#5MD2L־~Fy]5LKJlu?/Zol6(&Y1n ;@+6Woc2 quZH8iM 1I :8a>y-q! }BAa\T_IF A*$X0R meXY#/w-MrMT nqSSc*#q`';Ǩqc{oS|`ز7F jBR1I,":y< |5SAjL2W=rSڷCVx_,US0v6+ wO{s))ƒ OWWtzY5_:IujONwa,K]$ 4*ְݡ=GU^A#Ij C,"% ]RW}E_Ԁv6HE7W Bc%CF-Ji)f'zOVXVKHrL^3H?ߠ2 pc zg!|n>OK$1ң+^}p} qUo*6Ԙl[&^]>0n}w?zV~#LD@[g|KHLg y + z ? ]  Uf S ~ = b +  H p  +pH L3cw"mBAF 21(ޘk> 6 IQ ^  ] { w & d@ R m;W+d$/sdrxRh ϲ=d78u34<oERn KYQ[ O27<LQCnbNLD? Sk<w D 9'U2ef[Z3QTC05({ENHOT)&.gXvf=A=2ac},O]p|=VM Pl}ؔ'OQ {I3 ]Mm_ =b|huJA"T*1s:?*O?${) z/z?ׂCN@as P<1c .pzb(1OI$ (9I dMPTWM?Bd>Ub%A{zUt;t{Ih]6 A}~$]e\ޚHn}+I3\SXVf,:+EӜ K *x'D8Y\* lU)Vmep_T(oj v"B2F6&SLz<U=H?Z3F7+R B U%m8{8&VyRe&-@:QX>w5UMvlhr[XcNöi*M+;3\g^,5,i)TYBaf߻g@@pD hX 5  [#iVhS74vpo5:-DqA^fȓ TC%z.Y1'UwaEM" H-#O<q @kLH! L / s<F` ;; p@jVYV! ̭!{lM܆hej>t zS' \e>>4_zx^ |w#wM4YMYlQ*n iҷųF 3yeyI2 LszBxKzsNW3qIM.S~A=eYD5ŸGDEij~t8:E/JoW<;,[:E=p V7Ao .ͨ2Ho,bb 3H `cLn}iivn3H)EP/7ZzzQb;xYQUWp_q_?; rҙ\~V$^ q ؽl+@ 7Ou:/nkw%v-Hbk$)e0)NNi4}W1h_||@8"]lDgM>F ?Bms?6tg( et15gh-f ۫(,$)6pH h@G7=\ tMd0O|w'wjU,7Q#C "$XE14}Ğ(vi^Rdw >u3( t!f UB:E( ])*J!=X5)3 ,H3w6vvTK=wvӏ7q7=[HlTWy-'j Ҁ?g5:7:@UM$Yp; &I1`>¾* Vt`*Fy{{c:@R)k<sosXn3;Dp^jP<uv~^ U6HirMsE?5q׾2(>C#X=Sl$# !X&%$ F€-\j>W_In|r)>~-w[MǍK$i`b[u2 vB$ʆlFQ_y\t,w(-"J|oW"lKoK6otE7Ombn=M Ĵ'HEW^gMZjM[ 1fX0G,'{B S#O|aaskM*9WApw7e4 p1 I!fZ&>i~Z)V>E-)U)6 kE\e` &ZS+mzABz߭!sT@1>`f5$!?6 Rn*͑,lG|a;rW-WfbY=}EܞŸM fp=>U-vr YLx>`|(+H(itjr>g F2^J]t4|(:/*uvaqy JFb@~j:J7@&̇wБ>`f~fRLdMg;f5sզ)t2eZn93K9w;x O7 wo qK0 s7z Q{XT2"&t o\UyM ZnKBPq]hčmRRIz#,e, 48SVWPQDMUg,;mVAD1Zht5IG35Y?t[&l y6#BZ&1;|Ls.B3W\).lM+r8+ %0^7NDtON$9&i,z,#*nK e1Az1 )10pmY4ɦSm\"="VafmHbDVXH!hͬ9QWO=}&D&Uq@$2n w 3OP%xz|]KI<hjMH G$"yOnHt=L& mIMx*Uz 05 U>DZN:Ep\ %f{%h~J@;Z"0 5sF^4~c`EOrk^v  ^*tq&$;E*:  F#(!(l%04&V/9|mB:6ahF,\CmR-LJ?:E d@)ZN? dD0"50 V VOM;x_^{@ib2;m.Zi)T{)C `"#w'8&1GaKk-1/AX>]T$D*Ѧ pæ755,RR6[a \JLcb:> :Q5}rn|p/a F]Z/Y]ox4q f0Fڸ1NoVlq]1FwoܛlCfOc}L?( Xw&~nV 7CfiAwGK17} g_=OHGrcؚ.Y3W0?*s(n{ѿQ  YzЗ hSZMexO QCs8 9EgA>W(65. Խ<~? $"u,*M"1 .3vֲsm2 K+]|/ ?'iwyy|g(xI8t8FuERO:49M;n^'=]uYRK>99&Yn.aضVn">XAȔCKmv%<9O/)W}9Օ!POrc$vlL,"D0ZТYRvw&O*SFY!d]AL8=L>-he$x8\{up32L u= LuN"WKiFڹZ.,1/2I0G!viY\&/>[1X0Ic٣eJE;Z\BoK3j0eT|^j%CMj%gF$2_ԞM^Tرh_DH=AY$?_vlRtsI5Hmr7ȇԂ oKb . ? $|{tLSGz\{N]A# zחRՂ4C(^b["SEbR `h-&"Fc0>(3[^p2=+Q J]%5!^N]1BB/;.sv`6ZeOE2?gxt%jl7dT;w?:ovprE^1.'%#Џ5R *}q&}WkmR.DE#cyſ@Q[2::,,\$SwY MM6&P%-IQ&rM;_` r/فpɦkuUM85]!r9BK"tg (?}~q/`|>CMHq^zyy6Y?o^$N4uk?k[3A}|&Ùa(p_O4F#GUF-})f+Q(BNZ.LK+P!ХvWoHO ijN c~DCR0Ueűll *g"i7n8sxv=tsea|{>WhTP|}NݡZ]^Y;RQoH-Ի$Ih3.acx>={M7^+|zϔ!Arhb`6B$ H$!# Sy3!X 5+mƕ2DrM %]s !H_oDn$tV mkJGL QsxP-)n&(.+yvL w{mI4 {$3AK(;޼}]|`o !5M5C >KiOSG!];tޑ~߫p K;K ET& ^2p@]_֥|w4tK{UbHڄG7tC8 &SZfs0SsP 2a4X4$;kы glyyXR2) u {zH}Dғ y'/kd XVi>3SisC~#E[h1B>kAB8ecL8mtZ?}c5Mzayƕ@-pRjeCs6AhZA qdБyahvkHq1h75+Z/xw0kE}9`b=sUu C+y$<<6eAQF-`~|F`oZIE"eފTKe_&" ="2 T!u$i2?1L=8yK*ܥk %a4 ?|ݚy%:6 Ӑ=u vH!U'0:!##A,kB 7yopYE0>NmƟdXR~\YmA>Xi8Mx>#IN!tЕ^ؕHS<{ע3EȆL't̵8~Hɋc}[R|m1Z80>DaW N%st6og֥[xO ~pUNs+%sS;7kc8|Up' 'y ; /-(Ba@7xg"Kh+U =($+|-R*vPa4Dul`W\wxlΛ_̩GS79:)]>vZfƽ7hɽK,As[ܷ}@v%W.co_zӬ(OUn~P!y f"!!]0DK, )׿ʿ0b"A`184qpu; Fj,>,PGk{%+2 \:aؿwGl4JA @-Tw QeA&7 e?4fο]G7M_ }WB}XxP[GʊrH$aNRO'8 \{tlw9"5Na '*QQ O^kuo5EB&=;#G khU@cm?[I _Q%i+L,0)j cu,UX~Oa,}T/nUAl 4\ܲ j!|P{˞am&x}# !?d9?9%gj5V#J=naPFA{zQ /-?,7Vv@V/|1Пcv^aq4U>:\@ (wEM4O$2(4_Bmۨݠ/mBl_0svŖv|ghD@е6u{М<`r ~@u|̢cM(I[?JDZIq˅E !pDQE,.g[[^Pt2ҩ^ 6?xlDܴ?{KNgiBSat`>T~bhɧf g˘߼k"H['JBR)%'ݠg\EK;#^&D-w$n&WIE"eؒfp]K1qA}ZI?%6 fg]צrփ%V0+BpWaZP]cEmiL-.>dVDvvf`P(rIosP'XIMңY_iu"XFÑ5M|j&p6$)~½ ֆG2pK;,84z-33+i?~4hI N Xg WxQfu9ɋYy{pȝ%uhh)a('P{ &$3%2N?g P)$[U| 6Jv3qrOE^R=Dm'rj[l>}Rg[;mLHh,<f>B^hi@ٚ=3MxUs;`3)gR|eBwccBAWD3Be4}!0[4I0QޙfgD&\Q.,j34Z6J=gM;7AS'P x( 3&A?lH])JR{}Tb4yiFQ.X=n1z0;JΘ}7lI 6XtjK[,OEcvA9&:r`>k)Uu P{E}T.w8cPBoe<(;HPO}&mE=N^ZG-"4_TgM-oς_{UjK@wWl}mӰwPj/`PT*H;q=X312gebE_V&Ms'A_ Y>/g jO 40EUG/Bl+B!  )%(TTۉ͉78-ClbVF0nIOx:2p9u*jpQ@-\W"_]: {;*FOgixblO=2x*L8S$rrҌF+M`K(7TԴ.Shɾ8i*;\eH@(-S/ +'g&%PdVw vF :1g(\6j>w.*xϜv1r@`31HudUjͭ1K}fMW(&2X F$&A.1DI`9p^_\ A3 5 |L2u7`<`IyMeXJL.J>RHeWk)| UPQ,hg]v(X Ynk~[w#Mm#$fI}^PeN4[fY{ٯkikh8oʣ2 gDgE>%PN-%kq eU*A $-@&!PR9*c,o(x\gԵpm])w 1;X @-}1 Ӑ`ڞGfP<^ƃf4FGh:T@us6T]VhI[Vwt!^dN3!h{R;UG/%":%>l46q*8S,pٿ @HD B.Kp)SyfS^!ljzLxܸr{{=lrYO6nl U/ tXcQΟgZGn'PH%ME %t"UH2mgE82@aAg~\FhW]jc!h}FdiBjkoܿV`N(m{j]`!=w <m,x T'Vc6 3+A qHyZg5lhu>s oaKYE_N2 'YpPwnS_4: 1\1)*.*B* (' 6&.lbY}L|rs&i_lKa>)G;O;eOБO\>:F _*=0, 27s.#s - e9MKO$HW7Gil4<2`xXFD&|zmXE&#Q`S=eK~+L@f| Y8ye ȗ:>n_R"C$'v/9#g#e0I4<.1ui^kwK({n@.uP.h !X#TvA779KNa6d+5v|п1S~2* =j7OCJCk*ŞIK$!2$ =L]te2v]+di-73FG/B %)M{6O.OxNS ze'?qgb&,\`S{@-PH=KQ)`4Ym2{q:QHEC=o"bk{ϬeEnzVs}<TD{;NxhSA_;Q;;yc/%s-&:$Tb_DOE,xR=Mi2P6j}e>Q(t'xkhD]:z+"3VcM-QF4O@k*GLKgDE[r]kvF``j34ox] X5(iWnJU):9ƟT|iF1=|q0.i{@#16P\z1{ ^ݔ.O]K #=܉CyZ9n_)+^/ݠl83hVےsb>$r 6iY4B=8Թ[y?B9 EFUl44\mSiKh$gdlZz$i:˵zDa3G= ~G/N&8+<6YFOWW^؋m}i|>"gI.Wa>83V0{7gTSKj;dZCbN <l# (3 &',Fm9[Q051:7Rtu Z%^/pP{uDfOM9GjrM/h{S>X6I~0@w0@)?nF zp~;NF Av4rHSvmHH\_DOu~U8c%gBQn(PPޯi>ƦJQIcC[Բ1tH9jkIPH| V?{%[lSrRIlAP(WkIٯwĂܴ_Rٹ*Jl*F{<aT$Jl?5kF-P<6+#@ (´La/yR! 8U - e. Y1ik$rby7 0 3^, b.iGfOw%7B-z>" 1G4}#36(4?Wo1bd!m/XgLj8eV |Hx "6g g)vQ)c`Qb=L Cv}eqfNaJ/]jnRWo;@,K+,C4e ~8ĕihZXQ6<P@6&V6+Cs"! bS~֤n=bPEuVgI: =8T8c$M.Ge LdO))&=2O;5+O4 T %/%'R1U#O= L9)NT`aj.*-MhA2ZTgL;>']HO2tc<Ƿ1ra]_U7b 2TT !iRA.G(D"ESp*ZB [qbgdLH`{ɰȧx-(*"!MS'1PG\KtWȁWv&@rO{,U!K86  !8Gr{>H&0HM_b^_~}jgql&-%1<Sf8FK_FZ8JmXwNliuX3L[[fd]oYqfWOHLVDWK7+g;3*m!Z21=1 hKP&Xb 5 0 4 @8 V.%;-?!,E56#7867Y17m%Dn3i]؃]Uqksp͂vlvxkL.rRNS S31);(6>%0bQ*QFQ ++.B2tYLODWNg\m_tk@ I U$@962 M1 5%- $31D*<rW'mY:8wCpFmnU|LHi7r֧2r*v!zͦ~gr¤T"I+' j,u-I@H>"Noz_<n^@BO2+Z\&k s}gxLPj6U+e[(x~n3kGB͵VHqI¬i+whz[݌PrZRatK?`b{[kо|bf#|~ ޤZvѣtd">or0::I7ydNP`)?:759-~jl|uo^h_:|U0iY2Gv۲NYDZ -{1-puw%NTzǻXkLprgA]33P:rHDI"e$bC+xv.l(OI#!WoJ%[6xP} &.dMH.`IEI'QGA.X+DO\z_[ kxqwۥn 8eHax2ʈ$ |KӴ0жbA) }9ÖY֙ o<Y!Pijiv'^ra*!%V@*i p Vl R N-Ng<ni@[z& lekl·Hzk"K9y~Vgrj@H[O39F,D0&0spۂXABqMͰhqtUdcZjLX{sSdMpRC[/ <VzQk- 'K2n?< LiYQwL.rh G]U;* ,_ƓTk~*] [W@W+ZA2~Zk4>V,=F`oF 5*~m`&3`8!|[dr~.c}X80y>ƖU&DVF$g$6Di0qϜpcamUŽ5 c}hgK oـtjXXe!Ɉp?xW_*>] )ce~ `< 3V %`)2-W1S8 {}~;Wi~Oyږ/,/G<_n*R +G8i$1S@u$\&oHbfI,_+:J F/6hObJU~g}L}$#/3j\%r92j9?G,+,LFchk}t5Gt"/!&"6RffšZ@6ooKqw݀ ~"8GJ<&9RDT*PJ'{GL;fi2N_c_nhm 3&$6V(ui{שFfk/X7BAR|q?@uDb6O.@3. Ƹx?N|Ksm =l>0>^T~пɿ o:B*lDxNwm%UT,b,T U{xR$~P&UVk )7h~Kf2?2/R[iz`^?[GbsssHqGKvThTg>Q9K$n)y"TW2G<'4 J?*Bi!vFDH0.LSWOW[];XL66 1MOel8Y==|kHFzC# L-!H[[Cg5KGW"Rdrfr;bZKA"6R,5oK-Ee$_H?F%/3e'@OԧFUvli6`}RKRzuv@6t>KMh=Q]#U^4֪>^y1\a=" -<' ( dr:a"=,?EL $Ygsj,W]:?YJg}1/.*VJ 6keP5Ψt}u"oJ{w{ST@( r$9rhqܖ]a]м^.Fe82=VYC4TR4Opz |Yns ,"'H7 m$N"77e-U^^@v^SZwR1?8J\xtrd)x XMdV&8x:x~KEgѿU+ %V}TQqhMY^n0JnHC8__<kW$!/Ti1"\1DpE8QFn:<,SfD=46_cU.0>TyVFp 0%9%*8,B~WC8#A' km; @KGWR_"Ybfʯ)ZUIG7@0 YB,N"  vvbk(E.P[ox֊vlIQ=EBdw8Kӑhx]ä6 Yxp0?j d~{ѯ1-72֐E| h|.bi}3Di.H8kXCP?:PnU,f4+mZd!P14W lB>1*H J0/K!M 1Q2 bDMhkU_:  8v2 -? KG>9iggug}/henTOqBi^3AtKlkX_iJ:* !aH|+W%"Q2E By*zl'W7< mq>jZ9W en iv9hsvU1CoE_F=Y57k$+5>MAf gdOEJz:yj5Sr S,?i- I)s%'\$; M6zh9=2.ZX '0D~$E%0]+jN>etݟ+S?937i#$9*D/pI/23~ibkbiև[K. ru 9;9Y=9KUV=H8o4nRI'Wӈ/Nрr#~{cU5!f8u^=s9CFc- #Y(41i/3!im\D$HThR[g~bv+enX)&xJ725%74z\+u*5c˺vGrs0csdLs- zNel^]IYmS [FYoZPq s`ȶ*8 ,7z=kVN31e(ze= <YzrtxyFVhj|i\p7DA0e,#H &9m YC.dL.|L A6U"#0Uk/+}^^}uu4E+M[H M*NbgA+YaqgRw|HtM>vc8&arOZmOXPm+[IvH!oO-_  FI%7 ( zr."z|Roe!v` V'$P )  D\U_%2-OV 4& Rv\FXIȫޏZ}ftfz!<Iq@xQ W_: J Jl,JZo<`ܢrlX"^RGK]77W~FKf\Op?Nx(y5skwͥve}½.>LѰA`Y 4U +kW$, r$j +s 0c(6}-*|  )j!qhZ-Y!/C^$eSiHw{vr9eSatMqqjgp Jwo?&k^L<E^N0A+>c"]@md_K9-C"Cbvc-WOu[hgj39W7YUDd%y9 %fbjMmKO`HLgWtЈ}x'@^Xjj  F7'nXO_^KDVsc}rQZ}n0U`[p|,j.Yk_uA^|+H{+7^ls%ٹy͝_&O% '}-2 BO/f0H`D?4:40IO/PZ8$.D#M/gy#_]E@K<-yڎhkZWjcS raZ~oiDuzsT`u=E,nQ? QE/g[|M Fl!vXwU_xpLJn0Fo̬h.a Kd}zL|b8YYtH.99(D*%)m:&{C` lY\=-*Y;-NzsSJdbKFC9@6n9R5D) ((YK02 )99C5)1/'(*Y)ZBX]:cjfF_m@&hDB-P Qy:XSf\R3?^ g"{H]|Sf/,ShV׫+E|y%n=v6* @OX M1A5/g"3YBQ<DpO&C 12<PB|8`jsdOm{ed1}ymAoym:! y[-y@Tϯtxh|[.RN: p *Oe/]?!IATB t7\'ay{xwc}rhM~gyDhsڄnԚҥښEץSTHd yʭc|&mQv\/ZF7 P{`>gKu'r mDo*gȘކ#[=Ŏ uvgg,` dyb|ą#|\ɞv+*|$CM3 !P8`%5(2&//'@&&1 X1'5?OeURq_ZJ[qϔ <-1 L7oǎ\!Hawj|iPH#ЛtݞxjQ%o~^KYbWb1L]NzB^$/ x" gѿh] u$u(D J5`8D-C q;G6XexUr(y;PzmG.^#ɿJ?̮{ ݠƝrтIy?w^[M>JzOmG\ZU1' 5$k%I, ~"8U Y9{tm3fD̐#s^zooLT:8[iooud$U8XzdkIsIdQ|aV)i0V >QI7/R Ibe4/J(sښQQB\e8 #Kq*zޮ^zM2#URm_ E[^^9#5F)N;F  S (b$nP(.700:as ("2U6JMa/Y+;era>g|]Asf7N}ÌÒnΒy=Pbml#: /zBP R(nH8@F125O7&:i'C5I(*.iLV@*THn6gR@H" @g*ZyPLX<An"ZrRdWUdDkݷHO7 Kd,p1|9(;'UAU0CZ>Lff\L'=34jj3s  U `SȄPNBA30\Dzz<*gp Sv?>DgNSzHNTDfcKt/k t A5W2wF[fHP\>Gvy>>E\hST)(bX7UV3G 3g# ?zCޱO T.nX&0'I12$J 5; -0T9YD5^P9EGCG.N")a߇ !12^*)j_O6@?h%XG Uh;EAC T iv %^%$5 44O5+P=L\OpL0rUƱA-  >em8 'L"iXOUj&NuRȏBM ttϯ՜PMWxgaPUNVEDnGK[\V\9 K5c88;6-`_Ia+K.@M7& _$"/"- -?rpFy0"@gU<3G!M+UǦvwXv$y-qp[yj@LqgcI+W.W+ 8mf> rE $@2#(,YS QL ܴYu(!G]gUZm9'[ UwM zG+J\^|lq VU:\ E.>;ws!N%/J"2e01-&&{P+:jfPyoƅns ѳ &-- &)-BB@TF`BQG8`E!ejQg`^%(OU*~obzzDuykEZƤ y{Ddrbi8_TxYbz۔mbb]sht[iJG8Rs9fZ^s3kQJ.ausP'pi7F^ aaBTcea4aQTAC,I8@dC2<Z89f M{57+@FJAL=6Sl)6>W]2[ Y[Ep_6v׏Ivznmv5lqH98b/8HD ^?qz׋u?\@ak)|EAsI BhBX2jc{_?u_Vb z~B9y* i**&$A$J@?>YDH1-s[s JqORFw`yNiScۈQysψsIgH ڰÖ©ʑȤwM˜bhzofuuGeq3Ăfuc~wDsΗ=7R q vjqqdmoQbTiIw7G /0g^/,x=b"~+c,%*8 *% &x @dKOnlVppE: e$}$Z&^T ]3 sݓjiqk j{urKIM86yUzH!]Tj Qu…~zr̡ 7xAxԟv@Ĺ p,o/(<]! 5p%XA&"q65& &** , <y274?8 *44v+IlI H$m\, I)Eu k<#"#9G5#<J)) 00(!;9I5<#fWkXv%Q K(QrPmOZd!v0\M^j>FkT@HQC/U56s? :3p$I3N5")FGG!S4#Bdt XXH8@3 4})B+#s.:;;/QE'XNd&5F{ZM^g}fV|,ԓfܛz7`%r{zND%x>Wd#IT&lGH.?*r 4$P*0Fm͒t z=RUixEUHUW?59GGMID?3H76P0XRMYGDVN\XK' Ld~Fk/ə}To?dlgj=rtt*l|hl\T\;MaZ3C]g^!Wp\rڄk mD,VQMgpE*<]?]vnuGuwoxRfSMz:Ũ,RQ,4s** CGuaxęQD "5w6=YE)C $;$[\bO1B{32!nL 2 0C*H?O )E5-asSզ޹l~ &gFl~ խߩ>;|m1ʧ'r]Yv+k,=hi7ї:0ιIg*}}v}7Zof` qg>h0a2gE8e'XQ0I:4-U!.ER]I6*T=AQ.-z{5-@@!2:$C*:6,a%#S @qEY wccau _ؒi}~,|Go~͘Wzװq<=0ʿP 5.JEz#+ M &( "01&$7O>/OyS59f9Ej3@:OL_3s.bbc5X4]*XSC`7]A6J t%GfZEKP)7l>hD!H=8 [$r'!(yf9{i5Io8Yike_E j =+VfGӸbq+̪2/b&YVѣx".{mPU[\2~yvyqӗozlms`uw{dgΩf5SsmP3l~wz}pQJo[Hw~Kq9zj\ Ts{^jd_l{CmdOmRnn\w^mnٕsqDΗuȳ_4fyiD"#MZa 2 `v bJ f+)*L RY%z9j'J, 7| <3A<2FC,3RAQx4Hm5KeEtjk/K!RM{9yu].e6yt1yg|~gqkc{؃hX] trx2ki,ki msqyth/ur.Guhvby2_S]q_6+b|m'bd4[^8J`lnFxRz bll`r }yI~FMr{wi}xhaU(yvF|WltCFf^CKcTol]bSi@TTIZ+`b4.K2]3dBC E|;50!-!4#:  D`)_`@@^\^Ex&HO"&Z v]~+&)1Y/3!E $&R0),%;w(wD%6;%*U]S0j9 \ @Sg@FCC'>.@A dE<Yc ' VI@TIoZdI\RAI>%L <Nk.dJHlf+{>|1Ql6OL:0y$X;Q&%54L&Z DT޺0f.AyO" aF\bv:=P/>P $A[+! vzb'oCx1h9moyb"Nkgv0tیaaR^iXitcotq|aIk:`T1o3CyP8 4%s[W#93'x&*$&}&&-4G!(SEA Nn/ *AC&>H-bmmXG_^r>jΆ*$?Xp֭%S3s  Q0 mRzP YBPQ'Pal04&/_D*gVa5*KQ#|`T 2E E 't0O,X:EJfCo xoU@"^Q\UXbFKh҅ t:Р͠oɣţ[()3>8ID7eTsH޻ؠ9h(!LܞCC:yl5[a)j [{?G7Yx<=8oE @, #pL 9C oN^(N#w}=αW^pm!r+ W[ ,@4##!<0'$2)(6#.`Rp>u` 2& 'NE 9lY[86\6ǎjdCG7t,mbwyW۴Qַ7 3D3Bn3Zv|d+2'" ()]0^* "- T-=,=I7)=DUqBX^o*bb}nfcyMu*smЙ]V&ם*-xuލ0 wj`\kDtU>+B4E@F8'* &6N*Mt)SZN`h˸"8QhָCv2 IaMX*83B+bE7` yZJҽD`qMoAݲ_i4+c-67bѭ bҞϿɀ״qk| jrmчpxw`u{$wd_iy?"o&~gysO{T{8MC-re~|?#L?~ND)!''+<8..AiNq:Rk[nxfӔs*xԅdÜ Ņr`աҩm^&iQsދXptdwg Kh2OG&DPJI,}# S+G%%,%pn%%l 6)<:b/`3N<GwL59/>&N-IIG7hLTWJDWh$g+[WB6t\6R olQQBKOeOWCH#CMfEQO6tRfISASIe =CQ'. LO,7#'^ 01&S.!kR MGsH>L`C:]P? Q)dЯ e[D;q`efh, d(p3<4-P.7xU2H4JD[7dG]GTVFjFB`eaCkzmjhHgjrMsdEP?G^BUE@>N=>K83V?.GY(9'.0!*3((,}XM& ĻB*#]D]ri 7NevQE|\,7s $khR:qom pt WW]A# w1_V+Gn$[q2"c@I5W0v`Q 2Y&1_`$ Jh"Aw193W(M(P$* 2  *$D*;-y!.85>F0f7BN9;V P:J+La%:(VE Y )K8vvG( z yjW0m=9V[Т$`de+* ]5 t_Ml Y >/"/'2!|: J4E`0EKK$LELZXbnkX czhaNm&d[gv[chdYUedWh~ {AX`ZH>}\[C2X8Wk0DeLqEC+GO$WD3M$+&A(2hX-%:8A2% 98%,,2:7$*C-"># *R4?i("z,I it)- #@U0+}@@$2H(%%~<'74i;DH?65dNGTLV1J^MicYkLansevJ [cnidv'p$plop]bbgTYY(M>JXL=C=j- L)2&2$ kuIx׸,ʙ2=љ a. vibq{hWu }`oXd%js~f^VZn$hF`\w]Z{߉nzkQt'?zuIя ~{|]SyW)Fژݘ41*{ݢßo߬ qV!LМN~(l[˰Խ,أIDջ(ULҹ͸:}a fAlrGJhM x R   #$"0%-v:IDM43!1494GEWqxaItb2ro5satnvi~t P{rtˌw` )ϐҀoT*}~;w:jqfa[xjYYaEQjZzG8URMOd38-P] ,G&nR 6@3|vVx @/;_%-#N O#B!j . $B;!$ x M&G%)e DZddZ `\@u9P & 12 Y$ - jL Rwpl38'ff]G4Z]X"0)xW^Ȼ#2W%|qMݻHdc9y!?"n=Q.K+MKM=%RZ0p Y!j;}dNZ#wl)ua` sruzT}xi\xekGNkLY@MNFZJI,>5N#5(@G8&E#C, $/   % 1 ~  5,6̹>!*@)H] wii,IGHb\utUvۢ±~E`ikQ"q?{}3 i:v }qIs,@tR!Lst`rD+K5}B T A e >(5y(2:=3"a82@>|- 2"*$H1`M;<I9+a4E-@9E!42ym8"p.(>($*$&v*9 - v= F9M3.U.|ZuU|bX& + Bl`, e]][ lOe =[X$"s0t -.@&p <+~-)!)I$G3OHt<)6O 9:-U0AV 8-+"5\.82-*r+=5H=|7+ K.D k%} 7aCtES0pR E0$ "s$"-h0{Ql$v#_<4)h$/7DOHL'@ChE%N_?HG<r-Upd WJFk8?Vj @JM;FK^X^W\MSR9ZSM2EGMQt^|>=NR4XY_Ud?n4WcZF[IHYmQ]E9MZMd3X*9sEB?M>X=j(ABsD@+r'8V)n',$8+%v&)J f'I  |WI1WZN|ӲL_k;S(9Xp^VB&a=3cNOawIw*=\Nh(H(=Q7*C2ҽ'kp,&ҙ\)ݰsq'+ҫ`Aդז:2fX. ̒hŨvlVZӶ}SߜhW* %uct ~" Sp@-E/JJa7BH;IyK^)OUpBV]]XOTYj];SJVa}I8k'AWcEbVZ6bDQ@9SDO<1%(*D!.I %5F )3F9o k 8B"Sy2 +uK !16,!(+Q)":*6B1 i#L5I5a&Qh"Q*KhgdwiVm`lljxw`v5A^uqV}>S0ilVUfV1Cd+cP?BUfE7A"6i:G)$1N68"-/0>? Y~ pVD-Ew"nSi~*6FTrT+!we7I(P_]1U"uZ8f/!2?'$#/T&!";7(:)Bs22l eI6?>E\>;5o?909>W6v('!0 +-oT   rW5YGPi~lr_Vr h2XK'mqx!n60E$/iH7QG7(\MD9\YLm;4L/7RHZ0W D_ HP#S=0=HOG7g<.'5_@?-` /B.8}f7(.:!o#'pO;XvlJYWDA"O^<\]S:ĺ=L0/14rHڬ'vʭP и]:^ ~\9̲CSܲ?UÞWިҥ̛˟-c±\[=1']?ǤԮ_t֫::&I_+j-Sw+YE>!E+>MDA/< 3%$ -,)5\1>$>?;$<v@8I:XYQ\JgP\VYVBpZ[SG]'a*dn[rU5s[L5c^g]ITxj\H(leKQ[$V@RLG[RH;Ub@5*O=? \U];GiSLHI|Id<UrFTH?NY"N&]IKCSDNVCVOzW3Q[QpTmBF@F=$.QA8C5=5572:/?`$#{ z YeAyY VV 1!:)L   #w@ 6&k,&b ":I ! Z < OY! wE}(m{J#v`KB!ENTn/&UGl`m/c _una .8t]zCj@$25iL|;hj@* l11d !_0*QAFrwѳx>v]x{8f&Tn)+,L/0%#UFM+fiҹt@.^| ?% &kAB/Ga) yr ; g; U %J02`$#)<3?I744NF9A79+AG^N3AGJ@;BJ3L?WnK7*9 @DO"H}d\NSB U[dpW*RJIQy_Ln]KdZLYpP,KDUI3>CYOJ_JJE5-3OB81,9K 8 .1%2$w' 4c G :;(\ qC + :@  &jt  mA)A-km 4i4g.13. %]45)+^31% 9$E@".Z ~'[ #$c8C}kn )lD` ZQc? UTu5(dk^I[ 9.6d.ni [J 8 lvx 7 %ui(!- ' b(u$H,"2-;*$+3)o+ "x k+0Q&' 0]+De w> 63S59QRGt[]6.|    KTz]J^Wh-OIco:'PU-Ebgi(Jby7h"|9pEn'Q9@>OW-+v`Mg!S=pM^aq5)k;FZW 0Y*6[ ]8  LP$%.B!%$"#!y1@'+~ !Z py^ J _G#   ! ! " %,5&4 !h7 1G3:H)+U@ J!WSI >^gcXH?]`bbS`\_YVLUEqeaRWccOS0WZM(DUC@2!H>?4 1<1w$2W gdKBs #\)'1 }-4ub"3(Q W~^wN8'.G\-.5*<?.$vX c7VlgJO 9{,Wm!M RoZZs.2"="2o31&lf v4 C& ,y1Z]0%#&9y)(.a(.C44n >4=/b64:6:8=@2PN6/65$+W@ A4"+5-41[AC$#A2t">$",O%a&y m",   }# 04#7$F7KnYtR(1L}V. NzXOx9I)j"GZPD) ^ whx.y\\( n^0\%UZDSA{HEPU=9$/XZMe+.: F   "  {tt"}"YX l*)*+ $9* ;2&T!AWCIB;;;.;9UV_F$60?KIS,(B(CL>E- 1;4-+?5+8)F@C-%`T&j)(>r @& .[ J 7VW %r<~I)P%TUxo0{X}x.:m&1[*D ='#t  4 kavC " ckq?  H; T o//j+q? -568`6'64V3:S$"7J+L %G%*H G_R Oj:5<K?6MAR_>g lJ ^rF"*x[y* w m } 1"]JX o W1e =c*y%AZ &2fd"s7]e3=$J=۹޹e+HֿVŷ,D8зIBkd 6[*   V o6p"v!'+{)&Q$t2.7"n )1575 A.>1w73p7n7+99'M))1& /%w|;"$~11 )k$%(\4#*"4!1:'')p) '(}! <;8Z6 W F-+J\ h 2e ; C , WK k5j L#HW !"['/#/$+j!*~V!7l  zDqoo^H p9 /pQVxf-I"g^8h 87+O6}Qe e ea[#zWq1bT#_l5v!'''(N \ ! AY j fof!Y`? 5#-L&A" vM( ;2 4 +    Y/ B{ MBA   K[ Z g   $ * ! .K h1 0f#=Lcb(l/,61#&% #-!*!]"U"f" I1 Ti gL 4MQQ;[n00%~@u(rH'Tp=?%QPD2Ex87Da>M"{ 8D[-' )HJx\L  j  Fy821P z0A^7gZ=N:x>SacrX (lra &*=% m") '%5*$v(F%P)Z-<# :A4%*#*[$4S1;3**,v6,{)F"7s:% c#"'!j+/$R@#dE<Ec R ;s. 2l I#jjI KLK*v/L`4] `f'_Q^OW/[ !YS & s    vm W Z" (H w"%V V 5 B E * G{I) 8&5S<DHMuN}r:tD v+ +L ,?V '% ) Ad({4)#"),&$&<y:8(1O&c7*34~3q8I<.V:1-!F^-i3'g:2h9;$&7 ##J3T+! @"##}) u 4u ]]Z ^^KB )S"~T6uNQ?jDE3y EJ059$Y>{ay&+E' ZB/iXqdHE <z  (  ZKQ yW+ 9 q)v&HF))"A9$1X(l,B"|fI% &Jnr)Yf=8*>?8(g9*3'+ Maq 4 s 8dn $}!"["!ve6 ro #~;.>$ $v" E K c w! T 9s =0 te ?! # =P%1 I"Z! ,&(#0p^#",'?$v /)S"-{ $ @ n(' 3lDK @hv E [ "(F 5 B @ Sb > ` l"t    =%CR 0mb9Z c%2%u{F B"\ 1<oT3Tqt7g!Z> op U 8 q;;u7mRL tD^&BE#p{GrYq'k>@RQ~5:8orF)3Vt!=ND7 % [ C  U F  >9&-*4 '  y + k[2 <  j&6oELp 4b;=m8tj\h?|'r{_&!e{? Od|iB4 y(6i v0 + g) V&Jt K ~+ Z m l j4wt  'J!Ua;gWCV) 3V!e!N!hH p o1+Y`z+  &  l c a Z     I WX Y 5 B!n;p '  c% f |~ 9'2 =+ u }DpIaE}IH{$Zh8 976xNd&ko~F+$*Ior"[[dfB|TYb:xNDa _-W na"!  p9$SINSl J/a{r`ty8\ Fx(g[B`w$^re M0fHgn ; } Y\ g e E i_ Ac -   5 [ *"'$/T --$wVi7qa'Z+wl<\nBwW0D 36_8'S?AU1l$OQ=9#t/Fte\W/" =l6fVUyhB](W9KUzB cN vjuT  (Z  `P N ~(  &H=C L  `* i`    R BA|<x G 1B 9 ] *SrZ Jq HO)oLp&n l" &$HH%MNlM3/h tKpB)h8#F' `f+ M0O)$~ish#Wfs$z.\v^RqZc%y4  2\enw!?asj06z'@f'S{5`(v6awc>QUz)7*Z4E'&LoUFbbw N  (C ] 3xZDv{xX7o9pL=|15WH#ZK:bL]R}5YRU-[z}kfTvJxC$mk*4%P+9 3LxSCTJd>K7|4a,0q @D E2/m._pb3B=>z7"m/oU{VebCGQ OghIZyLGklv:6I.-lWH2<yD%D<YUo589rZ*lu}#R;<]-#U?#-Hy(kiK!?4dI1]Td.UaZ&t^vvf3 m0nhfMB=d!q~?Mlqd0_!u){'InYV)(*iHU^[a8J|#\=S5O!BaKGwTPh?JUaEStvu*KY"--[Ccd' "]!r"rz^`Y zV&O&V /2X%(x#8M V`F~VRHr"jBM)b?pw~D\kK>dKMR`UB!8{Bh&w2T!ucnm>y?nsj&&vNymm9 <&h3t,_|kPAls1Rb3qcFrw'>0al*.2v3Vkb#1rJ7M#|{E('/-S;G}gY8"a0Pb$N/8x ^  )U2J**nkh|^lLuist!I!hv8FkTf6jq7K[$+|6}WAha{%|W C]IrN9$69T;B)3F@'U2:%FV *\ A} #%w_wv/2,Kbu+xtgDn.> s^VlzcKnb=1Ih= HT ,4-G8D+,K4G;DZ Y[3?8KA;B@:*B5-$&50+)9'()# !   SAUR1, 0, 6, 0LISTINFOIPRD99 Drum SamplesIART 99SoundsIGNRSound LibraryICMT"http://99sounds.org/drum-samples/ICRD October 2014id3 ID3MTALB#99 Drum SamplesTCONSound LibraryTPE199SoundsCOMMNenghttp://99sounds.org/drum-samples/drum-machine-2.2.0/data/icons/000077500000000000000000000000001514070543000161075ustar00rootroot00000000000000drum-machine-2.2.0/data/icons/hicolor/000077500000000000000000000000001514070543000175465ustar00rootroot00000000000000drum-machine-2.2.0/data/icons/hicolor/scalable/000077500000000000000000000000001514070543000213145ustar00rootroot00000000000000drum-machine-2.2.0/data/icons/hicolor/scalable/actions/000077500000000000000000000000001514070543000227545ustar00rootroot00000000000000drum-machine-2.2.0/data/icons/hicolor/scalable/actions/share-symbolic.svg000066400000000000000000000021751514070543000264230ustar00rootroot00000000000000 drum-machine-2.2.0/data/icons/hicolor/scalable/apps/000077500000000000000000000000001514070543000222575ustar00rootroot00000000000000drum-machine-2.2.0/data/icons/hicolor/scalable/apps/io.github.revisto.drum-machine.Devel.svg000066400000000000000000000441511514070543000317750ustar00rootroot00000000000000 drum-machine-2.2.0/data/icons/hicolor/scalable/apps/io.github.revisto.drum-machine.svg000066400000000000000000000225201514070543000307330ustar00rootroot00000000000000 drum-machine-2.2.0/data/icons/hicolor/symbolic/000077500000000000000000000000001514070543000213675ustar00rootroot00000000000000drum-machine-2.2.0/data/icons/hicolor/symbolic/apps/000077500000000000000000000000001514070543000223325ustar00rootroot00000000000000drum-machine-2.2.0/data/icons/hicolor/symbolic/apps/io.github.revisto.drum-machine-symbolic.svg000066400000000000000000000033101514070543000326210ustar00rootroot00000000000000 drum-machine-2.2.0/data/icons/io.github.revisto.drum-machine.Source.svg000066400000000000000000001204021514070543000260200ustar00rootroot00000000000000 Adwaita Icon Templateimage/svg+xmlGNOME Design TeamAdwaita Icon TemplateHicolorSymbolic drum-machine-2.2.0/data/icons/meson.build000066400000000000000000000007371514070543000202600ustar00rootroot00000000000000application_id = 'io.github.revisto.drum-machine' scalable_dir = join_paths('hicolor', 'scalable', 'apps') install_data( join_paths(scalable_dir, ('@0@.svg').format(application_id)), install_dir: join_paths(get_option('datadir'), 'icons', scalable_dir) ) symbolic_dir = join_paths('hicolor', 'symbolic', 'apps') install_data( join_paths(symbolic_dir, ('@0@-symbolic.svg').format(application_id)), install_dir: join_paths(get_option('datadir'), 'icons', symbolic_dir) ) drum-machine-2.2.0/data/io.github.revisto.drum-machine.desktop.in000066400000000000000000000006631514070543000247330ustar00rootroot00000000000000[Desktop Entry] Name=Drum Machine Exec=drum-machine Icon=io.github.revisto.drum-machine Terminal=false Type=Application Categories=AudioVideo;Audio;Music; # Translators: Search terms to find this application. Do NOT translate or localise the semicolons! The list MUST also end with a semicolon! Keywords=drum;drums;sequencer;rhythm;music;pattern;beats;percussion;loop;groove; StartupNotify=true X-Purism-FormFactor=Workstation;Mobile; drum-machine-2.2.0/data/io.github.revisto.drum-machine.gschema.xml000066400000000000000000000003011514070543000250500ustar00rootroot00000000000000 drum-machine-2.2.0/data/io.github.revisto.drum-machine.metainfo.xml.in000066400000000000000000000154501514070543000256630ustar00rootroot00000000000000 io.github.revisto.drum-machine CC0-1.0 GPL-3.0-or-later Drum Machine Create and play drum beats

Drum Machine is a modern and intuitive application for creating, playing, and managing drum patterns. Perfect for musicians, producers, and anyone interested in rhythm creation, this application provides a simple interface for drum pattern programming. Have fun!

Features:

  • Intuitive grid-based pattern editor with infinite pages
  • Custom samples: Add your own drum sounds with MIDI note mapping
  • Adjustable BPM control
  • Volume control for overall mix
  • Save and load patterns
  • Multiple drum sounds including kick, snare, hi-hat, and more
  • Audio and MIDI export with support for WAV, FLAC, Ogg, MP3, and MIDI formats
  • Metadata support for embedding artist name, song title, and cover art
  • Keyboard shortcuts for quick access to all functions
#eac8ff #9d25ff Drum Pattern Loaded in Light Mode https://github.com/revisto/drum-machine/raw/master/data/screenshots/drum-machine-light.png Drum Pattern Loaded in Dark Mode https://github.com/revisto/drum-machine/raw/master/data/screenshots/drum-machine-dark.png drum-machine io.github.revisto.drum-machine.desktop https://github.com/revisto/drum-machine https://github.com/revisto/drum-machine/issues https://github.com/revisto/drum-machine therevisto@gmail.com Revisto therevisto@gmail.com

Drum Machine 2.2.0: Reset to Defaults!

  • Reset to Defaults: New menu option to restore all samples, BPM, and volume to factory settings
  • Clear Button: Renamed from Reset, now only clears the pattern while keeping custom samples

Drum Machine 2.1.0: Drag and Drop!

  • Drag-and-Drop: Reorder drum parts by dragging them to new positions in the drum parts column
  • Slide Animations: New drum placeholder now features smooth slide-down animations for better visual feedback

Drum Machine 2.0.0 is a major release with custom samples! 🎶

  • Custom Samples: Add your own drum sounds and map them to specific MIDI notes for export
  • MIDI Export: Export your patterns as MIDI files with proper note mapping
  • Pattern Management: Presets have been refactored to a more flexible pattern system
  • Bug Fixes: Sounds now stop immediately when pausing, disabled export when pattern is empty
  • New Translations: Added Catalan, Greek, and Uzbek languages
  • Translation Updates: Updated Slovenian, Basque, Ukrainian, Georgian, Chinese, Persian, and many more

Drum Machine 1.5.0 introduces major audio export capabilities! 🎵

  • Audio Export Feature: Export your drum patterns to WAV, FLAC, Ogg Vorbis, and MP3 formats
  • Metadata Support: Embed artist name, song title, and cover art in exported files
  • Repeat Pattern: Set how many times your beat repeats in the exported audio
  • Bug Fix: Fixed issue where multiple drum sounds weren't playing simultaneously
  • Translation Updates: Updated Spanish, Russian, Georgian, Chinese, Hungarian, Swedish, and more

Drum Machine 1.4.0 is here with some good updates! 🥁

  • More pages for longer, more complex beats, because sometimes you need more than 16 steps!
  • Mobile-friendly improvements, now your drum machine works better on phones (with showing half of the grid)
  • Goes global! Now translated into 17 languages including Chinese, Russian, Arabic, Hebrew, and many more

This release of Drum Machine 1.3.1 brings significant UI and functionality improvements:

  • Refactored headerbar and background styling for a flat, integrated visual experience.
  • Enhanced accessibility with improved tooltips and descriptive labels for BPM and volume controls.
  • Redesigned app icon and updated text styling for clearer user interface elements.
  • Optimized layout breakpoints to improve responsiveness and reduce early scrolling.
  • Fixed padding, border-radius, and vertical alignment issues across multiple controls.
  • Updated file dialogs to use the Nautilus file chooser for a more modern approach.
  • Improved keyboard navigation focus and updated tooltips, including dedicated play and pause hints.
  • Transitioned to the Nautilus file chooser for a more contemporary interface.
  • Now accessible on narrow mobile screens with adaptive UI elements.
  • Refined app icon, and adjusted brand colors for better contrast.
keyboard pointing touch 360 offline-only
drum-machine-2.2.0/data/meson.build000066400000000000000000000024011514070543000171330ustar00rootroot00000000000000desktop_file = i18n.merge_file( input: 'io.github.revisto.drum-machine.desktop.in', output: 'io.github.revisto.drum-machine.desktop', type: 'desktop', po_dir: '../po', install: true, install_dir: get_option('datadir') / 'applications' ) desktop_utils = find_program('desktop-file-validate', required: false) if desktop_utils.found() test('Validate desktop file', desktop_utils, args: [desktop_file]) endif appstream_file = i18n.merge_file( input: 'io.github.revisto.drum-machine.metainfo.xml.in', output: 'io.github.revisto.drum-machine.metainfo.xml', po_dir: '../po', install: true, install_dir: get_option('datadir') / 'metainfo' ) appstreamcli = find_program('appstreamcli', required: false, disabler: true) test('Validate appstream file', appstreamcli, args: ['validate', '--no-net', '--explain', appstream_file]) install_data('io.github.revisto.drum-machine.gschema.xml', install_dir: get_option('datadir') / 'glib-2.0' / 'schemas' ) compile_schemas = find_program('glib-compile-schemas', required: false, disabler: true) test('Validate schema file', compile_schemas, args: ['--strict', '--dry-run', meson.current_source_dir()]) subdir('icons') subdir('drumkit') subdir('patterns') drum-machine-2.2.0/data/patterns/000077500000000000000000000000001514070543000166345ustar00rootroot00000000000000drum-machine-2.2.0/data/patterns/Boom Boom.mid000066400000000000000000000001421514070543000210750ustar00rootroot00000000000000MThdMTrkLQ '"dx"x"dx"x&dx&*dx**dx*x"dx"h"dx"x&dx&/drum-machine-2.2.0/data/patterns/Chill.mid000066400000000000000000000003151514070543000203610ustar00rootroot00000000000000MThdMTrkQ q$d*dx$*#dx#*d'dx*'x*dx*"d&d%d'dx"&%'*dx*x$dx$#dx#,d'dx,',dx,,dx,"d&d%d,d'dx"&%,')dx))dx)/drum-machine-2.2.0/data/patterns/Maybe Rock.mid000066400000000000000000000004551514070543000212470ustar00rootroot00000000000000MThdMTrkQR$d,dx$,h&d,d'dx&,'h$d#d,dx$#,*dx*,dx,x&d%d,d'dx&%,'x,dx,x$d,dx$,x#d,dx#,#dx#&d,d'dx&,'x$d,dx$,x$d#d,dx$#,*dx*,dx,x&d%d,d'dx&%,',d)dx,),dx,)dx)/drum-machine-2.2.0/data/patterns/Night.mid000066400000000000000000000003551514070543000204030ustar00rootroot00000000000000MThdMTrkQ '$d"d*dx$"*x*dx*x*d'dx*'x*dx*x*dx*x*dx*"d'dx"'&d*dx&*x*dx*x*dx*x$d"d*dx$"*x*d'dx*'x*dx*x*dx*x*dx*"d'dx"'&d*dx&*x*dx*/drum-machine-2.2.0/data/patterns/Shoot.mid000066400000000000000000000004411514070543000204220ustar00rootroot00000000000000MThdMTrk Q $d"d,dx$","d*dx"*$d"dx$",dx,,dx,$d*dx$*,dx,x#d&dx#&,dx,*dx*,dx,,d'dx,'x,dx,)dx)$dx$h&d'dx&'h$d,dx$,$d,dx$,,dx,,dx,&d,d'dx&,'x,d)dx,)/drum-machine-2.2.0/data/patterns/Slow.mid000066400000000000000000000002631514070543000202540ustar00rootroot00000000000000MThdMTrkQ$d#d*d)dx$#*)*dx*p&dx&*d)dx*)*dx*)dx)$d#dx$#p*d)dx*)&dx&)dx)$d,dx$,%d)dx%)/drum-machine-2.2.0/data/patterns/meson.build000066400000000000000000000004071514070543000207770ustar00rootroot00000000000000pattern_dir = meson.current_source_dir() pattern_files = [ 'Boom Boom.mid', 'Maybe Rock.mid', 'Night.mid', 'Slow.mid', 'Chill.mid', 'Shoot.mid', ] install_data(pattern_files, install_dir: get_option('datadir') / 'drum-machine' / 'data' / 'patterns')drum-machine-2.2.0/data/presets/000077500000000000000000000000001514070543000164615ustar00rootroot00000000000000drum-machine-2.2.0/data/presets/meson.build000066400000000000000000000004071514070543000206240ustar00rootroot00000000000000pattern_dir = meson.current_source_dir() pattern_files = [ 'Boom Boom.mid', 'Maybe Rock.mid', 'Night.mid', 'Slow.mid', 'Chill.mid', 'Shoot.mid', ] install_data(pattern_files, install_dir: get_option('datadir') / 'drum-machine' / 'data' / 'patterns')drum-machine-2.2.0/data/screenshots/000077500000000000000000000000001514070543000173345ustar00rootroot00000000000000drum-machine-2.2.0/data/screenshots/drum-machine-dark.png000066400000000000000000001064301514070543000233360ustar00rootroot00000000000000PNG  IHDR>sBIT|dtEXtSoftwaregnome-screenshot>/tEXtCreation TimeWed 05 Feb 2025 04:45:49 PM +0330õ IDATxw|[- ; I@a$Pfoi٤B[Fer_nB/R.ʏRl{(4$'ΰرlcc˒,GGɯ'cY::8q@qe;@bv|C!?(@YJ @g/(P]B%tr5 smEk]Lk0E k0@n™%,sdZ&[ a^|,6vϩm 仾> b^|*Ev%ӶXЮ3ʒsmأ2hGY™j=?׷ $+-9[6sPe`d4蹃pbAf\@Uh.9U6sY0YW˥ tL\)FvL. Xq]>lBQot f{7sa[,KۋF˦i%s ݏ侾=}YwVZzl\:}(qd3CjPZˎ{1SӾV%a?Wͫ̾d{/)-̕8ep|4ed[0{{́4ihRl/3˦)%YٗD:Ҕ,[}˙3{7^6M)8KnLlaLwgiM2W2-Lu =R]ۗ™7e3/*uLV0d-^oY*vw?WZf9Tt'y,Y0ھ%=}}+KH&+ɖI͜)*Ev.PD- {>sّ]Ovxk|p&z n%y,N+a;>D g:q|Vⶺ?N9U4Z(]/Ʉ gPrKj/ IQɪbgl[vN,]`W싁>?AЗs3=d%k;y}sZ$S4S,jɲ\.=.yny}nEck>s,Rl9+veԅ(}#b;] t| n=h؍ֈ'C\| ?T9OTc K&eӉCBޛq; OPb[Mtl|'kT473ٱ~$E "_`XVCdeIpL?za[/Lvnd?וu.}i}ݛTW}O+3.4~،?6ݔLvEc*..=pS_XK=/;b?/*r="fCI+#Q?lo!mOfy?;FylGqԯҡy:K$.y}T:4Rܞ~ҕ]bfufhTWODLЫ@Ox+𪥩Mm1Kf]L1.{4"ᵩJ)D |}.]J*( $B.N9V4Sm\<yW}~xَa$W+": t 1dh957 >?i=u˜}a%tH5ɳ9q hOf@ILIR0ȑ}9}d9o}oE`cJ#fV ?RRF/׺9w/.Iٱ'3:wiWz+SwDW*fV SoWǞ, 5z?9%iǪ@.IM v}fUuohr_gؤFꊻOVCms5/i}㿛 t|^yt:I:IX4 'icVՠRffzrCU^Qknjxx5zP咆*$sk}$I*V,_ڤ[2>!S{&鳵z` 6JJ tοH E_WFkGIFŢL:?(ekgŀ08=풤oQ:Zl{ ).3+5X,='W7w?~Ytً'Kњ5Zx ?i,VQivT7굇>ьCicdE-}&o !jblf/eϯ$_+Ir]*h綠JtcJ/vn=J/V+ӿ|%׭-_ ϟ?WB?#CUj%I: s<4)s]ߢw\g~B֞RrIǜtUi={ }{`0/holU=?yE%]h4T;{]wk%zhwɆ\l_6#ً&Ix%SNNF6)tsx`/h?7kǦFM=Jby6>sr=#%>|}I!',H۬mW]Mz{*TIkרr\a:{XUHLeNH򋵒!oW[Kg$-^r֮l?Oth@*˲ͪWo^wFMҾܰɚuڵYkWlS,Vtn>/5iH}woA4~ZkٻUX ۹̩vT7vɃi]<ދtp}OvG>Xv6o.+ZgXuOts>shFU[wh[#1]U[Meiy9#p^ΐn3ߜY6mإ[/}*H8&/,R{)YS]Z{~GiIױnE3+kZ%c'jrD;zO;=s[P{M"V_Ch^V-3yb1K5My0Jݖ=qޯRv׷h>mIkw_θf&?Bǔ*+V .w-ӹG]_|M9B氪? nԯ.zJ^:WfШ C0LxwX׬'MmysX۫+̇tմ3_Y]$I ڽ3{%Ӥ[#*s|"'sPJ ˹Ce]˻sRᾉã2Ջ_8w郅W~j<|>{UV3 ?T4s}-Q3覗̒M9JYIԽ1h._:A˴"qj^4C=Nzŀ( ZjiJcoZR+D?ew1if^n`IzOßf;ri{ sA[("ە|tj é2f/g2 3ZڳfE:s G2-Q$Ua/6íÙ8\6ehT7\qU,jyw{.vWXR,S$S5OCj٣ `PE-6>v&pM([zBQNw\/P4hlE3e0]Ǣ "&VM([Q4hlE؊ E`+&VM([Q4hlE؊ E`+&VM([Q4hlE؊ E`+&VM([Q4hlEʛ+L4Ah4եjR:sE3'Y˥E@s/_vN gh/Kf[EhVD1+T.<.=Y\{A fk$H@މYQŬ±VF* ,pZ-YM8!fEnT,V9i.bZZ"F m%)-r}4սdBL ZmBF4RiIjȾHu2exM,h  9i6,/M8֖0_[&C4K,ŬpfY=|^MP4Mdu=|VYlbh$L~3ZWfh_X Е_0n_Mta@bV30 EH2 ͦhdά(H=%{kgsP4hlE؊ 7\0nr*ƖP.k@bCܠ;~^a_^XY"Z ~9% p ۄ N0ad0'L'ɀC4ʶ"mt]*){9Wc>wȊ=E:a|xcnaY1ˑpEhr<5l׸ɕsT68=ovcaVI嵰o_X/ IDATFhֈn1xcFO+n=]^'UˊY4s(M?{3M6JpJ0E=D#1~Z]Ss\p^} /U}ξnY1KwSں^/N;Љi&jm 붫UkKXΚNL}7>~vh!5nJe+ʆm랔tǪthQ K,$Iq{ܷuc.5TkA7ڐأ E`+&DsMr.CNrrl)2!Cm&C~m&&Dpw(cE"12$Hy&9ml5c<`N7&D憬v,C1a|ɐocIs2 Q4$PSCKijhQ   G3!*lK9&̓9`<`N'0O2 jYUF_t75hղ^?p9c<~ &̓ dp $9<6eNv_Gq{|6K­ 8:wں^%#++?Y1KƐ{oYZ[²drvI R$SMƐ^Ng;8<=]{~mB'0O2 &̓ d/' \r\#knWSRL/?k箷v"K}f|t}+uyy/𩩡Eh 9 &̓ dpBa_WIyu.TRPrZVPs&lk28DŽy _: `8^wd0'L'Kf2dp $9(@yTX'`<`N'\ȋML ۚ 1ad0'EH_Xd0'Cm&s*Ɩg},5c<`N7&_dc 6ۚ ).-X&lk28DŽy o|ׁdz5;"9ml5zWe,5sl50P46ߣn~R[yN}F8)(H[aqS*5b*# q*.jc`hBtÃhѺ~ɽ͒~0~QڼV7|jjhKնM;m0:[jQ Fff22̡h"EgF"IZIMF7RW~Z۴U.לQŘrȘ2=a?jmϾ5v>vWdH@ZyjsU9v+sZ׊7:b~'kl Wm/|_{;R%΢ |MtsiyԸYKVէ\]tB6z lܢ3%GOt+~[>m 5\sQ4I"I֖u)-*-@ֈ~z=IKGN KkkUn^%KOЧ~"h& +,i J}I6,ѪU)|t!r]XLNߣ 9f_ze}hq7Ruʆ']ֽͷ6*.umgj©z dEݴFtՏik4zp]q< Z]VҤ5tDiuދi´QS.wC'ӟ@vP4C4<5倱:E k>P@x"]u+t>ui:{ȯΞ+I:TΏL2Z[ºG֢j.wߍ߾]-yDR`'e,sű*Z!%{N-N1fR1\u8=ۺ^n]n_G1=vz7{<+{s]؊ EHyc 6ۚ z2a[!?6y[EH"e},2!6y[9ݡe¶&sL'ɀFhk g},2!6y[9> ۚ 1ad0'EH"lS$8pT` Is28z55d|Uݑ15c<`N7&BSCKFG^_ N0ad0'V-hZV2dp $9<6eNv_Gq{|6K­ 8:w ,K-aYrv$W:STHL6Cz9A dp $9 GucbQK^G>WӊY 6e]VP Y5c<`N{r%˥:Ҫ$xS m%HR'awr__*]j/]o{?_͍!VǟRVL,vf7`b=Em|,*+M/-%)")sGzr[].KtJmŕCghlE؊ E`+&VM([Q4f; MTrv h]VRpwHTv/O^[r ,,KHLmam[L'Is28y ?M "mt]*)_H}# iUXT`[1G',7?z[t4 5_kjBD7'$W?xX[զ\P'[#Y$-9E',U鲇jYD;9zxIRc}s'UgMC]POҰe)0}|~V-J<`ue#n>_k*I AD7z5nr +N9 Jj/E^3CzO[kUXׄ0FD7mvcZ0\Wz>OeVo4ih Qteg0m.ᔄx <;P\8G=D#1~?~KSs\~|zt7/HWlmՃܹt>k}m]3O~/͊4c+JŇ-3G uU%EgC'&\c}CMZ472eC6uOʊY:cU:-Vml&LV$Ӌ^!Y=W`ф$?}nׅ}/hLϿG}j-9Ƅ|^x_c0{4hlEHtcOI&̓ dȷMdϱMd @e},2Dbeprll,2!6y[9&̓ d@~hInnXdhv,cesdc 6ۚ 1ad0'EHz55d|UAB6Eьg 2>N2&̓ dp $9`<`N7&ªeU-YM -Z idhjh?pԑBIs28y N0ad0'LHv;v&vI5QΑCwpT[7+{{r<9+f)ҖuuZAu?ɰgyRkKX,\..idYDb )e L'Is28y K.KudwUI+u))sJp;NEDE3T^z+[ӛC?#,Y n8 {YTV^Z2KRDR4嶺|C]z/Rۊ+lE؊ E`+&VM([Q4hlv /uK.VfYDbjk +l#Cfp $90nr*ƖP.i,wTAkw<5c<`N&VIy@^Ǿ\<<ТX4FIs28ȯisǫ<`:]nJ*)blV-R9 N5c<`N/Ro;2 &̓ dp%3^Iy@ulok28DŽy _M bFv<*, N0ad0'MtE`Iy@&W&|̄mM0O2 $/e},2!6y[9c˳> ۚ 1ad0'EHuG`N|mMf},5c<`N7@2c 6ۚ =2 ۚ 9ۚ ([Q4}4!I;D_vf:Q"jkff=t۫jmv<9=޳D NOֈ}Z#߫y5l@"ф&LT[Ӡ+OChLT^QОy9SQe*. I?R%I:_lXBa}:{g$;Z>YG Ӈo-?@q1x>YYUŎlM.(˒VꠅS;/ iskѪiGS@_}ځD#1mY__\ uAr }w>~}GjGe}n,{lmY_ϖmԌyt]窨m>фWλz~oh]zzmoyE-ۨn?SsWߦ-OO>ޢ@q~RB6'WӊY 6e]VP Y5c<`N{r%˥:Ҫ$xS m%HR'awr__*]j/]o{?_͍!VǟRVL,vf7`b=Em|,*+M/-%)")sGzr[].KtJmŕCghlE؊ E`+&VM([Q4f; %k`+,E"1 !38y N0ad0'L'ɀCRp{*)طRK^G^GZȐ`<`N'0O2 &̓ d@Y <*)!G28y N0ad0'L'ɀE(,goϣb? Is28y N0ad0'EH_Xd0'Cm&sL'ɐocɀ $:#Xd0'Cm&sL'ɐocɀ:@fXd0'Cm&C~m&C~m&&VMxMH*NTȯښYYjұgѧQ{fzWv<b&$ =Knhݧ5xZ۲cϘ|ʆiM*,븳h`&4aH ]ښ]yFc9X*SqY@ uMzz7e,Iz5WeÊ w龟=;%Ig:>\>|kna tѼ/ij7/v# O~h4 @͟+hB uAY4T-yaN3^gVmM>zg%EG\&iZj g?>c~;Rk?ڬ^-vtggk:}lf̛k:WE%=F#12(n_fs;hB۫w?^]X?7c.Jjjh샷ϖmԁGLU9GWY!Izw.OS5qzt_$z:hTN IDATIsW8QᶨohB⟗ikust)?ڴf{V7rLy}^ޠw~%IO׼ӻ=6|tyyL?wo{"m۴Sw\ZuSUX׮=^lKa#tݽ|x~}cZ}+̡hB4vR6~OkT2$L.IzUzO%I-^϶J&L?,}V`Ň<wgvOӰeG((uÃh]iTد)IZijᵋΜm*)、.}>ߦ-OO>ޢ@q~X~ X57Etiׯ12 3hqFZ]=^|pYZXAgSVC]PWmMh$1:)yD٬&>rIRQI;ifǞMMfCy]zݾnmyv凗凗'] oIxӮ++Z@v>[Q4hXV"9ml5sl5sl50P4$"oXd0'Cm&sL'ɐocɀ $Xd0'Cm&sL'ɐocɀ $ )f|H8P gp $9`<`N'0O2 В‘pTM -dȑ N0ad0'L'Is2 yl^$dn8li[3k?q: e9eYZ[²drvIt\"B-m 6dr<Is28y N0ad0'C=R]iU z{wJ~gN$f; BAs28y N0ad0'L'ɀá[Q4hlE؊ E`+&VM([y~ |zݒ5Y"Z ~ڸɕ[B`,wTAkw< `<3gN'0O29&̓ d@h)=ny[%##OM -EcI/,k*)RIy@%U-תeU 5'`B'0O̙ &ӄ w $9<έdt/ta),jD+Up"r]@@DdW(dĶ {t}&II7g^>INN|'3;gcYf E?8'[Cc=<jp 5gN n0&=&̩EoJ WM}(}rtCc&L>`B?y͙SL 5w sj4Μ笩i(xADmM;b|}s}珕${/kX|.Ŷ/t FDL6J7=ehn=铧/Jᚠ֭خ{n.*I1g.vF*IZbSnz˒¥p>5omՆ#'뷝> p3Z*]U5Q_|z/oՅ+a&z=qڪ[.@t}hcu1Zf\I]{Y>K_Wi͘3YcO4۟զU;J"hu+-=>jHc|X5l$͜3E#?u!$>\AD/ zssEߜs$zSM]HW<>wSڶ~κM=)}^۶%I'<}4QV#FQM]HVnד,ҲW֨i˞^tvILQ85(-hԙuiK}7عΚa 7P]Xt+7hǫF.٨=Dh$iƜ) ZSɲ k4!Ig9} 5ƅۛVgݐ$}}݂wmܣ|bѸ~{yP=X pA(&OiW*ٖpm0F൶yn˄ֶcE&̩F;m{N|m0&൶yn˄ֶc=&̩FtG+Vfjז `B ^k\Lkm<ּcB?mM bxۉEjojk,{ m͝ڴzGLjp 5gN n0&=&̩F hk,X4^͊ES+m(:O`B?y͙SL 5w sjw~>亞oZO龬0ˢg;NG;lVwgTlY%ϒR^TXB]t.|,׶ Xҥ-kvjMEdLjp 5gN n0&=&̩BZYdYRR[%E;%%}q=RRp:h2 ١R24'huCú gIILvueQRZJ(u,,QMG4"hE8 pA(&QJT SGiF\vV{k67k%?>P8@'YAX,HwT]푪eN2a`B?YI&L';Ʉq ԯ糊\Ϝ˘?u;uݟu=}yi]Z\bb+NȖ7ԅtIjh-5wjŢ V,5Ģq5w*O] &d8~L7Ow _dɲ|KYl9qnhXP &wJL';Ʉqp dy"hyL:ʕ? 0uTjCe}H [ &d8~L7Ow o#hyXBk5k˄LX^kN2a6˻p[& Q?mk˄LX^kN2a6˻p[&1#9@֧"̭eᱶM~1.2,&fyiˀq4'^+o=ORi'u>|Α )' ur8Iqu gsԇ4uxv<"P`D_;zsszEߜֽ<'}M?~rŃڶ~cm_uq~M\x։Shac76[g0 A}bVi/PwGDkoȱGqz=#hO&LYA7|]pMPVl=7Mko$͘3Y];O#F$[M)7=eI[sMvzToZ-] ]2Z jk,gh>5omՆ#'뷝> p3Z*]U5Q_|z/oՅsoK =Hy;OX^z귶$]w%|X8}VY+nu^R շ}Z3L5Mxg t g)T*fAD/VlSg5cᣆ9֯ܮɇUI9S+?SG)+OHj}/k?9OG|zpQ@y4nx"Qg"$~jB[Ҷt֥'hIsڶ-If̙=Tw&j! izEZ5mk~c&(\S4cd-kL`DY5miVG[o>GM[5u^XQΝ/} tL ՠ\8?$ԅ&׬.^2w:(&*Ϯ5sd Q۞dZtH:R}tf̙mvnhZwwgȆQl;Wko%h!hBޝsj ӷ7ڡϺ!mI,ڠ/GĢq γmî}`&8 pANؕovmPcmc\d@?Y=M.Җo#hyvmb!_[&`²Z&Ow ൶Yޅ2amM o+u|mP kmccB?YI&fyn˄q4<6ޡβܩMw伯=X4^bѸ#`²p dy'0n0,$ &d8@+m(A[sV,PtrĢ}4L'{<7Ow ;Ow>Γzi?s”s/vK8Wn_.k]JmB~CYV)/섭.mYS+n*޶muwFe˖eY,i5ȶ%Q{K";P &*N2a`B?Yީ+?ʒ%˲*)'5))K\f^WT$Aӗ1-W9z yNFl[vBlGvW8 =Ag|Ь-O]8KRLR=v=Ђ{@Я@Я۟Rw>%IsN?\I{هN0Mȶ~? fkԸ4p.5n~ mfbYh 5W1(qgim[w|QT[Kg [ݝIœ6pAlֲHzY}_$E#qIRݐ$i$I=B<\oZݝP8}έ-8Ǧ$Ϳq>Vӎ?qoحDь&S=> HԦ7-nZ=-)߿wN &QMteՓZ϶ jsjpJ̩,Nof' kj M X,QֶcM 1`N nhox[&55`0 hyD ԍֶcM 1`N nh\Lkj`@j(X45^L'5SL'5S6ޡβܩMwτ MβEEp`B?`B?ܰbцܩ6cM :WVe˺ Sν,]op.t4 ͶmuwFe˖eY8oۊꌨKv`B?`B?Ƶm.%!NjoҖ5;r馢Ʉ keɒeYJKnI GP~z.3+\*KK˘+hfJKy=}yi]Z\b^#?;![#+[`3>h 떧.%)&)2:3וq;GKŃj)ԱʦG4"hE8 pA(&QMG*]P jC |e l[XB#P5~R95~R95~RC҄4r| ;aKMi=A(V߹',~~A5w*OPCI I I I5u!:{k+gV 9Q+mPWY_rl: @@_;5SL'5SL'5SL'5$9254ٓ0Aȣ>T7@Я5^L'5SL'5SL'5$M:ʕ/k5aꨲ4=?K5lT9jV,٨.W4U<a&zLooүr>nӪzM;{~g{7F(&QM ۮ|[`N ^k䱦omXS76y NWmM X,QֶcM 1`N ^k6.jp- V-j0mXS{L'5S6yMisk5Aj(X45^L'5SL'5SL'5$mZCm͝eSV({;0A(ohyj07Oj07Oj07OjHZhCY_m͝ZhCٞf;|Vu=ߴ|}Y9aʹE-%wٮRlVwgTlY%ϒR^TXB]t.r@j07Oj07Oj07OjHEڶ~q[_P@k[eN\la:䯕%Ke)/5~VI=p@/yNI %?g_2r\ϥy8ifv ϙٗלv-ݥ%v5bJe= >fаnyYb9.S3q]3qT<J l: pA(&QMG4"hE8 pTՠ>P8@'Y̶%鎪=B UXL'5SL'5SL'5S X@ܓZAABښ;' jp sjp sjp sjw,P|~54RCI I I "hyԇ7%>D I I I o#hyE ൶Mkjp sjZ&55`0 hyzk̩km<I ൶Mkj`RQלh̩km<ͶMkjf&55` h_tFO^R8:sٯV:3tGkj^~iGEKon6'vVIҸ GMT,w֯QoMُҐjo~SY%ˣ }%Iw|)Im{:cKS!GMԮ[siڝj(U-}a.ߪCv|Ʈ8~N~Wh\-{֭7_\`(Ar.X 4Bp@;۵u΢w΢+nu^R շ}Z3L5MpEcu2G ΢:i>XO=ر>pAm:s}ʏhQ $__8N?{r[zl+ھawڰ}IҰTaYh 5W1ckBi֧tW7I{nn}J]6]|(/kacs>_*4jŧy[^^#IgiC~?,cG6ܮ'XeQӖ=ϧVw}eI?~ڲIͻ:t%I-;\4!Iڱyuu'hI4j0ىߥ7^Z 6[;]Go'kɪR=zwFPݐMV6=;ZpHԦ7-nZۮ~8wmܓyޗMmJG(&QM _ԑֶcM l䱦omXS&G,x[`N ^k䱦Oj0mXS&G;ZֶcM 1`N ^k䱦 M bxۉEjP5~R95~R95~R95@m͝e#I URL'5SL'5SL'5SY}'|ӲMe])^.78q:pmʖ-˲YU˼*K3.Evsjp sjp sjp sj诐V,YԿTVI=p@/yNI %?g_2r\ϥy*]P #̩ &̩ &̩ &̩æG4"hE8 pA(:`>+ pA(&Q*`Y,&@q`)Ut l\u,'`]0S ?'g8 hʸDeL4HX •*0B3qM34bYI_X&e+;p$Mc eRF %`L}:N TeI3nm'PFODl;QBXOA_x~鵘8a ,Km'C%Y޵-|!bvDq;&N: e X!YVzL+c[6)Fdw%Yvz+ҏ{=PykRzeom&$MSj;eLkc[6$z}fM+OdmX7lؽerZꗍ0kw;pfLfiawLt <`+ϭTLM NXB7lJMbTd&0Oͽg*;NZSa&RN/TO~8q4{M'M)w gf}40 A*^)RƪN;`@>`DͪvS{#knZ䈐̪FЬ:Y9NWBȬNͪdZ+tՊW?fU~~8AunMw>"p pA(&QMG4"hE8 pA(&QMG4"hE8 pA(&QMG4"hE8 pA(&QMG*]Ȳ,>>>,%˲dYyl[m[vV"n+O(K(Mȶv2"hP"R0P W X| JR,RP}hBH\HL8-M  \s} }*+S,w$&yB~k%`ȯ`ȯX4(Pd-ԅ ;ɵaEꈰI-j4 >>O%~Bj(\!A !jxkd=OmJ@n @Y!n*[PM@>DTY>Ka#CfJ W}cXMeYꇆvT?4ϐj9hj%%b E&|~K5տF>X4D#?dG|~KuC`^g)?S0WGk7ԅXV/ݕ.@3^|&+?^ePT7$\2A%+2 gLV<.\µJ ^}b8τy2pp7chzwy,#|~KA k ?B9 `kCՃ `#z4fY'- Bw^/sXڠ:[#ڳ]-٪vwI:eξ ݯVOޒZھn$iq[?ig Օ'Nxb@5]Ko:UskZt[z w+Ip%r27˭/cOSomg+w_%YNAG)0O+x-ubxs8<{jB,[Vԋ;\_s9Zǵ}}+mX]~oy9ӠdnzaiV]??ޫ;c:Z_BFIG+ާ g+,KCw_s:XtjB?IZt~hGh3!3HW,}a5ڶnqQKw-Q.54wE5V#4w#qES~m|IwMJղ,uʁWgs-k=zb!SRI1JJH=:Z{>q{'kبzJ$lЧKJE$IKY-kv3*)Y~XǞ1M;6h5ѺG>ZIKV^pw75ep׎ٗ#_'RNy篩3֤#u$7sK^[J?x5avljQN֞۵vjkR0wpX74?j]j[Ljbʹd&`S3k VrXȔ=r&:cT?}:"ⱄ-\-I:#$IyަPmP_5{T=r  Iz륍z%cizō띋z:\s:X;^KY߿>#h#xM<,KjV|tgM2z8ݸs} Zlnbvlj$ =nwuڅ3u/JoU!#juK{K/{%)TŶnz^IWtGtUY;e,Kʭs{=Kw^٤?L'|M^ߕzkHIҌ'jƉ{=~eD,#ۖZwwQN''$ig$\;$&OyZtbxzsζH΃8i~ҍ?-⿭u_۞. {eɄ5pYlmƗ`]=}Zmbф{9͚#ЋGȏSe NRB M+w*\T.ۯX IZqDcui5dx7DmMBtZtf̯~@v֞ZU|ڵJR6XM-zkHgT5:V{Ё3u{AZc sCgje *wnVmzEwƇG~񚆍\?׿s42\;g?YoqgL e/lmЧӘ)Hhq[ k5%&-Frڄ]2KiGQ{s6ڕnF+>`}>~A0 MQduCú gII縴%%וq;G+ccZ|ƒ5O+w[՚Ƴ?,7nX$_瓺y'hqvxAihy_Xܱm}-_k Gxmۊ*%MTx1h. %W }\bh$V|*7MW#2/h$_#g4=.QoXF;"]]p7cUA/v{|`E<(P,`LEy8ǨNMIQx,\@߼'3aa|&sAshⱄ:Z+wbw`0E&~co8k3τ<.嗈jӥpmP_OVl%v ZYUж}Rp/>_5M[*w/ݝQ~:*]5pO"n=yW ?IDATچPKG/&~&ǼjWb٪7EbU}j:3hζbۿ1MffPc:Z"Uu`x,B& RUL U5pg۶[(XB-ݲm.y&aRtJy ;ahcѸڛe'x+*/xA3߀{nA*ǶaDbɐɚL2UMA-fM}ٴ)LL Gy2x!hf3g$S,WM]H"5D<0yW%/B&n I,PwgTʪfJ5;JX$X$@ȯPM@PypF#T& (Ug1h+|f/@[U >`(@?൜hBH\HMd`p#¦'NlZ9O5=NX~HmuwFeY}|}-Y>Ke$d# [x ʲβ,kjh}g.}JSmGKMnVet+\qis|f64)O#/RM]PH_5JLHg\z4S}:vq$TA3{\K}z\K/ ;wl]}ݡ8i6> hOLԥu={MdB}ƪٗϛwn|,Q7pmδ]b/ *e)+\lm\޳;jߐkfSHOcRU\;'4h[oXt_Ϗ2u;}3~}>,cPAD"fbѷ7/~ 163f\1=]Y-e8A3sn>kSY+czǟqqx?eSa0_U!/s쐙y*ϐ*,5h5duޒ~R`e9-s\k'S &sf"cbBWʁu3F?k2_(KW,dZu\J7-e\u D k42{fȘΘ?{fʘVhپ,@eD}6{6Uiϝ=o}LɜYHZ6sM V<ʜ/byJ og+`7dRA}=f`'שP2;UJ6KG༾l\۔61wf_L7_W{_, f+'l溝O]@9 튗9O[cYj7-sbP\Bb겔YhZw[SXh@kZ\mRc1U4Nf){LB)Py} X\XlR)4w"l{\0xCkd}T}fZBK |Usys|7o5 nkM  R>O0O) )|k9Wfo̷9TxdMnٗ2fޗoۅBh_!SL&ӊBZ{2 w66%_LH4nphBT4LRB_)k: TP*wuy ,t&],ҾH'B롴Zfǔb}ױX,5gR(d]Js*HcV@֗iߟRMl+r BT|k)^ ףe3RT&=uNb2W[n[sWUȔ ; +ilNbxReǔz;tOLɜ`:rn˾lڗ)c &NR[&Ń<1&2еK} ݴSjcZPr#l2su\a3ǚM`pp"tg_2%_hp+g(`_9s3=U"p:.z.`TCr㜕1=T-S85o;O)Ru&'ksk^fK+׼n>WTc0TtN<@qr̔j ;娻Z9*dJU +V]LBr^'p#VmȔ@nn)^ KSwxnQ^EԷj0]5jd! >. )) 0f` _7(e{Ϡ ) 5he&Un R.J8H!XA?>Be?ʃqaۃ!_7$YL+cJ!IENDB`drum-machine-2.2.0/data/screenshots/drum-machine-light.png000066400000000000000000001051031514070543000235200ustar00rootroot00000000000000PNG  IHDR>sBIT|dtEXtSoftwaregnome-screenshot>/tEXtCreation TimeWed 05 Feb 2025 04:46:07 PM +0330HJ IDATxy`&# m-*^ZzVYm*z֪UZm $\!@ȱIv&1n6g7χݝIX̬R ;Q1v@#va)>&v"c\ċ@ @W:E86tvנ] }.pv՝ L"tv uL%b--с0-g:鮣逘V3BS}w?4v"7:"pCXr# 3 NŔZpOPհa3UU"fWHv3Ӂ0d"Wu:pTLdg_i/@k s<'| N] ~xg}ZTJ1ހf*IJչYh:̮LO':]WGgL;25 uP"^tstsu2luHȌ!)H mCgHE[lN A A%.lv@M7Cv6dz6@n/uh1$KTxj缾-q2Ey~OLCh3h=d6~G7 uź"lmW@<8 [nUq_-tnͮ0'Bf_ÃemƝ?6豧LkeyZV K lܶZ8o\$5uMlSa'>5 בs3=d!elws:Jv@;: {$˒,dy@ o,}dz}.a*6+۶dԅi#b;- |~~hn@ ʐ lݵf3 n#|E;Sa _),#,&aӤlf,a qiAnzȷZ<'S]]~Q~Hs7y-o[)E);i1Y M3M3%e̻˳ r2tuRAnnl&2:ut=h٦h)UeIt͌vl+z8y2ѓ ycK={۷gW[.O(lyGrU&ԔXw)dzg`Ee&h.\H$fkDu19hdOۅ_ȒqC}^\@" ;g QO]"lѴNt0/q&8Щ'0 t!gof5Ïbjo6ꈄRf4;ڹH'FDy$YyG@ E?L6lef19hFm)һeymɲ<+B&QCbG[2߮vK]+6CU@@0_ zϫXy=^ex3tؒײؖ[&dŸQ]}~Dɞl mo&33N"f$_R @ֿWwWuަda@0Хp=g3V&5a֕#5;rs4#$h<&i[7kCuS"nn*U+y@ǜsN=;\IHw<_~G~ٖ#_H"]6L ^usk5okMȒޡj#l Rެn/ʿG-҈8?.UtIպeu0rswiö5:tѮ" ~GēI"}IJJŠٙ)`g1+kwg/Rex35pjhtw~f emܱNU;4(eymf-]-]3ToNl*"Izn_&c}sͳ $.W šw~z$pBf&;>;d^Q2V??gH_޾Ek6/×s^OngKhFFKŠM<:fjcyFkzK>Zsfp2ACҊ WgN}rz6s삇|zkuɲ<ڡ޹UwnЮꝲdiXtk5Ϩ.مs ׶gu<. {$u97UAʚ]z?-jd#%cus)I_룵o馳ҘiֿW[UUGz ~VnD˫C.4CٙmA٥:I_5o;,IbJ-cIYUCz/mf5Ԫo>:Ni]i% 44_3UW_}GcհK~:}Ż}|OU5 H0EgMDVc(e%OehW/qN0VC>CŖʵԻd)|Jz jߙ]* pَ +}|$銓niQ'1?-[^$*7+O |9z{?>ԝ/J;*}#Sˋ$ݭP5n*5P6-՝/_@}:aΚ0tct?${+]zkUC>RSߪMKTm1]wUh}ד>{C/[響$?Nu/-~TL7`I=eAC&h뮍ڴ4]NOy*Gso 5 3Rk6/_&/H7-U_LPu]a]b6O~2:x践cB.s=;k+j+ӵ|Kt)Ҿ;ɸɚt:_!P}Ukp +]_Z~ ToܾVӷF?zP43շ>PsW)_Լ}Fi3%I~ۺJ뷭шܯA3 C%fZڷ~Իڴ$}_hOPVkO#>f$`9}Z˿X}{uig=աPd>.)t חSҪK4h^[vWqLѥ'%c?'kg3w30-]x*-^w*kwVߞgYLz}ך%.( LPЎ}m¼>w鮗;Kz59e})VaP84JIM'fcӷG/ie놧/nmӹB =R붮REK'te9>x$iWIҠBW{doIR^vֲgUkl;OWѸnI7۵ljꪚ۬ia,c#_U6\ko<}bgcڶg.vGS~=vW/^ n9;F'SY͏3YfxFRm'go:~A>Tmں{ l~;2#v6ʓ$me۶'sˮ굺ԙ*-NUbm*i_fy$oޤ;-||I,Msj},$iP0y={vPwj:``?)/Y Q>]?$IǍ==涽rC Yj1rÐ>#<ڲkz4{2nf~뚗m,_})+ƯC浧ԵTIAڲk}}FԜ4…\u[WjeC׿G[%I?v5W?u[VhwuJVb9r$#~{^[)PYW:+m*@w)Ӗ]?iBa4%iPpm,_k?G5hm$_f$iDXt٪km|d_،#uۿȒqڰ}M}N>GZqzՖ]_馳wG)=OeYڰ}$i̇Z]f>ƕgוySgg !h&|~?G*|9:x4j~*ju=j ,^^<9igزR,[NqcOӸGĵkOKw֖-=_+?4ޱTSW%IϹZmxPм[Vheվ}Gk@PI|ԇ[>;׫נ栚?9f z߫^g\ 58!\ z7g/]%I~=1L4.FQĜ"xCq;RPpN~hV2+lᾑm*[ݮz^R}ޝ:k´.)ÆL Rd)ϗliA$"[|n屭a4¶GPx-ӂ\ډWvfA 'A˙Ng=b@RzplPZff4r%餃I2L1LlvP5u׌GNV|U0rڌfچQۥ\_d2+X2iF— Oj>o3+ç\>74S*8 *ϗ\j+ (h%I#ǫ o2t Rˌ&nɕ2]IJs4#hE8*Ճ&R:z pAt )},3n'2L:M@4"hE8 pA(&QMG4"hE8 pA(&QMG4"hE8 pA(&QMG4"hE8 pA਌d-+=.fJ $L_g=z)1` j le֖$&p(fe+|Vǭ6 fIˤЊo'a34SFYL[2|KAݛ |yiz3x!YL@ ]n-لIhöȓAg7M-%iCf5mfFOӌtE gC4PST;5|-j2LM#aS4} 'd7r1io} lZhyA .eM"[aFh -iЬ&5%MfLD4_ &~g6A(xoߙE8*#p?L*.=c TX|ERfIVJ-)+%8DŽ~67Oj07Oj0&CfXW>-Oh/eB/x2` z=ۜ`B?`B?8tpw\NWj#ڈqp mN n0`N n0`N #hQM/M|š"+J?MP[01|ͩ &̩ &̩鍠 D?,meWClwL!6y!=6yA"0my\xlwL!6y!=6yAWt^C5D[8e|ceB ֶcM ٶcM [}NW?t~~骪qF V/ݬ/~BuLADuj:mؤʚn?囚UUq:s4!IUZZ_F 'Izn5{, =LoS_TR800AYfϛ=KtyGNOI҈c\4o7Tbr,ۼ?NRenpe/zFo|ڬBM=:3oI//|BG?)ͫp A,X^xzo/ S=gXY:`ȡV/vs?>3OAqIҌsfj`}cn[U[>|TY9QC?+ P͹(;+i%RW$I+|϶ۖ}@ >4K W3ok?ED+ל IDATy}6n/M_U;n`}[2ZR(U;W,#4JVOӧޮ#/QC>CeyY}QO-ktK7'r h 'CWu_GS t!__:[}nz2=,r ꝥ/ IBDDٙ9>2s'jYv:g4hEj:Yf\]1fYGsTW$ Bt%Y6x1ղGm꜉tim;[=oЁzET dhE8 DΧҖ^ Qbҳm߱2tk䱦l䱦tM :W߽8g|ceB ֶcM ٶcM @oҽ8g|ceB ֶcM ٶcM @+$yڊnp]?V${L'osjp sjp sj@z#h1K/PToN?XOI I Ԁe%aV;[.Xմq}oUu lزm[Tʶ A%np?L*.=cCUFщW$eK_ /Q_ٱwOI I Q[<,Gk>_euŏhq]tO9=uŏN%aŏӺiq_%-CDDs?fwtS4bնu+h2-ZomU/6$Am_~N+-RqϾ.$U 7.n^g'h*+ԣ;~֟'4~њÙZ\bp[uoGvO7g [jo͞ |M`zK/_48Oyaeg!Z96Y^^}Nn6__\egtc\CD+/-x\4㜙{ߘVVUfFfNgP'Կh~s=ʍ@0{ukS7s\uIʭ*߳-涥e!P19҂ۚM}Nw<3]ּO)GNH*&Ztcq{nz2u۠m7csߒђBᵶ:v`@=+-^Nvd#h O]G_O]@}m!+2E'\[辗nsײҏ# eW Ihgݦ!}Gjןꑷq"iW闳f_L}o,ˣ+ܤEpzgmU[W=-I*߳M[|'$ Aegh;Z %R}ŝ9̄~R95~R95~R95 42JbiyBB[ټЋ15Į)>kPh^_՛`s I I I Ԁš@ NpP~ NC l&̩ &̩ &̩鋠 DQ86᪉85DWx}ń~R95~R95~R95 4(%-jw7JfڢsjHMkjH϶Mkj@w@*L~[qd̶E Ԑnm<Ԑm<Ԁ Dի:54.wWJfڢsjHMkjH϶Mkj@w@DusOWUm˃6Zjf}s` &毫WiK&Unw+Լef 0 IҵҲպG4j8Isfi`a'SGTP_ <W{GNO6;+Sh[,~NR%#$iĀ1 ks޲ԻuWO#ampAm_~N+-RqϾ.$U 7.n^g'h*+ԣ;~֟'4~њÙZ\%ח^Џ䖊MQ AD+ VW> Ecn{VvVrj몕kݜOhx1߷ M _ZWZ+/VvV= ;hKf3S{s۪JiJ|^Y oνGYQhͿ$IyE3RWE+yE?rlmigjiCc|q9G?G]:wgu[ hkμMG>F/Q vm0>--)^kۭGvO}w:dQVigd#h O]G_O]@}m!+2E'\[辗nM}Nu */[#I|ІדϺM3bS=֟tlWW9Mo/}Aut4~+,r~W,}QzZ}-/Dwkg2b**ר}ixgaFegh;cǫs&N9yuSlxAElCth Č&QM@|j+mQCrJpd-j0tk䱦l䱦tM It[G^n̶E Ԑnm<Ԑm<Ԁ DQY!ҽl+mGk̩!6y!=6yAb/O|;P[N)»d1`N n0`N n0`N HoM y YP~ ՛bj#L'5SL'5SL'5SҗYobYWMa3oW=`/ !7زc˶mvPA;(*`UX±R0)P XY}I0[F+{Մ~R95~R95~R95tTŖ*y-,#OeYd)yliA$"ڒaq/XGص h#h49t(&QMG4"hE8 pA਌d_/y|}ْ~R句T &̩ caRVdumh;(UHRŊgXS{L'5SA)>i)?/^Y SC*I |ع}Z|šZ6/Kg4&55DŽ~R95 }q,/ἾPԐ5~R95Wj#ƚcB?@ľ6BmQ5~R95plbCf_q kjp sj@z#hQd'-j0tk䱦K~[&55g&55; hQx\xҭmǚܓULkjH϶Mkj@w@Uלh̩!6yŶ]- Z[&55g&55; hE8ф$i͚,-+X5uUS_']^=\$!&TP1MWQfFFz-X=WY9.@aF*v٢>5/Jv-WvV$鵏Ҽ審|V٣^yEt3YWxGEOkwU|:x]2yz.5w__C?[*=}h\5z8]|5wxr@0 +digv-^l-oqʯlT]WgXo/}y OWGwzÕoooyK^Іk5j:xQڧPn}zsX@*-ZN< IҩթUC^ z]|Z6}ٴ\G?ILNEO5k⁧$ I'j޲O Ԑ#l?(I^Y8[/zZv5/ bnjI҂s`VvH&Ow~t̥ś5=#߷ٶ<Φ b=*)_;fн/ިu6v@q5qV@ Ig$k9ޱAtԘI%Iٙ9a%IJPNŇ@sZк՚k_[JƏ::} 7R4gsݫ_*k [hĀ1VJw_:4\ucOVCAm\M4#Ήk :P2Czy_ӫ?|2|By=5)zZ~V|>%Nt @0 S y ,/SoZ M:a_%I* hB %oޭ;h!S4yTj Rc%?yyO'v$ !P@.d-_In}?YlZK&_'IzGڢɚ5Sֽko|6ext91@Є$ig5gszokzrރztjHmo$ige,=m˚ 1]y$iZznu;l.ӶݛuiՈc$W4Ѭw~:c.}/ެ+gͶM6葷VI@)7}Fc&Z7Ј)߳M~]SϺ]GwlG $m^A}I 9b*wwl$5f3DIRvfNAsX~Ҳ5{3x@0f[ Au*߳Mן}'!0AZWZ>_}{ P~ZIQGǵ!FJ,~Nյ{SeM!~aZ]v0F5uժWKgW(C Vm^.W8M(;+WG=Y+\6.!C IDATכ!}GCN)G>t.=e\-M`@yEV2: rz|"-E~ۮ͒j^M9|&`+ ڹrŲM{g߮z^Cne+ǖm۲vPT$/%vKmoZj07Oj07Oj07Oj0R%eyi,K,8s:ϛ-:HR@[[R0Z_/y|]Kc+tB}esjp sjp sjp sj(>G$h ďi~YG4"hE8 pA(&QM2] |ERfIVeK Jɿ3IYŷTW!UJ+ `B n0̙SL 5sI ԀCbdJ$Ϲ}Z Woѷ̗+ڟ8 Uټ?ј0&Ϝ95~P?1`N H_: o8/F,NWj#`B?37Oj=&̩鋠 D+Jo/V$cO_q jp gΜ`B?M{Oj07&Ef~^ 2aL!g.v[&Ԑnm<ܧg&Q&Džwk+нe8PC\L!6yO϶MtM ^u͉z-#ҭm~beB ֶc}zm5 hC6n/Ew;NT[Wy^;y)ɕ0AbTW苯WI*/ݬ/گWک2$Ak>_gvn߸Sgv^Y8[4~ݫ[.X۷?}.]e@d$˲to' #hCڶNW0Pz_+LuV2Z?=Z ￿$iYz;Ug$iXh]|5{w GYSs&9HH !7"DDPPXQV]Ae`AXDn 7c2IGOOz:==3O׼_dzSs8W$mh5qV^v$)f70͙2_o~E?9ozx}h*a& gus.ХLN;떫e i6}/庎|-myVk6_#xCD?;OUцk[Wc㠖1k\n:Z%ID7?rVmlQ2m$ED?]i=x|Potz] r:4e z/I+iE|]@eq&ʪuĻ4k<-:=`M3sj$IZWUDc&j˜)65˴΋5a~Y0s_G/ףKW[&.lDYՄs`ƾzeѳMg죦1c$/L%ٳekxTȲeY[˲dR1gB҂s$%%ܺn}e=R|eMsL˽_g'Ma&SM@~^lP[S`F9j(Ж`@ AkmPC6yfFQF&P|[6j(Ԗ `B AkmPC6yf&QF&P@mWCLjZ|o˄ֶc}06{04bbi[&Z_C5Vy 5~=gN ~0&L'5S ѵStŬ{ob61aL&9sj 4cB?\\G\G|ѱRIq>V!>OJMfGD>N0&95~P1`N u4Ϳ&AMtM&]]x9{/|,I_'.{}uQ!PD|" >g;L A)&PT|ANE6{qd۬m0Ak]-F U-'_ 2E6{qf۬m0Ak]-F ho|[vj(Ԗ 5.ֶsC0f}o˄qZ۬m06&P@2)Zvb,|0Kej & ?Ow<&f8~{06&PĺG ֚nC0օL';̈́q d}0~04eU`yYr233C9ù˯uzJ\Js庮\ב:r]G)QJ85/fK5͒5̏g\'}D{>U"M}hB & ?Ow N3a`B?Yi&`}Щe˲lٽeɒ?cЅjZ{IJJJu%99ݬzʚ晖{D4A(AɮO4"h,Ԗ cM  (K+ Volt) FD=[ҥ0DXG-EOm^pHxJP%$ulӥVmX)˲5u œ1\ƏLP2&$I{jڰR׿r&"IjުXgMz۵MHs^OzEKw?v_ œ1=ϒ?sy_Ȕњ8fj׆v#0VOϽm^3U˺*_T[4uW+ktXM7sPd*d*W}~]z5'Eu%CIBЄa\%n׆d.ךK(rĮѓe!mܬJ~ݲ^ԍ-eY:ӗSVc(nXښ:I:-P}A9D{%S ߲V Hb5ޓ$c:lwCU+V˺ڹYGMVmM]`v$ˋ.ʵ֚k>)CZev:&4~$7?56i椹?ut.ڠy|ۢk sj sjC2)Zvb3`#A(kmy b6:j sj sjúG6c61aA1,~4;kZWf~q~(~8vTOi+W\ו:r\G(:jPGX)$иJh'|`N ~0`N ~0`N ~h^(5͖j IRxKf>&55 M Y,˖{kY,YJTG J εsJrrY8KY53-~!i&P:A]g"hq$iu.@41 uw]^ضC$z' `&9ϳ+ O/$iΔ 8,4gn/hL8skt_ty M (d/^9QmW`޺_kٕ.aآ~O\Q'/?yi͘8Gw}~ӮƝv]@0E)&SM׀ֶcM l䱦`mXQc >s4XۢsjZ&55mǚٶcmB 6j- h|[`N Ak䱦`mXSC06yMſl h6K)>qLmQ5~R95~R95~RCZ2)Zb04"֖A*n?Oj0?Oj0?OjH[hyf5F&˳=Κyʹν]~4SZU+u庎ב:J'7T/:V4Ivt?4K$25SL'5SL'5SL'55/fK5͒5P>&[2>TȲeY[˲dR1gB҂s$%%ܺn}e=R|eMsL˽_g"h i~dYO4"hs$ksyTB뷬-mҬISvGgݠ}œ1-yQ;: Iҗ]k5+|RS+d~Z4~g]uMy_7aGeZ|Ś0fzY|u_ cƪ%I/#hB4iT->Ok4{`sՄsu룿+-Kӡ1?c5ՏQg]wS<ѣ:k'>͍u E_xy>s_]~o .g\Wp^24]{abc4"hV!>O`B?`B?`B?N,[e,K,ys.T+-8KRRR*ϭ+ɹfW/eW47ϴxv&@Mvx A)&SM3|Yxl>&SMO4 osRUzo̱"hVq*]`W$0R{cm"hƒ~`ҷXRF޸=e XJIU#rJJQq"hK+{7={]I 2}Ԩ8qo,K;;ueYV4`lm݄M8qum ܐtQ@OllY:u+H~TB!>'@pR(֝mٲ,;6f"hRڳ,,gھUӖXwB=]1GUSQ&m +GxJ{^˲e~_[1w)ư$MMepbInz[#[%9lr%źu/ryYL<^}[1m˖%[vt]QMX\K\wf)ٲ,#ubem yջ?_Vވ}6k MXzbfZ7#ڲӡް)WJno̴zo[0ٞ v[}a2o̻,Q$Ml߅67lirenz/]hL$hV;9:7tLv5A@Votջ#a{fK"xGZkeo]i"c6]Yn֧5z?DMݪ~wZ$̶c` 9w>f"h.+g6=I {Vƕ|lfYU {WLt.{CEξ cW&?~]e Ajlߕ6s w9NB|ObVfݺ֟cCzVDЬJɦ7aj*}V-fUځ?^j*4|t`!hOƔHTmT4\[J&b%{*]􉄺bJ6V \Ugl9d7(.v QGV#CfF"PGeRM庮:{)ƥNR=井]rۗʕ%K ($͜0OgyZ[jܤ~L/<5մ;-7P[Fk8:W}Ek6oSKw>{|'{{ʻO˶ldit.#ݭ3>!^s\bm]vWu.GCҷgK/{G}ۦUVԢ?n|*=Q2e @|4{|I-O\G=Cm>WW={ִucut>ɲxV=^mjӨf1x}bK]b'c3i>{wzw|Y4am>bf9[nҁ|/d }{:YXr]e:hT}{ =fӏ7M.ܖ 5{~3yZ/rM5A3ݾ%o?Ko;C-g-W_ ϒ$=AIHox =~mճjsz9 Y{Q~vI=IsҌqsU~{iu^zs+Z|w޳աs=Laf5krr\Gc黟z{ղav%I=[4qTq'-5yt-y8I쩦1jzoڶ-]7ԏӶՑ9r <^P 9f0)Ǘru)I{L?PzSzW Jtn*SU*遗oUCQW:|"I=Vc/It?8[Ox@6m['Iu!_V=wֿfX~\I҃/ߪGݭ։1#hWirj[Wy/gǧݬ3%IzN_JJb7eO]_h钤Ξv4v>Ӻ]{^NyVzmkf-BI}ϴouyKf{T$i?__ӨofN'uu$W?_&޳>_Uz\>S:dѲ-[m|Kbz剼Gu h%Kj>jۏwӧO_sli{c.S$Q}M,^̝tДO{uu a-Ը>ڨ2-c~F5kkɈvm.1H&l%̭fdVFtF"޸Ijm__9zN4cIƭk%<sM=Mֶ6i{O3'̓:r]ɶl}dgܟ0j_鯯ޥ'W<>-[98hmԷAfo;~I"w,c$T1 CȔһX,a{~{N]Mbe9$ˇS3;LI3i]V̖ohe +X۷t܏ݨyҀ.{lw?$һν:|oZ4R],g|Hpuu=OkՅ',.[M0XeW̳MG=kil_ڳ4y~$b[vxN]^s졣\#%I:h&fz|Ze=C~'kGiu_A|Tv[7Mnd*ѷ'_(^3Nwt-_Ԭ'ޥDү%I[MTϼv&{ז:fu3m0A vWWz&Rrzݪ oL￟{4\ٷ7Wuo7]ֿ.B7?y|v57י(0m$'kGOӧg#dY|6" i\$Նk%IPX[Ʒ5{}/?,l]pUڪgT7F3k ڶw_Ԥ1;3ޡѕ;,~4;kZWf~q~(~8vTOivmoKWԏ54s P6Ok/R28#guzԗD*+>WIy!п,BdrLOhr' J εsJrrY8KY53-~!M@Ba)Q"=#:hΨ'ꡐ?#}?Fz#Aha;Rr5[CIWzo geYJ ۑ_P54H%H#X2L&Ԍ6̀c'*󱎀򳭐"HF1F"h\ఎD#.l7#oU{ ܾ^.`jyR Z :41H]E.҄j#u.1jk> =#@C_, a5D*]0DB51! Gٚ d'̏dw`!5ՍQO[dL)'Y᫘pÒ W"߃}Rp;ޓ_5MW j01j#u 57t F?R]Q]J2,uF4 `HL|O8 &WgujLp=Skc4#R}QP6>X2(ڂ&[CicOX1e*IAP,RCmuͰVC(Y dL2)hz%wpmjmnPDe[A #Jlb_B˲X;Dõj͖L2=3G KK~B̾f& K4\H(xXEj GUWSu2`dq ܯJAL'l+hjQĻt#S$TK{T}̨Ơ9@ɉC (RWD*XGTlD#LQ.Tc'_]n%$?$P"9nJd\d|[9vDpj5" ֛=<6[Յ|^:2rg盞{ߕʲ&cb[!FTJ: RIܔ'%uNߟKeٲ-[R ) +lG8,VoH.K4@ŋdi:bᰔYiª84CdYVߖN,qR+T<ĹtYhE#4:Rig_*4n<{)('+$ul|^;*Uco2YH_hzs7ͪ0eK?w xr R2VVǹ_vm+.n_DdXa)v߳ߓT@N֗RX1bb jIDATP[ bi+Ǯ.V-dR(m]{d*2Hn,6?ߖvkli='uc} aIiƷߜo,Syn/%V\9 v`O[l?jW\fm>۸mOC5O`,;27n[c~0> *|2_ yʺf,(gy r- YŮlU3&SqkfP{ g.k2疤\G%*O Fd )6bj:Y-n\M|X'YaBgޒb؉PR||2_x8KWlH;~drQUDž0K]Osnq )8Sy8ra3!hfRYo,<32Me=?U3쭙o)ukRv3 wJ۪< sF]f/4}ԭm 23403 /uYB&`Bf|gͷ4n›([ 5a4^n(l:YwE3ʚVl,@eEؼ|B֪ȴe>ԾT|kdN,&wf|Ӳäe?/{@yJ og/`5dRAf;` 'ߥPTJ6KP`vM-4?v}M񝹷v-t >9¤Bgq@6=}mn{Fɭ P` O~Nhe!д|,ň ^W(m)aش|FQhKac(seikRAs+l2o'dJl䊅v-e^UL̠|/f F I`]m̞7 CyURfB\`bgx =w- kM /.B$Repv͝6P,6I9i3 JvX//Zj,ȼlŮICP+%ӯJr|=Vb'!hUbo@:E=VK,RC+6}0`u(pR(f͡]J*H>Nj(\l0?ŦS]l+r Ş3Ŧ~ ^7Y!S2#(ypgn,T&=t^eJ5eWUȔ ; Ş7ЮC ) `J ^S|2%sP̵-`>;X90xJ= lz2:ϘzSpn?0 8k`SjcZP#l'1s\aRc&02xs t 73pA0߁yzϙ*8h1j03!Pq0r 7@zymO#UK"^=@0 ?C}N)Ru&/k̲\fL+s\VTc0T^*y vQws#VUȔ?\j)W@G0NGڐ)+@ݗ |U03*ݧJ`**ݾoT+`j mTkFB }P]03FRI}`@̌FjoDl#=p(03Z1kĆl"\ PqAj; C@X*I0ZOvIENDB`drum-machine-2.2.0/drum-machine.doap000066400000000000000000000024251514070543000173040ustar00rootroot00000000000000 Drum Machine Create and play drum beats Drum Machine is a modern application for creating, playing, and managing drum patterns. Perfect for musicians, producers, and anyone interested in rhythm creation, this application provides a simple interface for drum pattern programming. 2024-11-27 Python GTK 4 Libadwaita Revisto revisto drum-machine-2.2.0/io.github.revisto.drum-machine.json000066400000000000000000000024061514070543000227120ustar00rootroot00000000000000{ "id" : "io.github.revisto.drum-machine", "runtime" : "org.gnome.Platform", "runtime-version" : "48", "sdk" : "org.gnome.Sdk", "command" : "drum-machine", "finish-args" : [ "--share=ipc", "--socket=fallback-x11", "--device=dri", "--socket=wayland", "--socket=pulseaudio" ], "cleanup" : [ "/include", "/lib/pkgconfig", "/man", "/share/doc", "/share/gtk-doc", "/share/man", "/share/pkgconfig", "*.la", "*.a" ], "modules" : [ "python-dependencies.json", { "name": "blueprint-compiler", "buildsystem": "meson", "cleanup": ["*"], "sources": [ { "type": "git", "url": "https://gitlab.gnome.org/GNOME/blueprint-compiler", "tag": "0.18.0" } ] }, { "name" : "drum-machine", "builddir" : true, "buildsystem" : "meson", "sources" : [ { "type" : "git", "url" : "https://github.com/revisto/drum-machine.git" } ] } ] } drum-machine-2.2.0/meson.build000066400000000000000000000005471514070543000162330ustar00rootroot00000000000000project('drum-machine', version: '2.2.0', meson_version: '>= 0.62.0', default_options: [ 'warning_level=2', 'werror=false', ], ) i18n = import('i18n') gnome = import('gnome') subdir('data') subdir('src') subdir('po') gnome.post_install( glib_compile_schemas: true, gtk_update_icon_cache: true, update_desktop_database: true, ) drum-machine-2.2.0/po/000077500000000000000000000000001514070543000145015ustar00rootroot00000000000000drum-machine-2.2.0/po/LINGUAS000066400000000000000000000001161514070543000155240ustar00rootroot00000000000000bg ca de el en_GB es eu fa fi fr he hu it ka nl pt_BR ru sl sv tr uk uz zh_CN drum-machine-2.2.0/po/POTFILES.in000066400000000000000000000010671514070543000162620ustar00rootroot00000000000000data/io.github.revisto.drum-machine.desktop.in data/io.github.revisto.drum-machine.metainfo.xml.in data/io.github.revisto.drum-machine.gschema.xml src/application.py src/config/export_formats.py src/dialogs/audio_export_dialog.py src/dialogs/midi_mapping_dialog.py src/handlers/drag_drop_handler.py src/handlers/file_dialog_handler.py src/utils/export_progress.py src/utils/name_utils.py src/ui/drum_grid_builder.py src/window.py src/window.ui src/gtk/help-overlay.blp src/gtk/save-changes-dialog.blp src/gtk/audio-export-dialog.blp src/gtk/reset-defaults-dialog.blp drum-machine-2.2.0/po/bg.po000066400000000000000000000352651514070543000154440ustar00rootroot00000000000000# Bulgarian translation of boatswain po-file. # Copyright (C) 2025 twlvnn kraftwerk , 2025. msgid "" msgstr "" "Project-Id-Version: drum-machine master\n" "Report-Msgid-Bugs-To: https://github.com/revisto/drum-machine/issues\n" "POT-Creation-Date: 2025-10-25 03:26+0000\n" "PO-Revision-Date: 2025-10-25 14:50+0200\n" "Last-Translator: twlvnn kraftwerk \n" "Language-Team: Bulgarian \n" "Language: bg\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Poedit 3.8\n" #: data/io.github.revisto.drum-machine.desktop.in:2 #: data/io.github.revisto.drum-machine.metainfo.xml.in:6 src/window.ui:69 msgid "Drum Machine" msgstr "Барабанна машина" #. Translators: Search terms to find this application. Do NOT translate or localise the semicolons! The list MUST also end with a semicolon! #: data/io.github.revisto.drum-machine.desktop.in:9 msgid "drum;drums;sequencer;rhythm;music;pattern;beats;percussion;loop;groove;" msgstr "барабан;барабани;секвенсер;ритъм;музика;шаблон;удар;удара;повтаряне;жлеб;" #: data/io.github.revisto.drum-machine.metainfo.xml.in:7 msgid "Create and play drum beats" msgstr "Създаване и възпроизвеждане на барабанни ритми" #: data/io.github.revisto.drum-machine.metainfo.xml.in:9 msgid "" "Drum Machine is a modern and intuitive application for creating, playing, " "and managing drum patterns. Perfect for musicians, producers, and anyone " "interested in rhythm creation, this application provides a simple interface " "for drum pattern programming. Have fun!" msgstr "" "„Барабанна машина“ е модерна и проста програма за създаване, възпроизвеждане " "и управляване на барабанни шаблони. Тази програма е идеална за музиканти, " "продуценти и всички, които се интересуват от създаване на ритми, и " "предоставя прост интерфейс за програмиране на барабанни шаблони. " "Забавлявайте се!" #: data/io.github.revisto.drum-machine.metainfo.xml.in:15 msgid "Features:" msgstr "Функции:" #: data/io.github.revisto.drum-machine.metainfo.xml.in:17 msgid "Intuitive grid-based pattern editor" msgstr "Прост мрежов редактор на барабанни шаблони" #: data/io.github.revisto.drum-machine.metainfo.xml.in:18 msgid "Adjustable BPM control" msgstr "Настройване на ударите в минута" #: data/io.github.revisto.drum-machine.metainfo.xml.in:19 msgid "Volume control for overall mix" msgstr "Настройване на общата сила на звука" #: data/io.github.revisto.drum-machine.metainfo.xml.in:20 msgid "Save and load preset patterns" msgstr "Запазване и зареждане на шаблони на барабаните" #: data/io.github.revisto.drum-machine.metainfo.xml.in:21 msgid "Multiple drum sounds including kick, snare, hi-hat, and more" msgstr "Множество барабанни звуци — голям барабан, малък барабан, фус и други" #: data/io.github.revisto.drum-machine.metainfo.xml.in:22 msgid "Audio export feature with support for WAV, FLAC, Ogg, and MP3 formats" msgstr "" "Функция за изнасяне на аудио с поддръжка на формати WAV, FLAC, Ogg и MP3" #: data/io.github.revisto.drum-machine.metainfo.xml.in:23 msgid "Metadata support for embedding artist name, song title, and cover art" msgstr "" "Поддръжка на метаданни за влагане на името на изпълнителя, заглавието на " "песента и корицата" #: data/io.github.revisto.drum-machine.metainfo.xml.in:24 msgid "Keyboard shortcuts for quick access to all functions" msgstr "Клавишни комбинации за бърз достъп до всички функции" #: data/io.github.revisto.drum-machine.metainfo.xml.in:33 msgid "Drum Pattern Loaded in Light Mode" msgstr "Светъл режим на барабанния шаблон" #: data/io.github.revisto.drum-machine.metainfo.xml.in:37 msgid "Drum Pattern Loaded in Dark Mode" msgstr "Светъл режим на барабанния шаблон" #: src/application.py:69 msgid "translator-credits" msgstr "" "twlvnn kraftwerk , 2025\n" "\n" "Проектът за превод на GNOME има нужда от подкрепа.\n" "Научете повече за нас на
уеб сайта ни.\n" "Докладвайте за грешки в превода в съответния раздел." #: src/config/export_formats.py:43 msgid "MP3 files" msgstr "MP3 файлове" #: src/config/export_formats.py:44 msgid "MP3" msgstr "MP3" #: src/config/export_formats.py:50 msgid "FLAC files" msgstr "FLAC файлове" #: src/config/export_formats.py:51 msgid "FLAC (Lossless)" msgstr "FLAC (без загуба)" #: src/config/export_formats.py:57 msgid "Ogg files" msgstr "Ogg файлове" #: src/config/export_formats.py:58 msgid "Ogg Vorbis" msgstr "Ogg Vorbis" #: src/config/export_formats.py:64 msgid "WAV files" msgstr "WAV файлове" #: src/config/export_formats.py:65 msgid "WAV (Uncompressed)" msgstr "WAV (некомпресиран)" #: src/dialogs/audio_export_dialog.py:115 msgid "Save Audio File" msgstr "Запазване на звуковия файл" #: src/dialogs/audio_export_dialog.py:139 msgid "Image files" msgstr "Изображения" #: src/dialogs/audio_export_dialog.py:145 msgid "Select Cover Art" msgstr "Избор на корица" #: src/dialogs/audio_export_dialog.py:202 msgid "Audio exported to {}" msgstr "Аудиото е изнесено на {}" #: src/dialogs/audio_export_dialog.py:207 msgid "Export failed" msgstr "Изнасянето е неуспешно" #: src/dialogs/audio_export_dialog.py:214 msgid "Export cancelled successfully" msgstr "Изнасянето е прекратено" #: src/handlers/file_dialog_handler.py:51 msgid "Default Presets" msgstr "Стандартни шаблони" #: src/handlers/file_dialog_handler.py:83 msgid "No Pattern" msgstr "Няма шаблон" #: src/handlers/file_dialog_handler.py:84 msgid "Please create a drum pattern before exporting audio." msgstr "Създайте барабанен шаблон преди да изнасяте аудиото." #: src/handlers/file_dialog_handler.py:86 msgid "_OK" msgstr "_Добре" #: src/handlers/file_dialog_handler.py:109 #: src/handlers/file_dialog_handler.py:177 msgid "MIDI files" msgstr "MIDI файлове" #: src/handlers/file_dialog_handler.py:115 msgid "Open MIDI File" msgstr "Отваряне на MIDI файл" #: src/handlers/file_dialog_handler.py:185 msgid "Save Sequence" msgstr "Запазване на секвенцията" #: src/utils/export_progress.py:68 msgid "Preparing..." msgstr "Подготвяне…" #: src/utils/export_progress.py:69 msgid "Initializing..." msgstr "Стартиране…" #: src/utils/export_progress.py:71 msgid "Rendering audio..." msgstr "Рендиране на звука..." #: src/utils/export_progress.py:72 msgid "Processing beats..." msgstr "Обработване на ударите..." #: src/utils/export_progress.py:74 msgid "Saving file..." msgstr "Запазване на файла..." #: src/utils/export_progress.py:75 msgid "Writing to disk..." msgstr "Записване на диска..." #: src/utils/export_progress.py:77 msgid "Exporting..." msgstr "Изнасяне..." #: src/utils/export_progress.py:78 msgid "Processing..." msgstr "Обработване..." #. Update tooltip and accessibility with current BPM #: src/window.py:198 msgid "{} Beats per Minute (BPM)" msgstr "{} удара в минута" #. Update button tooltip to show current volume level #: src/window.py:207 msgid "{:.0f}% Volume" msgstr "{:.0f}% сила на звука" #: src/window.py:222 src/window.ui:170 msgid "Play" msgstr "Пускане" #: src/window.py:226 msgid "Pause" msgstr "Пауза" #: src/window.py:264 src/window.ui:52 msgid "Open" msgstr "Отваряне" #: src/window.ui:54 msgid "Open Preset" msgstr "Отваряне на шаблон" #: src/window.ui:57 msgctxt "accessibility" msgid "Open Preset" msgstr "Отваряне на шаблон" #: src/window.ui:58 msgid "Open Saved Drum Pattern Preset" msgstr "Отваряне на запазен барабанен шаблон" #: src/window.ui:76 msgid "Main Menu" msgstr "Основно меню" #: src/window.ui:78 msgctxt "accessibility" msgid "Main Menu" msgstr "Основно меню" #: src/window.ui:79 msgid "Access Keyboard Shortcuts and Application Information" msgstr "Достъп до клавишни комбинации и информация за програмата" #: src/window.ui:86 src/gtk/audio-export-dialog.blp:6 #: src/gtk/audio-export-dialog.blp:96 msgid "Export Audio" msgstr "Изнасяне на аудиото" #: src/window.ui:88 msgctxt "accessibility" msgid "Export Audio" msgstr "Изнасяне на аудиото" #: src/window.ui:89 msgid "Export Current Drum Pattern as Audio File" msgstr "Запазване на текущите барабани като звуков файл" #: src/window.ui:134 msgid "BPM" msgstr "Удара/мин." #: src/window.ui:139 src/window.ui:143 msgid "Adjust Tempo In Beats per Minute (BPM)" msgstr "Нагласяне на темпото в удари в минута" #: src/window.ui:142 msgid "Tempo" msgstr "Темпо" #: src/window.ui:184 msgid "Adjust Volume" msgstr "Нагласяне на силата на звука" #: src/window.ui:207 msgid "Reset" msgstr "Нулиране" #: src/window.ui:208 msgid "Reset the Drum Sequence" msgstr "Връщане на барабанната секвенция" #: src/window.ui:223 msgid "_Save Pattern" msgstr "_Запазване на шаблона" #: src/window.ui:229 msgid "_Keyboard Shortcuts" msgstr "_Клавишни комбинации" #: src/window.ui:233 msgid "_About Drum Machine" msgstr "_Относно „Барабанна машина“" #: src/gtk/help-overlay.blp:11 msgctxt "shortcut window" msgid "General" msgstr "Общи" #: src/gtk/help-overlay.blp:14 msgctxt "shortcut window" msgid "Show Shortcuts" msgstr "Показване на клавишните комбинации" #: src/gtk/help-overlay.blp:19 msgctxt "shortcut window" msgid "Quit" msgstr "Спиране на програмата" #: src/gtk/help-overlay.blp:26 msgctxt "shortcut window" msgid "Playback Controls" msgstr "Контроли на възпроизвеждане" #: src/gtk/help-overlay.blp:29 msgctxt "shortcut window" msgid "Play/Pause" msgstr "Изпълнение/пауза" #: src/gtk/help-overlay.blp:35 msgctxt "shortcut window" msgid "Clear All" msgstr "Изчистване на всичко" #: src/gtk/help-overlay.blp:42 msgctxt "shortcut window" msgid "BPM & Volume Controls" msgstr "Удари/мин. и контроли за звука" #: src/gtk/help-overlay.blp:45 msgctxt "shortcut window" msgid "Increase BPM" msgstr "Ускоряване на ударите/мин." #: src/gtk/help-overlay.blp:51 msgctxt "shortcut window" msgid "Decrease BPM" msgstr "Забавяне на ударите/мин." #: src/gtk/help-overlay.blp:57 msgctxt "shortcut window" msgid "Increase Volume" msgstr "Увеличаване на звука" #: src/gtk/help-overlay.blp:63 msgctxt "shortcut window" msgid "Decrease Volume" msgstr "Намаляване на звука" #: src/gtk/help-overlay.blp:69 msgctxt "shortcut window" msgid "Mute" msgstr "Заглушаване" #: src/gtk/help-overlay.blp:76 msgctxt "shortcut window" msgid "Preset Management" msgstr "Управление на шаблони" #: src/gtk/help-overlay.blp:79 msgctxt "shortcut window" msgid "Load Preset" msgstr "Зареждане на шаблон" #: src/gtk/help-overlay.blp:85 msgctxt "shortcut window" msgid "Save Preset" msgstr "Запазване на шаблон" #: src/gtk/help-overlay.blp:91 msgctxt "shortcut window" msgid "Export Audio" msgstr "Изнасяне на аудиото" #: src/gtk/help-overlay.blp:98 msgctxt "shortcut window" msgid "Navigation" msgstr "Навигация" #: src/gtk/help-overlay.blp:101 msgctxt "shortcut window" msgid "Go to Instrument" msgstr "Към инструмент" #: src/gtk/help-overlay.blp:107 msgctxt "shortcut window" msgid "Previous Page" msgstr "Предишна страница" #: src/gtk/help-overlay.blp:113 msgctxt "shortcut window" msgid "Next Page" msgstr "Следваща страница" #: src/gtk/save-changes-dialog.blp:5 msgid "Save Changes?" msgstr "Да се запазят ли промените?" #: src/gtk/save-changes-dialog.blp:6 msgid "" "Current preset contains unsaved changes. Changes which are not saved will be " "permanently lost." msgstr "" "Текущият барабанен шаблон съдържа промени. Ако не ги запазите, те ще бъдат " "загубени окончателно." #. Translators: Cancel the operation #: src/gtk/save-changes-dialog.blp:14 msgid "_Cancel" msgstr "_Отказване" #. Translators: Discard all changes #: src/gtk/save-changes-dialog.blp:15 msgid "_Discard" msgstr "_Отхвърляне" #. Translators: Save current changes #: src/gtk/save-changes-dialog.blp:16 msgid "_Save" msgstr "_Запазване" #: src/gtk/audio-export-dialog.blp:39 msgid "Audio Format" msgstr "Звуков формат" #: src/gtk/audio-export-dialog.blp:45 msgid "Repeat Count" msgstr "Брой повторения" #: src/gtk/audio-export-dialog.blp:46 msgid "How many times to repeat the pattern" msgstr "Колко пъти да се повтори шаблона" #: src/gtk/audio-export-dialog.blp:59 msgid "Metadata" msgstr "Метаданни" #: src/gtk/audio-export-dialog.blp:62 msgid "Artist Name" msgstr "Име на изпълнителя" #: src/gtk/audio-export-dialog.blp:67 msgid "Song Name" msgstr "Име на песента" #: src/gtk/audio-export-dialog.blp:72 msgid "Cover Art" msgstr "Корица" #: src/gtk/audio-export-dialog.blp:76 msgid "Choose File" msgstr "Избор на файл" #: src/gtk/audio-export-dialog.blp:105 msgid "Cancel Export" msgstr "Прекратяване на изнасянето" drum-machine-2.2.0/po/ca.po000066400000000000000000000501231514070543000154250ustar00rootroot00000000000000# Catalan translation for drum-machine. # Copyright (C) 2025 drum-machine's COPYRIGHT HOLDER # This file is distributed under the same license as the drum-machine package. # Victor Dargallo , 2025. # msgid "" msgstr "" "Project-Id-Version: drum-machine master\n" "Report-Msgid-Bugs-To: https://github.com/revisto/drum-machine/issues\n" "POT-Creation-Date: 2025-11-27 15:26+0000\n" "PO-Revision-Date: 2025-11-27 19:47+0100\n" "Last-Translator: \n" "Language-Team: Catalan \n" "Language: ca\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Poedit 3.6\n" #: data/io.github.revisto.drum-machine.desktop.in:2 #: data/io.github.revisto.drum-machine.metainfo.xml.in:6 src/application.py:67 #: src/window.ui:69 msgid "Drum Machine" msgstr "Caixa de ritmes" #. Translators: Search terms to find this application. Do NOT translate or localise the semicolons! The list MUST also end with a semicolon! #: data/io.github.revisto.drum-machine.desktop.in:9 msgid "drum;drums;sequencer;rhythm;music;pattern;beats;percussion;loop;groove;" msgstr "tambor;bateria;seqüenciador;ritme;música;patró;beats;percussió;bucle;groove;" #: data/io.github.revisto.drum-machine.metainfo.xml.in:7 msgid "Create and play drum beats" msgstr "Creeu i reproduïu ritmes de bateria" #: data/io.github.revisto.drum-machine.metainfo.xml.in:9 msgid "" "Drum Machine is a modern and intuitive application for creating, playing, " "and managing drum patterns. Perfect for musicians, producers, and anyone " "interested in rhythm creation, this application provides a simple interface " "for drum pattern programming. Have fun!" msgstr "" "La Caixa de ritmes és una aplicació moderna i intuïtiva per crear, reproduir " "i gestionar patrons de bateria. Perfecte per a músics, productors i " "qualsevol persona interessada en la creació de ritmes, aquesta aplicació " "proporciona una interfície senzilla per a la creació de patrons de bateria. " "Divertiu-vos!" #: data/io.github.revisto.drum-machine.metainfo.xml.in:15 msgid "Features:" msgstr "Característiques:" #: data/io.github.revisto.drum-machine.metainfo.xml.in:17 msgid "Intuitive grid-based pattern editor" msgstr "Editor de patrons intuïtiu basat en quadrícula" #: data/io.github.revisto.drum-machine.metainfo.xml.in:18 msgid "Adjustable BPM control" msgstr "Control de PPM ajustable" #: data/io.github.revisto.drum-machine.metainfo.xml.in:19 msgid "Volume control for overall mix" msgstr "Control de volum per a la mescla global" #: data/io.github.revisto.drum-machine.metainfo.xml.in:20 msgid "Save and load patterns" msgstr "Desa i carrega els patrons" #: data/io.github.revisto.drum-machine.metainfo.xml.in:21 msgid "Multiple drum sounds including kick, snare, hi-hat, and more" msgstr "Múltiples sons de tambor, incloent-hi kick, snare, hi-hat, i més" #: data/io.github.revisto.drum-machine.metainfo.xml.in:22 msgid "Audio export feature with support for WAV, FLAC, Ogg, and MP3 formats" msgstr "" "Funció d'exportació d'àudio amb suport per als formats WAV, FLAC, Ogg i MP3" #: data/io.github.revisto.drum-machine.metainfo.xml.in:23 msgid "Metadata support for embedding artist name, song title, and cover art" msgstr "" "Implementació de metadades per incrustar el nom de l'artista, el títol de la " "cançó i la portada" #: data/io.github.revisto.drum-machine.metainfo.xml.in:24 msgid "Keyboard shortcuts for quick access to all functions" msgstr "Dreceres de teclat per a un accés ràpid a totes les funcions" #: data/io.github.revisto.drum-machine.metainfo.xml.in:33 msgid "Drum Pattern Loaded in Light Mode" msgstr "Patró de bateria carregat en mode clar" #: data/io.github.revisto.drum-machine.metainfo.xml.in:37 msgid "Drum Pattern Loaded in Dark Mode" msgstr "Patró de bateria carregat en mode fosc" #: src/application.py:74 msgid "" "Drum Machine is a modern and intuitive application for creating, playing, " "and managing drum patterns." msgstr "" "La Caixa de ritmes és una aplicació moderna i intuïtiva per crear, reproduir " "i gestionar patrons de bateria." #: src/application.py:79 msgid "translator-credits" msgstr "Victor Dargallo " #: src/application.py:84 msgid "Special thanks" msgstr "Agraïments especials" #: src/application.py:87 msgid "Sounds" msgstr "Sons" #: src/application.py:88 #, python-brace-format msgid "The drum samples used in this application are from {link}." msgstr "Les mostres de bateria utilitzades en aquesta aplicació són de {link}." #: src/config/export_formats.py:44 msgid "MP3 files" msgstr "Fitxers MP3" #: src/config/export_formats.py:45 msgid "MP3" msgstr "MP3" #: src/config/export_formats.py:51 msgid "FLAC files" msgstr "Fitxers FLAC" #: src/config/export_formats.py:52 msgid "FLAC (Lossless)" msgstr "FLAC (sense pèrdua)" #: src/config/export_formats.py:58 msgid "Ogg files" msgstr "Fitxers Ogg" #: src/config/export_formats.py:59 msgid "Ogg Vorbis" msgstr "Ogg Vorbis" #: src/config/export_formats.py:65 msgid "WAV files" msgstr "Fitxers WAV" #: src/config/export_formats.py:66 msgid "WAV (Uncompressed)" msgstr "WAV (sense compressió)" #: src/dialogs/audio_export_dialog.py:119 msgid "Save Audio File" msgstr "Desa el fitxer d'àudio" #: src/dialogs/audio_export_dialog.py:148 msgid "Part “{}” is Silent" msgstr "La part «{}» és silenciosa" #: src/dialogs/audio_export_dialog.py:150 msgid "Parts “{}” and “{}” are Silent" msgstr "Les parts «{}» i «{}» són silencioses" #: src/dialogs/audio_export_dialog.py:154 msgid "{} Parts are Silent" msgstr "{} Parts són silencioses" #: src/dialogs/audio_export_dialog.py:179 msgid "Image files" msgstr "Fitxers d'imatge" #: src/dialogs/audio_export_dialog.py:185 msgid "Select Cover Art" msgstr "Selecciona la portada" #: src/dialogs/audio_export_dialog.py:245 msgid "Audio exported to {}" msgstr "S'ha exportat l'àudio a {}" #: src/dialogs/audio_export_dialog.py:251 msgid "Export failed" msgstr "Ha fallat l'exportació" #: src/dialogs/audio_export_dialog.py:258 msgid "Export cancelled successfully" msgstr "L'exportació s'ha cancel·lat correctament" #: src/dialogs/midi_mapping_dialog.py:22 msgid "Acoustic Bass Drum" msgstr "Bombo acústic" #: src/dialogs/midi_mapping_dialog.py:23 msgid "Bass Drum 1" msgstr "Bombo 1" #: src/dialogs/midi_mapping_dialog.py:24 msgid "Side Stick" msgstr "" #: src/dialogs/midi_mapping_dialog.py:25 msgid "Acoustic Snare" msgstr "Caixa acústica" #: src/dialogs/midi_mapping_dialog.py:26 msgid "Hand Clap" msgstr "Aplaudiment" #: src/dialogs/midi_mapping_dialog.py:27 msgid "Electric Snare" msgstr "Caixa elèctrica" #: src/dialogs/midi_mapping_dialog.py:28 msgid "Low Floor Tom" msgstr "" #: src/dialogs/midi_mapping_dialog.py:29 msgid "Closed Hi Hat" msgstr "Hi-hat tancat" #: src/dialogs/midi_mapping_dialog.py:30 msgid "High Floor Tom" msgstr "" #: src/dialogs/midi_mapping_dialog.py:31 msgid "Pedal Hi Hat" msgstr "Pedal del hi-hat" #: src/dialogs/midi_mapping_dialog.py:32 msgid "Low Tom" msgstr "" #: src/dialogs/midi_mapping_dialog.py:33 msgid "Open Hi Hat" msgstr "" #: src/dialogs/midi_mapping_dialog.py:34 msgid "Low-Mid Tom" msgstr "" #: src/dialogs/midi_mapping_dialog.py:35 msgid "Hi-Mid Tom" msgstr "" #: src/dialogs/midi_mapping_dialog.py:36 msgid "Crash Cymbal 1" msgstr "" #: src/dialogs/midi_mapping_dialog.py:37 msgid "High Tom" msgstr "" #: src/dialogs/midi_mapping_dialog.py:38 msgid "Ride Cymbal 1" msgstr "" #: src/dialogs/midi_mapping_dialog.py:39 msgid "Chinese Cymbal" msgstr "" #: src/dialogs/midi_mapping_dialog.py:40 msgid "Ride Bell" msgstr "" #: src/dialogs/midi_mapping_dialog.py:41 msgid "Tambourine" msgstr "Pandereta" #: src/dialogs/midi_mapping_dialog.py:42 msgid "Splash Cymbal" msgstr "" #: src/dialogs/midi_mapping_dialog.py:43 msgid "Cowbell" msgstr "Esquerra" #: src/dialogs/midi_mapping_dialog.py:44 msgid "Crash Cymbal 2" msgstr "" #: src/dialogs/midi_mapping_dialog.py:45 msgid "Vibraslap" msgstr "" #: src/dialogs/midi_mapping_dialog.py:46 msgid "Ride Cymbal 2" msgstr "" #: src/dialogs/midi_mapping_dialog.py:47 msgid "Hi Bongo" msgstr "Bongo alt" #: src/dialogs/midi_mapping_dialog.py:48 msgid "Low Bongo" msgstr "Bongo baix" #: src/dialogs/midi_mapping_dialog.py:49 msgid "Mute Hi Conga" msgstr "Conga alta muda" #: src/dialogs/midi_mapping_dialog.py:50 msgid "Open Hi Conga" msgstr "Conga alta oberta" #: src/dialogs/midi_mapping_dialog.py:51 msgid "Low Conga" msgstr "Conga baixa" #: src/dialogs/midi_mapping_dialog.py:52 msgid "High Timbale" msgstr "Timbal alt" #: src/dialogs/midi_mapping_dialog.py:53 msgid "Low Timbale" msgstr "Timbal baix" #: src/dialogs/midi_mapping_dialog.py:54 msgid "High Agogo" msgstr "Agogó alt" #: src/dialogs/midi_mapping_dialog.py:55 msgid "Low Agogo" msgstr "Agogó baix" #: src/dialogs/midi_mapping_dialog.py:56 msgid "Cabasa" msgstr "Cabassa" #: src/dialogs/midi_mapping_dialog.py:57 msgid "Maracas" msgstr "Maraques" #: src/dialogs/midi_mapping_dialog.py:58 msgid "Short Whistle" msgstr "" #: src/dialogs/midi_mapping_dialog.py:59 msgid "Long Whistle" msgstr "" #: src/dialogs/midi_mapping_dialog.py:60 msgid "Short Guiro" msgstr "" #: src/dialogs/midi_mapping_dialog.py:61 msgid "Long Guiro" msgstr "" #: src/dialogs/midi_mapping_dialog.py:62 msgid "Claves" msgstr "Bastons" #: src/dialogs/midi_mapping_dialog.py:63 msgid "Hi Wood Block" msgstr "" #: src/dialogs/midi_mapping_dialog.py:64 msgid "Low Wood Block" msgstr "" #: src/dialogs/midi_mapping_dialog.py:65 msgid "Mute Cuica" msgstr "" #: src/dialogs/midi_mapping_dialog.py:66 msgid "Open Cuica" msgstr "" #: src/dialogs/midi_mapping_dialog.py:67 msgid "Mute Triangle" msgstr "Triangle mut" #: src/dialogs/midi_mapping_dialog.py:68 msgid "Open Triangle" msgstr "Triangle obert" #: src/dialogs/midi_mapping_dialog.py:78 src/ui/drum_grid_builder.py:338 msgid "MIDI Mapping" msgstr "Assignació MIDI" #. Group 1: Note Assignment #: src/dialogs/midi_mapping_dialog.py:108 msgid "Note Assignment" msgstr "Assignació de notes" #: src/dialogs/midi_mapping_dialog.py:111 msgid "" "Assign a MIDI note for '{}'. This ensures correct playback when exporting." msgstr "" "Assigna una nota MIDI per a «{}». Això garanteix una reproducció correcta en " "exportar." #. Action Row for Note #: src/dialogs/midi_mapping_dialog.py:118 msgid "MIDI Note" msgstr "Nota MIDI" #: src/dialogs/midi_mapping_dialog.py:119 msgid "The note number to trigger" msgstr "El número de nota a activar" #. Group 2: Standard Instruments #: src/dialogs/midi_mapping_dialog.py:137 msgid "Standard Instruments" msgstr "Instruments estàndard" #: src/dialogs/midi_mapping_dialog.py:139 msgid "Select a General MIDI instrument to automatically set the note." msgstr "" "Seleccioneu un instrument MIDI General per definir la nota automàticament." #: src/dialogs/midi_mapping_dialog.py:143 msgid "Instrument Preset" msgstr "Instruments predefinits" #: src/dialogs/midi_mapping_dialog.py:186 msgid "Save" msgstr "Desa" #: src/dialogs/midi_mapping_dialog.py:229 msgid "Custom Note" msgstr "Nota personalitzada" #: src/handlers/drag_drop_handler.py:113 msgid "Sound replaced" msgstr "" #: src/handlers/drag_drop_handler.py:116 msgid "Failed to replace sound" msgstr "" #: src/handlers/drag_drop_handler.py:126 msgid "Not a supported audio file" msgstr "" #: src/handlers/drag_drop_handler.py:134 msgid "File not found" msgstr "No s'ha trobat el fitxer" #: src/handlers/drag_drop_handler.py:139 msgid "Selected item is not a file" msgstr "" #: src/handlers/drag_drop_handler.py:146 msgid "File too large: {:.1f}MB (max 50MB)" msgstr "" #: src/handlers/drag_drop_handler.py:174 msgid "No valid audio files found" msgstr "" #: src/handlers/drag_drop_handler.py:209 msgid "Error processing file: {}" msgstr "" #: src/handlers/drag_drop_handler.py:237 msgid "Added {} drum part, {} files skipped" msgstr "" #: src/handlers/drag_drop_handler.py:243 msgid "Added {} drum parts, {} files skipped" msgstr "" #: src/handlers/drag_drop_handler.py:248 msgid "Added {} drum parts" msgstr "" #. Only show skipped message if no replacement happened #: src/handlers/drag_drop_handler.py:251 msgid "{} files skipped" msgstr "" #: src/handlers/file_dialog_handler.py:52 msgid "Default Patterns" msgstr "Patrons predeterminats" #: src/handlers/file_dialog_handler.py:84 msgid "No Pattern" msgstr "Sense patró" #: src/handlers/file_dialog_handler.py:85 msgid "Please create a drum pattern before exporting audio." msgstr "" #: src/handlers/file_dialog_handler.py:87 msgid "_OK" msgstr "_D'acord" #: src/handlers/file_dialog_handler.py:110 #: src/handlers/file_dialog_handler.py:187 msgid "MIDI files" msgstr "Fitxers MIDI" #: src/handlers/file_dialog_handler.py:116 msgid "Open MIDI File" msgstr "" #: src/handlers/file_dialog_handler.py:144 msgid "Failed to open file" msgstr "" #: src/handlers/file_dialog_handler.py:181 msgid "Failed to load pattern" msgstr "" #: src/handlers/file_dialog_handler.py:195 msgid "Save Sequence" msgstr "" #: src/handlers/file_dialog_handler.py:221 msgid "Add Audio Samples" msgstr "" #: src/handlers/file_dialog_handler.py:243 msgid "Audio files" msgstr "Fitxers d'àudio" #: src/utils/export_progress.py:76 msgid "Preparing…" msgstr "" #: src/utils/export_progress.py:77 msgid "Initializing…" msgstr "" #: src/utils/export_progress.py:79 msgid "Rendering audio…" msgstr "" #: src/utils/export_progress.py:80 msgid "Processing beats…" msgstr "" #: src/utils/export_progress.py:82 msgid "Saving file…" msgstr "S'està desant el fitxer…" #: src/utils/export_progress.py:83 msgid "Writing to disk…" msgstr "" #: src/utils/export_progress.py:85 msgid "Exporting…" msgstr "S'està exportant…" #: src/utils/export_progress.py:86 msgid "Processing…" msgstr "S'està processant…" #: src/utils/name_utils.py:36 msgid "Custom Sound" msgstr "" #: src/ui/drum_grid_builder.py:323 msgid "Preview" msgstr "Previsualitza" #: src/ui/drum_grid_builder.py:325 msgid "Replace…" msgstr "" #: src/ui/drum_grid_builder.py:328 msgid "Replace with new sound" msgstr "" #: src/ui/drum_grid_builder.py:331 msgid "Remove" msgstr "Elimina" #: src/ui/drum_grid_builder.py:334 msgid "At least one drum part must remain" msgstr "" #: src/ui/drum_grid_builder.py:341 msgid "Configure MIDI note for export" msgstr "" #: src/ui/drum_grid_builder.py:398 msgid "MIDI note updated" msgstr "" #: src/ui/drum_grid_builder.py:406 msgid "Select New Sound" msgstr "" #: src/ui/drum_grid_builder.py:420 msgid "Removed drum part: {}" msgstr "" #: src/ui/drum_grid_builder.py:424 msgid "Failed to remove drum part" msgstr "No s'ha pogut eliminar la part del tambor" #. Update tooltip and accessibility with current BPM #: src/window.py:203 msgid "{} Beats per Minute (BPM)" msgstr "{} pulsacions per minut (PPM)" #. Update button tooltip to show current volume level #: src/window.py:212 msgid "{:.0f}% Volume" msgstr "{:.0f}% Volum" #: src/window.py:227 src/window.ui:170 msgid "Play" msgstr "Reprodueix" #: src/window.py:231 msgid "Pause" msgstr "Pausa" #: src/window.py:278 msgid "Open" msgstr "Obre" #: src/window.py:296 msgid "Added: {}" msgstr "" #: src/window.py:311 msgid "Failed to add custom sound" msgstr "" #: src/window.py:318 msgid "Replaced drum with: {}" msgstr "" #: src/window.py:326 msgid "Failed to replace drum sound" msgstr "" #: src/window.ui:52 msgid "Open…" msgstr "Obre…" #: src/window.ui:54 msgid "Open Pattern" msgstr "" #: src/window.ui:57 msgctxt "accessibility" msgid "Open Pattern" msgstr "Obre un patró" #: src/window.ui:58 msgid "Open Saved Drum Pattern" msgstr "" #: src/window.ui:76 msgid "Main Menu" msgstr "" #: src/window.ui:78 msgctxt "accessibility" msgid "Main Menu" msgstr "Menú principal" #: src/window.ui:79 msgid "Access Keyboard Shortcuts and Application Information" msgstr "" #: src/window.ui:86 msgid "Export Audio…" msgstr "" #: src/window.ui:88 msgctxt "accessibility" msgid "Export Audio…" msgstr "Exporta l'àudio…" #: src/window.ui:89 msgid "Export Current Drum Pattern as Audio File" msgstr "" #: src/window.ui:134 msgid "BPM" msgstr "PPM" #: src/window.ui:139 src/window.ui:143 msgid "Adjust Tempo In Beats per Minute (BPM)" msgstr "" #: src/window.ui:142 msgid "Tempo" msgstr "" #: src/window.ui:184 msgid "Adjust Volume" msgstr "" #: src/window.ui:207 msgid "Reset" msgstr "Restableix" #: src/window.ui:208 msgid "Reset the Drum Sequence" msgstr "" #: src/window.ui:223 msgid "_Add Samples…" msgstr "" #: src/window.ui:227 msgid "_Save Pattern…" msgstr "" #: src/window.ui:233 msgid "_Keyboard Shortcuts" msgstr "_Dreceres de teclat" #: src/window.ui:237 msgid "_About Drum Machine" msgstr "_Quant a la Caixa de ritmes" #: src/gtk/help-overlay.blp:11 msgctxt "shortcut window" msgid "General" msgstr "General" #: src/gtk/help-overlay.blp:14 msgctxt "shortcut window" msgid "Show Shortcuts" msgstr "Mostra les dreceres de teclat" #: src/gtk/help-overlay.blp:19 msgctxt "shortcut window" msgid "Quit" msgstr "Surt" #: src/gtk/help-overlay.blp:26 msgctxt "shortcut window" msgid "Playback Controls" msgstr "Controls de reproducció" #: src/gtk/help-overlay.blp:29 msgctxt "shortcut window" msgid "Play/Pause" msgstr "Reprodueix / Pausa" #: src/gtk/help-overlay.blp:35 msgctxt "shortcut window" msgid "Clear All" msgstr "Neteja" #: src/gtk/help-overlay.blp:42 msgctxt "shortcut window" msgid "BPM & Volume Controls" msgstr "PPM i controls de volum" #: src/gtk/help-overlay.blp:45 msgctxt "shortcut window" msgid "Increase BPM" msgstr "Augmenta les PPM" #: src/gtk/help-overlay.blp:51 msgctxt "shortcut window" msgid "Decrease BPM" msgstr "Disminueix les PPM" #: src/gtk/help-overlay.blp:57 msgctxt "shortcut window" msgid "Increase Volume" msgstr "Apuja el volum" #: src/gtk/help-overlay.blp:63 msgctxt "shortcut window" msgid "Decrease Volume" msgstr "Abaixa el volum" #: src/gtk/help-overlay.blp:69 msgctxt "shortcut window" msgid "Mute" msgstr "Silencia" #: src/gtk/help-overlay.blp:76 msgctxt "shortcut window" msgid "Pattern Management" msgstr "Gestió de patrons" #: src/gtk/help-overlay.blp:79 msgctxt "shortcut window" msgid "Load Pattern" msgstr "Carrega un patró" #: src/gtk/help-overlay.blp:85 msgctxt "shortcut window" msgid "Save Pattern" msgstr "Desa el patró" #: src/gtk/help-overlay.blp:91 msgctxt "shortcut window" msgid "Export Audio" msgstr "Exporta l'àudio" #: src/gtk/help-overlay.blp:98 msgctxt "shortcut window" msgid "Navigation" msgstr "Navegació" #: src/gtk/help-overlay.blp:101 msgctxt "shortcut window" msgid "Go to Instrument" msgstr "Ves a l'instrument" #: src/gtk/help-overlay.blp:107 msgctxt "shortcut window" msgid "Previous Page" msgstr "Pàgina anterior" #: src/gtk/help-overlay.blp:113 msgctxt "shortcut window" msgid "Next Page" msgstr "Pàgina següent" #: src/gtk/save-changes-dialog.blp:5 msgid "Save Changes?" msgstr "Voleu desar els canvis?" #: src/gtk/save-changes-dialog.blp:6 msgid "" "Current pattern contains unsaved changes. Changes which are not saved will " "be permanently lost." msgstr "" "El patró actual conté canvis sense desar. Els canvis que no es desin es " "perdran permanentment." #. Translators: Cancel the operation #: src/gtk/save-changes-dialog.blp:14 msgid "_Cancel" msgstr "_Cancel·la" #. Translators: Discard all changes #: src/gtk/save-changes-dialog.blp:15 msgid "_Discard" msgstr "_Descarta" #. Translators: Save current changes #: src/gtk/save-changes-dialog.blp:16 msgid "_Save" msgstr "De_sa" #: src/gtk/audio-export-dialog.blp:6 src/gtk/audio-export-dialog.blp:101 msgid "Export Audio" msgstr "Exporta l'àudio" #: src/gtk/audio-export-dialog.blp:44 msgid "Audio Format" msgstr "Format d'àudio" #: src/gtk/audio-export-dialog.blp:50 msgid "Repeat Count" msgstr "Nombre de repeticions" #: src/gtk/audio-export-dialog.blp:51 msgid "How many times to repeat the pattern" msgstr "Quantes vegades s'ha de repetir el patró" #: src/gtk/audio-export-dialog.blp:64 msgid "Metadata" msgstr "Metadades" #: src/gtk/audio-export-dialog.blp:67 msgid "Artist Name" msgstr "Nom de l'artista" #: src/gtk/audio-export-dialog.blp:72 msgid "Song Name" msgstr "Nom de la cançó" #: src/gtk/audio-export-dialog.blp:77 msgid "Cover Art" msgstr "Portada" #: src/gtk/audio-export-dialog.blp:81 msgid "Choose File…" msgstr "Tria un fitxer…" #: src/gtk/audio-export-dialog.blp:110 msgid "Cancel Export" msgstr "Cancel·la l'exportació" drum-machine-2.2.0/po/de.po000066400000000000000000000162601514070543000154360ustar00rootroot00000000000000# German translation for drum-machine. # Copyright (C) 2025 drum-machine's COPYRIGHT HOLDER # This file is distributed under the same license as the drum-machine package. # Manuel Rottschäfer , 2025. # Philipp Kiemle , 2025. # Jürgen Benvenuti , 2025. # msgid "" msgstr "" "Project-Id-Version: drum-machine master\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2025-03-26 13:12+0000\n" "PO-Revision-Date: 2025-03-27 18:59+0100\n" "Last-Translator: Jürgen Benvenuti \n" "Language-Team: German \n" "Language: de\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Poedit 3.4.4\n" #: data/io.github.revisto.drum-machine.desktop.in:3 #: data/io.github.revisto.drum-machine.metainfo.xml.in:6 src/window.ui:58 msgid "Drum Machine" msgstr "Drum Machine" #: data/io.github.revisto.drum-machine.metainfo.xml.in:7 msgid "Create and play drum beats" msgstr "Erstellen und Abspielen von Schlagzeugrhythmen" #: data/io.github.revisto.drum-machine.metainfo.xml.in:9 msgid "" "Drum Machine is a modern and intuitive application for creating, playing, " "and managing drum patterns. Perfect for musicians, producers, and anyone " "interested in rhythm creation, this application provides a simple interface " "for drum pattern programming. Have fun!" msgstr "" "Drum Machine ist eine moderne und intuitive Anwendung, die das Erstellen, " "Abspielen und Verwalten von Schlagzeugrhythmen ermöglicht. Sie eignet sich " "optimal für Musiker, Produzenten und alle, die sich für die Erstellung von " "Schlagzeugrhythmen interessieren. Drum Machine zeichnet sich durch eine " "simple Benutzeroberfläche aus. Viel Spaß!" #: data/io.github.revisto.drum-machine.metainfo.xml.in:15 msgid "Features:" msgstr "Funktionen:" #: data/io.github.revisto.drum-machine.metainfo.xml.in:17 msgid "Intuitive grid-based pattern editor" msgstr "Intuitiver, gitterbasierter Rhythmus-Editor" #: data/io.github.revisto.drum-machine.metainfo.xml.in:18 msgid "Adjustable BPM control" msgstr "Anpassbare BPM-Kontrolle" #: data/io.github.revisto.drum-machine.metainfo.xml.in:19 msgid "Volume control for overall mix" msgstr "Lautstärkeregelung für den allgemeinen Mix" #: data/io.github.revisto.drum-machine.metainfo.xml.in:20 msgid "Save and load preset patterns" msgstr "Speichern und Laden von Vorgaberhythmen" #: data/io.github.revisto.drum-machine.metainfo.xml.in:21 msgid "Multiple drum sounds including kick, snare, hi-hat, and more" msgstr "Verschiedene Drum-Klänge einschließlich Kick, Snare, Hi-Hat und mehr" #: data/io.github.revisto.drum-machine.metainfo.xml.in:22 msgid "Keyboard shortcuts for quick access to all functions" msgstr "Tastenkürzel für schnellen Zugriff auf alle Funktionen" #: data/io.github.revisto.drum-machine.metainfo.xml.in:31 msgid "Drum Pattern Loaded in Light Mode" msgstr "Schlagzeugrhythmus im hellen Thema geladen" #: data/io.github.revisto.drum-machine.metainfo.xml.in:35 msgid "Drum Pattern Loaded in Dark Mode" msgstr "Schlagzeugrhythmus im dunklen Thema geladen" #. Update tooltip and accessibility with current BPM #: src/window.py:278 msgid "{} Beats per Minute (BPM)" msgstr "{} Taktschläge pro Minute (BPM)" #. Update button tooltip to show current volume level #: src/window.py:287 msgid "{:.0f}% Volume" msgstr "{:.0f}% Lautstärke" #: src/window.py:298 src/window.ui:158 msgid "Play" msgstr "Abspielen" #: src/window.py:302 msgid "Pause" msgstr "Pausieren" #: src/window.py:317 msgid "Default Presets" msgstr "Standard-Vorgaben" #: src/window.py:344 msgid "MIDI files" msgstr "MIDI-Dateien" #: src/window.py:350 msgid "Open MIDI File" msgstr "MIDI-Datei öffnen" #: src/window.ui:41 msgid "Open" msgstr "Öffnen" #: src/window.ui:43 src/window.ui:46 msgid "Open Preset" msgstr "Vorgabe öffnen" #: src/window.ui:47 msgid "Open Saved Drum Pattern Preset" msgstr "Gespeicherte Schlagzeugrhythmus-Vorgabe öffnen" #: src/window.ui:65 src/window.ui:67 msgid "Main Menu" msgstr "Hauptmenü" #: src/window.ui:68 msgid "Access Keyboard Shortcuts and Application Information" msgstr "Tastenkürzel und Anwendungsinformationen einsehen" #: src/window.ui:75 src/window.ui:77 msgid "Save Drum Pattern" msgstr "Schlagzeugrhythmus speichern" #: src/window.ui:78 msgid "Save Current Drum Pattern as a Preset File" msgstr "Aktuellen Schlagzeugrhythmus als Vorgabe speichern" #: src/window.ui:122 msgid "BPM" msgstr "BPM" #: src/window.ui:127 src/window.ui:131 msgid "Adjust Tempo In Beats per Minute (BPM)" msgstr "Taktschläge pro Minute anpassen (BPM)" #: src/window.ui:130 msgid "Tempo" msgstr "Geschwindigkeit" #: src/window.ui:172 msgid "Adjust Volume" msgstr "Lautstärke anpassen" #: src/window.ui:195 msgid "Reset" msgstr "Zurücksetzen" #: src/window.ui:196 msgid "Reset the Drum Sequence" msgstr "Den Schlagzeugrhythmus zurücksetzen" #: src/window.ui:209 msgid "_Keyboard Shortcuts" msgstr "_Tastenkürzel" #: src/window.ui:213 msgid "_About Drum Machine" msgstr "_Info zu Drum Machine" #: src/gtk/help-overlay.ui:11 msgctxt "shortcut window" msgid "General" msgstr "Allgemein" #: src/gtk/help-overlay.ui:14 msgctxt "shortcut window" msgid "Show Shortcuts" msgstr "Tastenkürzel anzeigen" #: src/gtk/help-overlay.ui:20 msgctxt "shortcut window" msgid "Quit" msgstr "Beenden" #: src/gtk/help-overlay.ui:29 msgctxt "shortcut window" msgid "Playback Controls" msgstr "Wiedergabekontrolle" #: src/gtk/help-overlay.ui:32 msgctxt "shortcut window" msgid "Play/Pause" msgstr "Abspielen/Pausieren" #: src/gtk/help-overlay.ui:39 msgctxt "shortcut window" msgid "Clear All" msgstr "Alles leeren" #: src/gtk/help-overlay.ui:48 msgctxt "shortcut window" msgid "BPM & Volume Controls" msgstr "BPM & Lautstärkeregelung" #: src/gtk/help-overlay.ui:51 msgctxt "shortcut window" msgid "Increase BPM" msgstr "BPM erhöhen" #: src/gtk/help-overlay.ui:58 msgctxt "shortcut window" msgid "Decrease BPM" msgstr "BPM verringern" #: src/gtk/help-overlay.ui:65 msgctxt "shortcut window" msgid "Increase Volume" msgstr "Lautstärke erhöhen" #: src/gtk/help-overlay.ui:72 msgctxt "shortcut window" msgid "Decrease Volume" msgstr "Lautstärke verringern" #: src/gtk/help-overlay.ui:81 msgctxt "shortcut window" msgid "Preset Management" msgstr "Vorgaberhythmenverwaltung" #: src/gtk/help-overlay.ui:84 msgctxt "shortcut window" msgid "Load Preset" msgstr "Vorgaberhythmus laden" #: src/gtk/help-overlay.ui:91 msgctxt "shortcut window" msgid "Save Preset" msgstr "Vorgaberhythmus speichern" #: src/gtk/save_changes_dialog.ui:6 msgid "Save Changes?" msgstr "Änderungen speichern?" #: src/gtk/save_changes_dialog.ui:7 msgid "" "Current preset contains unsaved changes. Changes which are not saved will be " "permanently lost." msgstr "" "Der aktuelle Vorgaberhythmus enthält ungespeicherte Änderungen, die " "unwiederbringlich verloren gehen, sofern sie nicht gespeichert werden." #. Cancel the operation #: src/gtk/save_changes_dialog.ui:14 msgid "_Cancel" msgstr "_Abbrechen" #. Discard all changes #: src/gtk/save_changes_dialog.ui:15 msgid "_Discard" msgstr "_Verwerfen" #. Save current changes #: src/gtk/save_changes_dialog.ui:16 msgid "_Save" msgstr "_Speichern" drum-machine-2.2.0/po/drum-machine.pot000066400000000000000000000553061514070543000176070ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the drum-machine package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: drum-machine\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2025-12-18 23:51+0330\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: data/io.github.revisto.drum-machine.desktop.in:2 #: data/io.github.revisto.drum-machine.metainfo.xml.in:6 src/application.py:67 #: src/window.ui:69 msgid "Drum Machine" msgstr "" #. Translators: Search terms to find this application. Do NOT translate or localise the semicolons! The list MUST also end with a semicolon! #: data/io.github.revisto.drum-machine.desktop.in:9 msgid "drum;drums;sequencer;rhythm;music;pattern;beats;percussion;loop;groove;" msgstr "" #: data/io.github.revisto.drum-machine.metainfo.xml.in:7 msgid "Create and play drum beats" msgstr "" #: data/io.github.revisto.drum-machine.metainfo.xml.in:9 msgid "" "Drum Machine is a modern and intuitive application for creating, playing, " "and managing drum patterns. Perfect for musicians, producers, and anyone " "interested in rhythm creation, this application provides a simple interface " "for drum pattern programming. Have fun!" msgstr "" #: data/io.github.revisto.drum-machine.metainfo.xml.in:15 msgid "Features:" msgstr "" #: data/io.github.revisto.drum-machine.metainfo.xml.in:17 msgid "Intuitive grid-based pattern editor with infinite pages" msgstr "" #: data/io.github.revisto.drum-machine.metainfo.xml.in:18 msgid "Custom samples: Add your own drum sounds with MIDI note mapping" msgstr "" #: data/io.github.revisto.drum-machine.metainfo.xml.in:19 msgid "Adjustable BPM control" msgstr "" #: data/io.github.revisto.drum-machine.metainfo.xml.in:20 msgid "Volume control for overall mix" msgstr "" #: data/io.github.revisto.drum-machine.metainfo.xml.in:21 msgid "Save and load patterns" msgstr "" #: data/io.github.revisto.drum-machine.metainfo.xml.in:22 msgid "Multiple drum sounds including kick, snare, hi-hat, and more" msgstr "" #: data/io.github.revisto.drum-machine.metainfo.xml.in:23 msgid "" "Audio and MIDI export with support for WAV, FLAC, Ogg, MP3, and MIDI formats" msgstr "" #: data/io.github.revisto.drum-machine.metainfo.xml.in:24 msgid "Metadata support for embedding artist name, song title, and cover art" msgstr "" #: data/io.github.revisto.drum-machine.metainfo.xml.in:25 msgid "Keyboard shortcuts for quick access to all functions" msgstr "" #: data/io.github.revisto.drum-machine.metainfo.xml.in:34 msgid "Drum Pattern Loaded in Light Mode" msgstr "" #: data/io.github.revisto.drum-machine.metainfo.xml.in:38 msgid "Drum Pattern Loaded in Dark Mode" msgstr "" #: data/io.github.revisto.drum-machine.metainfo.xml.in:49 msgid "Revisto" msgstr "" #: data/io.github.revisto.drum-machine.metainfo.xml.in:55 msgid "Drum Machine 2.2.0: Reset to Defaults!" msgstr "" #: data/io.github.revisto.drum-machine.metainfo.xml.in:57 msgid "" "Reset to Defaults: New menu option to restore all samples, BPM, and volume " "to factory settings" msgstr "" #: data/io.github.revisto.drum-machine.metainfo.xml.in:58 msgid "" "Clear Button: Renamed from Reset, now only clears the pattern while keeping " "custom samples" msgstr "" #: data/io.github.revisto.drum-machine.metainfo.xml.in:64 msgid "Drum Machine 2.1.0: Drag and Drop!" msgstr "" #: data/io.github.revisto.drum-machine.metainfo.xml.in:66 msgid "" "Drag-and-Drop: Reorder drum parts by dragging them to new positions in the " "drum parts column" msgstr "" #: data/io.github.revisto.drum-machine.metainfo.xml.in:67 msgid "" "Slide Animations: New drum placeholder now features smooth slide-down " "animations for better visual feedback" msgstr "" #: data/io.github.revisto.drum-machine.metainfo.xml.in:73 msgid "Drum Machine 2.0.0 is a major release with custom samples! 🎶" msgstr "" #: data/io.github.revisto.drum-machine.metainfo.xml.in:75 msgid "" "Custom Samples: Add your own drum sounds and map them to specific MIDI notes " "for export" msgstr "" #: data/io.github.revisto.drum-machine.metainfo.xml.in:76 msgid "" "MIDI Export: Export your patterns as MIDI files with proper note mapping" msgstr "" #: data/io.github.revisto.drum-machine.metainfo.xml.in:77 msgid "" "Pattern Management: Presets have been refactored to a more flexible pattern " "system" msgstr "" #: data/io.github.revisto.drum-machine.metainfo.xml.in:78 msgid "" "Bug Fixes: Sounds now stop immediately when pausing, disabled export when " "pattern is empty" msgstr "" #: data/io.github.revisto.drum-machine.metainfo.xml.in:79 msgid "New Translations: Added Catalan, Greek, and Uzbek languages" msgstr "" #: data/io.github.revisto.drum-machine.metainfo.xml.in:80 msgid "" "Translation Updates: Updated Slovenian, Basque, Ukrainian, Georgian, " "Chinese, Persian, and many more" msgstr "" #: data/io.github.revisto.drum-machine.metainfo.xml.in:86 msgid "Drum Machine 1.5.0 introduces major audio export capabilities! 🎵" msgstr "" #: data/io.github.revisto.drum-machine.metainfo.xml.in:88 msgid "" "Audio Export Feature: Export your drum patterns to WAV, FLAC, Ogg Vorbis, " "and MP3 formats" msgstr "" #: data/io.github.revisto.drum-machine.metainfo.xml.in:89 msgid "" "Metadata Support: Embed artist name, song title, and cover art in exported " "files" msgstr "" #: data/io.github.revisto.drum-machine.metainfo.xml.in:90 msgid "" "Repeat Pattern: Set how many times your beat repeats in the exported audio" msgstr "" #: data/io.github.revisto.drum-machine.metainfo.xml.in:91 msgid "" "Bug Fix: Fixed issue where multiple drum sounds weren't playing " "simultaneously" msgstr "" #: data/io.github.revisto.drum-machine.metainfo.xml.in:92 msgid "" "Translation Updates: Updated Spanish, Russian, Georgian, Chinese, Hungarian, " "Swedish, and more" msgstr "" #: data/io.github.revisto.drum-machine.metainfo.xml.in:98 msgid "Drum Machine 1.4.0 is here with some good updates! 🥁" msgstr "" #: data/io.github.revisto.drum-machine.metainfo.xml.in:100 msgid "" "More pages for longer, more complex beats, because sometimes you need more " "than 16 steps!" msgstr "" #: data/io.github.revisto.drum-machine.metainfo.xml.in:101 msgid "" "Mobile-friendly improvements, now your drum machine works better on phones " "(with showing half of the grid)" msgstr "" #: data/io.github.revisto.drum-machine.metainfo.xml.in:102 msgid "" "Goes global! Now translated into 17 languages including Chinese, Russian, " "Arabic, Hebrew, and many more" msgstr "" #: data/io.github.revisto.drum-machine.metainfo.xml.in:108 msgid "" "This release of Drum Machine 1.3.1 brings significant UI and functionality " "improvements:" msgstr "" #: data/io.github.revisto.drum-machine.metainfo.xml.in:110 msgid "" "Refactored headerbar and background styling for a flat, integrated visual " "experience." msgstr "" #: data/io.github.revisto.drum-machine.metainfo.xml.in:111 msgid "" "Enhanced accessibility with improved tooltips and descriptive labels for BPM " "and volume controls." msgstr "" #: data/io.github.revisto.drum-machine.metainfo.xml.in:112 msgid "" "Redesigned app icon and updated text styling for clearer user interface " "elements." msgstr "" #: data/io.github.revisto.drum-machine.metainfo.xml.in:113 msgid "" "Optimized layout breakpoints to improve responsiveness and reduce early " "scrolling." msgstr "" #: data/io.github.revisto.drum-machine.metainfo.xml.in:114 msgid "" "Fixed padding, border-radius, and vertical alignment issues across multiple " "controls." msgstr "" #: data/io.github.revisto.drum-machine.metainfo.xml.in:115 msgid "" "Updated file dialogs to use the Nautilus file chooser for a more modern " "approach." msgstr "" #: data/io.github.revisto.drum-machine.metainfo.xml.in:116 msgid "" "Improved keyboard navigation focus and updated tooltips, including dedicated " "play and pause hints." msgstr "" #: data/io.github.revisto.drum-machine.metainfo.xml.in:117 msgid "" "Transitioned to the Nautilus file chooser for a more contemporary interface." msgstr "" #: data/io.github.revisto.drum-machine.metainfo.xml.in:118 msgid "Now accessible on narrow mobile screens with adaptive UI elements." msgstr "" #: data/io.github.revisto.drum-machine.metainfo.xml.in:119 msgid "Refined app icon, and adjusted brand colors for better contrast." msgstr "" #: src/application.py:74 msgid "" "Drum Machine is a modern and intuitive application for creating, playing, " "and managing drum patterns." msgstr "" #: src/application.py:79 msgid "translator-credits" msgstr "" #: src/application.py:84 msgid "Special thanks" msgstr "" #: src/application.py:87 msgid "Sounds" msgstr "" #: src/application.py:88 #, python-brace-format msgid "The drum samples used in this application are from {link}." msgstr "" #: src/config/export_formats.py:44 msgid "MP3 files" msgstr "" #: src/config/export_formats.py:45 msgid "MP3" msgstr "" #: src/config/export_formats.py:51 msgid "FLAC files" msgstr "" #: src/config/export_formats.py:52 msgid "FLAC (Lossless)" msgstr "" #: src/config/export_formats.py:58 msgid "Ogg files" msgstr "" #: src/config/export_formats.py:59 msgid "Ogg Vorbis" msgstr "" #: src/config/export_formats.py:65 msgid "WAV files" msgstr "" #: src/config/export_formats.py:66 msgid "WAV (Uncompressed)" msgstr "" #: src/dialogs/audio_export_dialog.py:119 msgid "Save Audio File" msgstr "" #: src/dialogs/audio_export_dialog.py:148 msgid "Part “{}” is Silent" msgstr "" #: src/dialogs/audio_export_dialog.py:150 msgid "Parts “{}” and “{}” are Silent" msgstr "" #: src/dialogs/audio_export_dialog.py:154 msgid "{} Parts are Silent" msgstr "" #: src/dialogs/audio_export_dialog.py:179 msgid "Image files" msgstr "" #: src/dialogs/audio_export_dialog.py:185 msgid "Select Cover Art" msgstr "" #: src/dialogs/audio_export_dialog.py:245 msgid "Audio exported to {}" msgstr "" #: src/dialogs/audio_export_dialog.py:251 msgid "Export failed" msgstr "" #: src/dialogs/audio_export_dialog.py:258 msgid "Export cancelled successfully" msgstr "" #: src/dialogs/midi_mapping_dialog.py:22 msgid "Acoustic Bass Drum" msgstr "" #: src/dialogs/midi_mapping_dialog.py:23 msgid "Bass Drum 1" msgstr "" #: src/dialogs/midi_mapping_dialog.py:24 msgid "Side Stick" msgstr "" #: src/dialogs/midi_mapping_dialog.py:25 msgid "Acoustic Snare" msgstr "" #: src/dialogs/midi_mapping_dialog.py:26 msgid "Hand Clap" msgstr "" #: src/dialogs/midi_mapping_dialog.py:27 msgid "Electric Snare" msgstr "" #: src/dialogs/midi_mapping_dialog.py:28 msgid "Low Floor Tom" msgstr "" #: src/dialogs/midi_mapping_dialog.py:29 msgid "Closed Hi Hat" msgstr "" #: src/dialogs/midi_mapping_dialog.py:30 msgid "High Floor Tom" msgstr "" #: src/dialogs/midi_mapping_dialog.py:31 msgid "Pedal Hi Hat" msgstr "" #: src/dialogs/midi_mapping_dialog.py:32 msgid "Low Tom" msgstr "" #: src/dialogs/midi_mapping_dialog.py:33 msgid "Open Hi Hat" msgstr "" #: src/dialogs/midi_mapping_dialog.py:34 msgid "Low-Mid Tom" msgstr "" #: src/dialogs/midi_mapping_dialog.py:35 msgid "Hi-Mid Tom" msgstr "" #: src/dialogs/midi_mapping_dialog.py:36 msgid "Crash Cymbal 1" msgstr "" #: src/dialogs/midi_mapping_dialog.py:37 msgid "High Tom" msgstr "" #: src/dialogs/midi_mapping_dialog.py:38 msgid "Ride Cymbal 1" msgstr "" #: src/dialogs/midi_mapping_dialog.py:39 msgid "Chinese Cymbal" msgstr "" #: src/dialogs/midi_mapping_dialog.py:40 msgid "Ride Bell" msgstr "" #: src/dialogs/midi_mapping_dialog.py:41 msgid "Tambourine" msgstr "" #: src/dialogs/midi_mapping_dialog.py:42 msgid "Splash Cymbal" msgstr "" #: src/dialogs/midi_mapping_dialog.py:43 msgid "Cowbell" msgstr "" #: src/dialogs/midi_mapping_dialog.py:44 msgid "Crash Cymbal 2" msgstr "" #: src/dialogs/midi_mapping_dialog.py:45 msgid "Vibraslap" msgstr "" #: src/dialogs/midi_mapping_dialog.py:46 msgid "Ride Cymbal 2" msgstr "" #: src/dialogs/midi_mapping_dialog.py:47 msgid "Hi Bongo" msgstr "" #: src/dialogs/midi_mapping_dialog.py:48 msgid "Low Bongo" msgstr "" #: src/dialogs/midi_mapping_dialog.py:49 msgid "Mute Hi Conga" msgstr "" #: src/dialogs/midi_mapping_dialog.py:50 msgid "Open Hi Conga" msgstr "" #: src/dialogs/midi_mapping_dialog.py:51 msgid "Low Conga" msgstr "" #: src/dialogs/midi_mapping_dialog.py:52 msgid "High Timbale" msgstr "" #: src/dialogs/midi_mapping_dialog.py:53 msgid "Low Timbale" msgstr "" #: src/dialogs/midi_mapping_dialog.py:54 msgid "High Agogo" msgstr "" #: src/dialogs/midi_mapping_dialog.py:55 msgid "Low Agogo" msgstr "" #: src/dialogs/midi_mapping_dialog.py:56 msgid "Cabasa" msgstr "" #: src/dialogs/midi_mapping_dialog.py:57 msgid "Maracas" msgstr "" #: src/dialogs/midi_mapping_dialog.py:58 msgid "Short Whistle" msgstr "" #: src/dialogs/midi_mapping_dialog.py:59 msgid "Long Whistle" msgstr "" #: src/dialogs/midi_mapping_dialog.py:60 msgid "Short Guiro" msgstr "" #: src/dialogs/midi_mapping_dialog.py:61 msgid "Long Guiro" msgstr "" #: src/dialogs/midi_mapping_dialog.py:62 msgid "Claves" msgstr "" #: src/dialogs/midi_mapping_dialog.py:63 msgid "Hi Wood Block" msgstr "" #: src/dialogs/midi_mapping_dialog.py:64 msgid "Low Wood Block" msgstr "" #: src/dialogs/midi_mapping_dialog.py:65 msgid "Mute Cuica" msgstr "" #: src/dialogs/midi_mapping_dialog.py:66 msgid "Open Cuica" msgstr "" #: src/dialogs/midi_mapping_dialog.py:67 msgid "Mute Triangle" msgstr "" #: src/dialogs/midi_mapping_dialog.py:68 msgid "Open Triangle" msgstr "" #: src/dialogs/midi_mapping_dialog.py:78 src/ui/drum_grid_builder.py:342 msgid "MIDI Mapping" msgstr "" #. Group 1: Note Assignment #: src/dialogs/midi_mapping_dialog.py:108 msgid "Note Assignment" msgstr "" #: src/dialogs/midi_mapping_dialog.py:111 msgid "" "Assign a MIDI note for '{}'. This ensures correct playback when exporting." msgstr "" #. Action Row for Note #: src/dialogs/midi_mapping_dialog.py:118 msgid "MIDI Note" msgstr "" #: src/dialogs/midi_mapping_dialog.py:119 msgid "The note number to trigger" msgstr "" #. Group 2: Standard Instruments #: src/dialogs/midi_mapping_dialog.py:137 msgid "Standard Instruments" msgstr "" #: src/dialogs/midi_mapping_dialog.py:139 msgid "Select a General MIDI instrument to automatically set the note." msgstr "" #: src/dialogs/midi_mapping_dialog.py:143 msgid "Instrument Preset" msgstr "" #: src/dialogs/midi_mapping_dialog.py:186 msgid "Save" msgstr "" #: src/dialogs/midi_mapping_dialog.py:229 msgid "Custom Note" msgstr "" #: src/handlers/drag_drop_handler.py:299 msgid "Sound replaced" msgstr "" #: src/handlers/drag_drop_handler.py:302 msgid "Failed to replace sound" msgstr "" #: src/handlers/drag_drop_handler.py:312 msgid "Not a supported audio file" msgstr "" #: src/handlers/drag_drop_handler.py:320 msgid "File not found" msgstr "" #: src/handlers/drag_drop_handler.py:325 msgid "Selected item is not a file" msgstr "" #: src/handlers/drag_drop_handler.py:332 msgid "File too large: {:.1f}MB (max 50MB)" msgstr "" #: src/handlers/drag_drop_handler.py:362 msgid "No valid audio files found" msgstr "" #: src/handlers/drag_drop_handler.py:402 msgid "Error processing file: {}" msgstr "" #: src/handlers/drag_drop_handler.py:433 msgid "Added {} drum part, {} files skipped" msgstr "" #: src/handlers/drag_drop_handler.py:439 msgid "Added {} drum parts, {} files skipped" msgstr "" #: src/handlers/drag_drop_handler.py:444 msgid "Added {} drum parts" msgstr "" #. Only show skipped message if no replacement happened #: src/handlers/drag_drop_handler.py:447 msgid "{} files skipped" msgstr "" #: src/handlers/file_dialog_handler.py:52 msgid "Default Patterns" msgstr "" #: src/handlers/file_dialog_handler.py:92 #: src/handlers/file_dialog_handler.py:171 msgid "MIDI files" msgstr "" #: src/handlers/file_dialog_handler.py:98 msgid "Open MIDI File" msgstr "" #: src/handlers/file_dialog_handler.py:127 msgid "Failed to open file" msgstr "" #: src/handlers/file_dialog_handler.py:165 msgid "Failed to load pattern" msgstr "" #: src/handlers/file_dialog_handler.py:179 msgid "Save Sequence" msgstr "" #: src/handlers/file_dialog_handler.py:205 msgid "Add Audio Samples" msgstr "" #: src/handlers/file_dialog_handler.py:227 msgid "Audio files" msgstr "" #: src/utils/export_progress.py:76 msgid "Preparing…" msgstr "" #: src/utils/export_progress.py:77 msgid "Initializing…" msgstr "" #: src/utils/export_progress.py:79 msgid "Rendering audio…" msgstr "" #: src/utils/export_progress.py:80 msgid "Processing beats…" msgstr "" #: src/utils/export_progress.py:82 msgid "Saving file…" msgstr "" #: src/utils/export_progress.py:83 msgid "Writing to disk…" msgstr "" #: src/utils/export_progress.py:85 msgid "Exporting…" msgstr "" #: src/utils/export_progress.py:86 msgid "Processing…" msgstr "" #: src/utils/name_utils.py:36 msgid "Custom Sound" msgstr "" #: src/ui/drum_grid_builder.py:327 msgid "Preview" msgstr "" #: src/ui/drum_grid_builder.py:329 msgid "Replace…" msgstr "" #: src/ui/drum_grid_builder.py:332 msgid "Replace with new sound" msgstr "" #: src/ui/drum_grid_builder.py:335 msgid "Remove" msgstr "" #: src/ui/drum_grid_builder.py:338 msgid "At least one drum part must remain" msgstr "" #: src/ui/drum_grid_builder.py:345 msgid "Configure MIDI note for export" msgstr "" #: src/ui/drum_grid_builder.py:402 msgid "MIDI note updated" msgstr "" #: src/ui/drum_grid_builder.py:410 msgid "Select New Sound" msgstr "" #: src/ui/drum_grid_builder.py:424 msgid "Removed drum part: {}" msgstr "" #: src/ui/drum_grid_builder.py:429 msgid "Failed to remove drum part" msgstr "" #. Update tooltip and accessibility with current BPM #: src/window.py:220 msgid "{} Beats per Minute (BPM)" msgstr "" #. Update button tooltip to show current volume level #: src/window.py:229 msgid "{:.0f}% Volume" msgstr "" #: src/window.py:262 src/window.ui:173 msgid "Play" msgstr "" #: src/window.py:266 msgid "Pause" msgstr "" #: src/window.py:313 msgid "Open" msgstr "" #: src/window.py:331 msgid "Added: {}" msgstr "" #: src/window.py:346 msgid "Failed to add custom sound" msgstr "" #: src/window.py:353 msgid "Replaced drum with: {}" msgstr "" #: src/window.py:361 msgid "Failed to replace drum sound" msgstr "" #: src/window.ui:52 msgid "Open…" msgstr "" #: src/window.ui:54 msgid "Open Pattern" msgstr "" #: src/window.ui:57 msgctxt "accessibility" msgid "Open Pattern" msgstr "" #: src/window.ui:58 msgid "Open Saved Drum Pattern" msgstr "" #: src/window.ui:76 msgid "Main Menu" msgstr "" #: src/window.ui:78 msgctxt "accessibility" msgid "Main Menu" msgstr "" #: src/window.ui:79 msgid "Access Keyboard Shortcuts and Application Information" msgstr "" #: src/window.ui:86 msgid "Export Audio…" msgstr "" #: src/window.ui:91 msgctxt "accessibility" msgid "Export Audio…" msgstr "" #: src/window.ui:92 msgid "Export Current Drum Pattern as Audio File" msgstr "" #: src/window.ui:137 msgid "BPM" msgstr "" #: src/window.ui:142 src/window.ui:146 msgid "Adjust Tempo In Beats per Minute (BPM)" msgstr "" #: src/window.ui:145 msgid "Tempo" msgstr "" #: src/window.ui:187 msgid "Adjust Volume" msgstr "" #: src/window.ui:210 msgid "Clear" msgstr "" #: src/window.ui:211 msgid "Clear the Drum Pattern" msgstr "" #: src/window.ui:226 msgid "_Add Samples…" msgstr "" #: src/window.ui:230 msgid "_Save Pattern…" msgstr "" #: src/window.ui:236 msgid "_Reset to Defaults" msgstr "" #: src/window.ui:242 msgid "_Keyboard Shortcuts" msgstr "" #: src/window.ui:246 msgid "_About Drum Machine" msgstr "" #: src/gtk/help-overlay.blp:11 msgctxt "shortcut window" msgid "General" msgstr "" #: src/gtk/help-overlay.blp:14 msgctxt "shortcut window" msgid "Show Shortcuts" msgstr "" #: src/gtk/help-overlay.blp:19 msgctxt "shortcut window" msgid "Quit" msgstr "" #: src/gtk/help-overlay.blp:26 msgctxt "shortcut window" msgid "Playback Controls" msgstr "" #: src/gtk/help-overlay.blp:29 msgctxt "shortcut window" msgid "Play/Pause" msgstr "" #: src/gtk/help-overlay.blp:35 msgctxt "shortcut window" msgid "Clear All" msgstr "" #: src/gtk/help-overlay.blp:42 msgctxt "shortcut window" msgid "BPM & Volume Controls" msgstr "" #: src/gtk/help-overlay.blp:45 msgctxt "shortcut window" msgid "Increase BPM" msgstr "" #: src/gtk/help-overlay.blp:51 msgctxt "shortcut window" msgid "Decrease BPM" msgstr "" #: src/gtk/help-overlay.blp:57 msgctxt "shortcut window" msgid "Increase Volume" msgstr "" #: src/gtk/help-overlay.blp:63 msgctxt "shortcut window" msgid "Decrease Volume" msgstr "" #: src/gtk/help-overlay.blp:69 msgctxt "shortcut window" msgid "Mute" msgstr "" #: src/gtk/help-overlay.blp:76 msgctxt "shortcut window" msgid "Pattern Management" msgstr "" #: src/gtk/help-overlay.blp:79 msgctxt "shortcut window" msgid "Load Pattern" msgstr "" #: src/gtk/help-overlay.blp:85 msgctxt "shortcut window" msgid "Save Pattern" msgstr "" #: src/gtk/help-overlay.blp:91 msgctxt "shortcut window" msgid "Export Audio" msgstr "" #: src/gtk/help-overlay.blp:98 msgctxt "shortcut window" msgid "Navigation" msgstr "" #: src/gtk/help-overlay.blp:101 msgctxt "shortcut window" msgid "Go to Instrument" msgstr "" #: src/gtk/help-overlay.blp:107 msgctxt "shortcut window" msgid "Previous Page" msgstr "" #: src/gtk/help-overlay.blp:113 msgctxt "shortcut window" msgid "Next Page" msgstr "" #: src/gtk/save-changes-dialog.blp:5 msgid "Save Changes?" msgstr "" #: src/gtk/save-changes-dialog.blp:6 msgid "" "Current pattern contains unsaved changes. Changes which are not saved will " "be permanently lost." msgstr "" #. Translators: Cancel the operation #: src/gtk/save-changes-dialog.blp:14 src/gtk/reset-defaults-dialog.blp:13 msgid "_Cancel" msgstr "" #. Translators: Discard all changes #: src/gtk/save-changes-dialog.blp:15 msgid "_Discard" msgstr "" #. Translators: Save current changes #: src/gtk/save-changes-dialog.blp:16 msgid "_Save" msgstr "" #: src/gtk/audio-export-dialog.blp:6 src/gtk/audio-export-dialog.blp:101 msgid "Export Audio" msgstr "" #: src/gtk/audio-export-dialog.blp:44 msgid "Audio Format" msgstr "" #: src/gtk/audio-export-dialog.blp:50 msgid "Repeat Count" msgstr "" #: src/gtk/audio-export-dialog.blp:51 msgid "How many times to repeat the pattern" msgstr "" #: src/gtk/audio-export-dialog.blp:64 msgid "Metadata" msgstr "" #: src/gtk/audio-export-dialog.blp:67 msgid "Artist Name" msgstr "" #: src/gtk/audio-export-dialog.blp:72 msgid "Song Name" msgstr "" #: src/gtk/audio-export-dialog.blp:77 msgid "Cover Art" msgstr "" #: src/gtk/audio-export-dialog.blp:81 msgid "Choose File…" msgstr "" #: src/gtk/audio-export-dialog.blp:110 msgid "Cancel Export" msgstr "" #: src/gtk/reset-defaults-dialog.blp:5 msgid "Reset to Defaults?" msgstr "" #: src/gtk/reset-defaults-dialog.blp:6 msgid "" "This will clear the current pattern and restore all samples, BPM, and volume " "to their default values. This action cannot be undone." msgstr "" #. Translators: Reset to defaults #: src/gtk/reset-defaults-dialog.blp:14 msgid "_Reset" msgstr "" drum-machine-2.2.0/po/el.po000066400000000000000000000335221514070543000154460ustar00rootroot00000000000000# Greek translation for drum-machine. # Copyright (C) 2025 drum-machine's COPYRIGHT HOLDER # This file is distributed under the same license as the drum-machine package. # Efstathios Iosifidis , 2025. # msgid "" msgstr "" "Project-Id-Version: drum-machine master\n" "Report-Msgid-Bugs-To: https://github.com/revisto/drum-machine/issues\n" "POT-Creation-Date: 2025-10-18 15:26+0000\n" "PO-Revision-Date: 2025-10-18 15:26+0000\n" "Last-Translator: FULL NAME \n" "Language-Team: Greek \n" "Language: el\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: data/io.github.revisto.drum-machine.desktop.in:2 #: data/io.github.revisto.drum-machine.metainfo.xml.in:6 src/window.ui:69 msgid "Drum Machine" msgstr "Μηχανή Τυμπάνων" #: data/io.github.revisto.drum-machine.desktop.in:9 msgid "drum;drums;sequencer;rhythm;music;pattern;beats;percussion;loop;groove;" msgstr "τύμπανο;τύμπανα;σειροθέτης;ρυθμός;μουσική;μοτίβο;χτύποι;κρουστά;βρόγχος;groove;" #: data/io.github.revisto.drum-machine.metainfo.xml.in:7 msgid "Create and play drum beats" msgstr "Δημιουργία και αναπαραγωγή ρυθμών τυμπάνων" #: data/io.github.revisto.drum-machine.metainfo.xml.in:9 msgid "" "Drum Machine is a modern and intuitive application for creating, playing, " "and managing drum patterns. Perfect for musicians, producers, and anyone " "interested in rhythm creation, this application provides a simple interface " "for drum pattern programming. Have fun!" msgstr "" "Η Μηχανή Τυμπάνων είναι μια μοντέρνα και διαισθητική εφαρμογή για τη " "δημιουργία, αναπαραγωγή και διαχείριση ρυθμικών μοτίβων. Ιδανική για " "μουσικούς, παραγωγούς και οποιονδήποτε ενδιαφέρεται για τη δημιουργία " "ρυθμού, αυτή η εφαρμογή παρέχει μια απλή διεπαφή για προγραμματισμό " "ρυθμικών μοτίβων. Καλή διασκέδαση!" #: data/io.github.revisto.drum-machine.metainfo.xml.in:15 msgid "Features:" msgstr "Χαρακτηριστικά:" #: data/io.github.revisto.drum-machine.metainfo.xml.in:17 msgid "Intuitive grid-based pattern editor" msgstr "Διαισθητικός επεξεργαστής μοτίβων βασισμένος σε πλέγμα" #: data/io.github.revisto.drum-machine.metainfo.xml.in:18 msgid "Adjustable BPM control" msgstr "Ρυθμιζόμενος έλεγχος BPM" #: data/io.github.revisto.drum-machine.metainfo.xml.in:19 msgid "Volume control for overall mix" msgstr "Έλεγχος έντασης για συνολική μίξη" #: data/io.github.revisto.drum-machine.metainfo.xml.in:20 msgid "Save and load preset patterns" msgstr "Αποθήκευση και φόρτωση προκαθορισμένων μοτίβων" #: data/io.github.revisto.drum-machine.metainfo.xml.in:21 msgid "Multiple drum sounds including kick, snare, hi-hat, and more" msgstr "Πολλαπλοί ήχοι τυμπάνων συμπεριλαμβανομένων kick, snare, hi-hat και άλλων" #: data/io.github.revisto.drum-machine.metainfo.xml.in:22 msgid "Audio export feature with support for WAV, FLAC, Ogg, and MP3 formats" msgstr "Λειτουργία εξαγωγής ήχου με υποστήριξη μορφών WAV, FLAC, Ogg και MP3" #: data/io.github.revisto.drum-machine.metainfo.xml.in:23 msgid "Metadata support for embedding artist name, song title, and cover art" msgstr "Υποστήριξη μεταδεδομένων για ενσωμάτωση ονόματος καλλιτέχνη, τίτλου τραγουδιού και εξωφύλλου" #: data/io.github.revisto.drum-machine.metainfo.xml.in:24 msgid "Keyboard shortcuts for quick access to all functions" msgstr "Συντομεύσεις πληκτρολογίου για γρήγορη πρόσβαση σε όλες τις λειτουργίες" #: data/io.github.revisto.drum-machine.metainfo.xml.in:33 msgid "Drum Pattern Loaded in Light Mode" msgstr "Ρυθμικό Μοτίβο Φορτωμένο σε Λειτουργία Φωτός" #: data/io.github.revisto.drum-machine.metainfo.xml.in:37 msgid "Drum Pattern Loaded in Dark Mode" msgstr "Ρυθμικό Μοτίβο Φορτωμένο σε Λειτουργία Σκότους" #: src/config/export_formats.py:43 msgid "MP3 files" msgstr "Αρχεία MP3" #: src/config/export_formats.py:44 msgid "MP3" msgstr "MP3" #: src/config/export_formats.py:50 msgid "FLAC files" msgstr "Αρχεία FLAC" #: src/config/export_formats.py:51 msgid "FLAC (Lossless)" msgstr "FLAC (Χωρίς Απώλειες)" #: src/config/export_formats.py:57 msgid "Ogg files" msgstr "Αρχεία Ogg" #: src/config/export_formats.py:58 msgid "Ogg Vorbis" msgstr "Ogg Vorbis" #: src/config/export_formats.py:64 msgid "WAV files" msgstr "Αρχεία WAV" #: src/config/export_formats.py:65 msgid "WAV (Uncompressed)" msgstr "WAV (Μη Συμπιεσμένο)" #: src/dialogs/audio_export_dialog.py:115 msgid "Save Audio File" msgstr "Αποθήκευση Αρχείου Ήχου" #: src/dialogs/audio_export_dialog.py:139 msgid "Image files" msgstr "Αρχεία εικόνας" #: src/dialogs/audio_export_dialog.py:145 msgid "Select Cover Art" msgstr "Επιλογή Εξωφύλλου" #: src/dialogs/audio_export_dialog.py:202 msgid "Audio exported to {}" msgstr "Ο ήχος εξήχθη στο {}" #: src/dialogs/audio_export_dialog.py:207 msgid "Export failed" msgstr "Αποτυχία εξαγωγής" #: src/dialogs/audio_export_dialog.py:214 msgid "Export cancelled successfully" msgstr "Η εξαγωγή ακυρώθηκε επιτυχώς" #: src/handlers/file_dialog_handler.py:51 msgid "Default Presets" msgstr "Προεπιλεγμένα Προκαθορισμένα" #: src/handlers/file_dialog_handler.py:83 msgid "No Pattern" msgstr "Κανένα Μοτίβο" #: src/handlers/file_dialog_handler.py:84 msgid "Please create a drum pattern before exporting audio." msgstr "Παρακαλώ δημιουργήστε ένα ρυθμικό μοτίβο πριν την εξαγωγή ήχου." #: src/handlers/file_dialog_handler.py:86 msgid "_OK" msgstr "_Εντάξει" #: src/handlers/file_dialog_handler.py:109 #: src/handlers/file_dialog_handler.py:177 msgid "MIDI files" msgstr "Αρχεία MIDI" #: src/handlers/file_dialog_handler.py:115 msgid "Open MIDI File" msgstr "Άνοιγμα Αρχείου MIDI" #: src/handlers/file_dialog_handler.py:185 msgid "Save Sequence" msgstr "Αποθήκευση Ακολουθίας" #: src/utils/export_progress.py:68 msgid "Preparing..." msgstr "Προετοιμασία..." #: src/utils/export_progress.py:69 msgid "Initializing..." msgstr "Αρχικοποίηση..." #: src/utils/export_progress.py:71 msgid "Rendering audio..." msgstr "Απόδοση ήχου..." #: src/utils/export_progress.py:72 msgid "Processing beats..." msgstr "Επεξεργασία χτυπημάτων..." #: src/utils/export_progress.py:74 msgid "Saving file..." msgstr "Αποθήκευση αρχείου..." #: src/utils/export_progress.py:75 msgid "Writing to disk..." msgstr "Εγγραφή στο δίσκο..." #: src/utils/export_progress.py:77 msgid "Exporting..." msgstr "Εξαγωγή..." #: src/utils/export_progress.py:78 msgid "Processing..." msgstr "Επεξεργασία..." #: src/window.py:198 msgid "{} Beats per Minute (BPM)" msgstr "{} Χτύποι ανά Λεπτό (BPM)" #: src/window.py:207 msgid "{:.0f}% Volume" msgstr "{:.0f}% Ένταση" #: src/window.py:222 src/window.ui:170 msgid "Play" msgstr "Αναπαραγωγή" #: src/window.py:226 msgid "Pause" msgstr "Παύση" #: src/window.py:264 src/window.ui:52 msgid "Open" msgstr "Άνοιγμα" #: src/window.ui:54 msgid "Open Preset" msgstr "Άνοιγμα Προκαθορισμένου" #: src/window.ui:57 msgctxt "accessibility" msgid "Open Preset" msgstr "Άνοιγμα Προκαθορισμένου" #: src/window.ui:58 msgid "Open Saved Drum Pattern Preset" msgstr "Άνοιγμα Αποθηκευμένου Προκαθορισμένου Ρυθμικού Μοτίβου" #: src/window.ui:76 msgid "Main Menu" msgstr "Κύριο Μενού" #: src/window.ui:78 msgctxt "accessibility" msgid "Main Menu" msgstr "Κύριο Μενού" #: src/window.ui:79 msgid "Access Keyboard Shortcuts and Application Information" msgstr "Πρόσβαση σε Συντομεύσεις Πληκτρολογίου και Πληροφορίες Εφαρμογής" #: src/window.ui:86 src/gtk/audio-export-dialog.blp:6 #: src/gtk/audio-export-dialog.blp:96 msgid "Export Audio" msgstr "Εξαγωγή Ήχου" #: src/window.ui:88 msgctxt "accessibility" msgid "Export Audio" msgstr "Εξαγωγή Ήχου" #: src/window.ui:89 msgid "Export Current Drum Pattern as Audio File" msgstr "Εξαγωγή Τρέχοντος Ρυθμικού Μοτίβου ως Αρχείο Ήχου" #: src/window.ui:134 msgid "BPM" msgstr "BPM" #: src/window.ui:139 src/window.ui:143 msgid "Adjust Tempo In Beats per Minute (BPM)" msgstr "Ρύθμιση Τέμπο σε Χτύπους ανά Λεπτό (BPM)" #: src/window.ui:142 msgid "Tempo" msgstr "Τέμπο" #: src/window.ui:184 msgid "Adjust Volume" msgstr "Ρύθμιση Έντασης" #: src/window.ui:207 msgid "Reset" msgstr "Επαναφορά" #: src/window.ui:208 msgid "Reset the Drum Sequence" msgstr "Επαναφορά Ακολουθίας Τυμπάνων" #: src/window.ui:223 msgid "_Save Pattern" msgstr "_Αποθήκευση Μοτίβου" #: src/window.ui:229 msgid "_Keyboard Shortcuts" msgstr "_Συντομεύσεις Πληκτρολογίου" #: src/window.ui:233 msgid "_About Drum Machine" msgstr "_Σχετικά με τη Μηχανή Τυμπάνων" #: src/gtk/help-overlay.blp:11 msgctxt "shortcut window" msgid "General" msgstr "Γενικά" #: src/gtk/help-overlay.blp:14 msgctxt "shortcut window" msgid "Show Shortcuts" msgstr "Εμφάνιση Συντομεύσεων" #: src/gtk/help-overlay.blp:19 msgctxt "shortcut window" msgid "Quit" msgstr "Έξοδος" #: src/gtk/help-overlay.blp:26 msgctxt "shortcut window" msgid "Playback Controls" msgstr "Χειριστήρια Αναπαραγωγής" #: src/gtk/help-overlay.blp:29 msgctxt "shortcut window" msgid "Play/Pause" msgstr "Αναπαραγωγή/Παύση" #: src/gtk/help-overlay.blp:35 msgctxt "shortcut window" msgid "Clear All" msgstr "Καθαρισμός Όλων" #: src/gtk/help-overlay.blp:42 msgctxt "shortcut window" msgid "BPM & Volume Controls" msgstr "Χειριστήρια BPM & Έντασης" #: src/gtk/help-overlay.blp:45 msgctxt "shortcut window" msgid "Increase BPM" msgstr "Αύξηση BPM" #: src/gtk/help-overlay.blp:51 msgctxt "shortcut window" msgid "Decrease BPM" msgstr "Μείωση BPM" #: src/gtk/help-overlay.blp:57 msgctxt "shortcut window" msgid "Increase Volume" msgstr "Αύξηση Έντασης" #: src/gtk/help-overlay.blp:63 msgctxt "shortcut window" msgid "Decrease Volume" msgstr "Μείωση Έντασης" #: src/gtk/help-overlay.blp:69 msgctxt "shortcut window" msgid "Mute" msgstr "Σίγαση" #: src/gtk/help-overlay.blp:76 msgctxt "shortcut window" msgid "Preset Management" msgstr "Διαχείριση Προκαθορισμένων" #: src/gtk/help-overlay.blp:79 msgctxt "shortcut window" msgid "Load Preset" msgstr "Φόρτωση Προκαθορισμένου" #: src/gtk/help-overlay.blp:85 msgctxt "shortcut window" msgid "Save Preset" msgstr "Αποθήκευση Προκαθορισμένου" #: src/gtk/help-overlay.blp:91 msgctxt "shortcut window" msgid "Export Audio" msgstr "Εξαγωγή Ήχου" #: src/gtk/help-overlay.blp:98 msgctxt "shortcut window" msgid "Navigation" msgstr "Πλοήγηση" #: src/gtk/help-overlay.blp:101 msgctxt "shortcut window" msgid "Go to Instrument" msgstr "Μετάβαση σε Όργανο" #: src/gtk/help-overlay.blp:107 msgctxt "shortcut window" msgid "Previous Page" msgstr "Προηγούμενη Σελίδα" #: src/gtk/help-overlay.blp:113 msgctxt "shortcut window" msgid "Next Page" msgstr "Επόμενη Σελίδα" #: src/gtk/save-changes-dialog.blp:5 msgid "Save Changes?" msgstr "Αποθήκευση Αλλαγών;" #: src/gtk/save-changes-dialog.blp:6 msgid "" "Current preset contains unsaved changes. Changes which are not saved will be " "permanently lost." msgstr "" "Το τρέχον προκαθορισμένο περιέχει μη αποθηκευμένες αλλαγές. Οι αλλαγές που " "δεν αποθηκεύονται θα χαθούν μόνιμα." #: src/gtk/save-changes-dialog.blp:14 msgid "_Cancel" msgstr "_Ακύρωση" #: src/gtk/save-changes-dialog.blp:15 msgid "_Discard" msgstr "_Απόρριψη" #: src/gtk/save-changes-dialog.blp:16 msgid "_Save" msgstr "_Αποθήκευση" #: src/gtk/audio-export-dialog.blp:39 msgid "Audio Format" msgstr "Μορφή Ήχου" #: src/gtk/audio-export-dialog.blp:45 msgid "Repeat Count" msgstr "Αριθμός Επαναλήψεων" #: src/gtk/audio-export-dialog.blp:46 msgid "How many times to repeat the pattern" msgstr "Πόσες φορές να επαναληφθεί το μοτίβο" #: src/gtk/audio-export-dialog.blp:59 msgid "Metadata" msgstr "Μεταδεδομένα" #: src/gtk/audio-export-dialog.blp:62 msgid "Artist Name" msgstr "Όνομα Καλλιτέχνη" #: src/gtk/audio-export-dialog.blp:67 msgid "Song Name" msgstr "Όνομα Τραγουδιού" #: src/gtk/audio-export-dialog.blp:72 msgid "Cover Art" msgstr "Εξώφυλλο" #: src/gtk/audio-export-dialog.blp:76 msgid "Choose File" msgstr "Επιλογή Αρχείου" #: src/gtk/audio-export-dialog.blp:105 msgid "Cancel Export" msgstr "Ακύρωση Εξαγωγής" drum-machine-2.2.0/po/en_GB.po000066400000000000000000000153131514070543000160160ustar00rootroot00000000000000# British English translation for drum-machine. # Copyright (C) 2025 drum-machine's COPYRIGHT HOLDER # This file is distributed under the same license as the drum-machine package. # Andi Chandler , 2025. # msgid "" msgstr "" "Project-Id-Version: drum-machine master\n" "Report-Msgid-Bugs-To: https://github.com/revisto/drum-machine/issues\n" "POT-Creation-Date: 2025-03-28 13:12+0000\n" "PO-Revision-Date: 2025-03-24 14:07+0000\n" "Last-Translator: Andi Chandler \n" "Language-Team: British English \n" "Language: en_GB\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Poedit 3.5\n" #: data/io.github.revisto.drum-machine.desktop.in:3 #: data/io.github.revisto.drum-machine.metainfo.xml.in:6 src/window.ui:58 msgid "Drum Machine" msgstr "Drum Machine" #: data/io.github.revisto.drum-machine.metainfo.xml.in:7 msgid "Create and play drum beats" msgstr "Create and play drum beats" #: data/io.github.revisto.drum-machine.metainfo.xml.in:9 msgid "" "Drum Machine is a modern and intuitive application for creating, playing, " "and managing drum patterns. Perfect for musicians, producers, and anyone " "interested in rhythm creation, this application provides a simple interface " "for drum pattern programming. Have fun!" msgstr "" "Drum Machine is a modern and intuitive application for creating, playing, " "and managing drum patterns. Perfect for musicians, producers, and anyone " "interested in rhythm creation, this application provides a simple interface " "for drum pattern programming. Have fun!" #: data/io.github.revisto.drum-machine.metainfo.xml.in:15 msgid "Features:" msgstr "Features:" #: data/io.github.revisto.drum-machine.metainfo.xml.in:17 msgid "Intuitive grid-based pattern editor" msgstr "Intuitive grid-based pattern editor" #: data/io.github.revisto.drum-machine.metainfo.xml.in:18 msgid "Adjustable BPM control" msgstr "Adjustable BPM control" #: data/io.github.revisto.drum-machine.metainfo.xml.in:19 msgid "Volume control for overall mix" msgstr "Volume control for overall mix" #: data/io.github.revisto.drum-machine.metainfo.xml.in:20 msgid "Save and load preset patterns" msgstr "Save and load preset patterns" #: data/io.github.revisto.drum-machine.metainfo.xml.in:21 msgid "Multiple drum sounds including kick, snare, hi-hat, and more" msgstr "Multiple drum sounds including kick, snare, hi-hat, and more" #: data/io.github.revisto.drum-machine.metainfo.xml.in:22 msgid "Keyboard shortcuts for quick access to all functions" msgstr "Keyboard shortcuts for quick access to all functions" #: data/io.github.revisto.drum-machine.metainfo.xml.in:31 msgid "Drum Pattern Loaded in Light Mode" msgstr "Drum Pattern Loaded in Light Mode" #: data/io.github.revisto.drum-machine.metainfo.xml.in:35 msgid "Drum Pattern Loaded in Dark Mode" msgstr "Drum Pattern Loaded in Dark Mode" #. Update tooltip and accessibility with current BPM #: src/window.py:278 msgid "{} Beats per Minute (BPM)" msgstr "{} Beats per Minute (BPM)" #. Update button tooltip to show current volume level #: src/window.py:287 msgid "{:.0f}% Volume" msgstr "{:.0f}% Volume" #: src/window.py:298 src/window.ui:158 msgid "Play" msgstr "Play" #: src/window.py:302 msgid "Pause" msgstr "Pause" #: src/window.py:317 msgid "Default Presets" msgstr "Default Presets" #: src/window.py:344 msgid "MIDI files" msgstr "MIDI files" #: src/window.py:350 msgid "Open MIDI File" msgstr "Open MIDI File" #: src/window.ui:41 msgid "Open" msgstr "Open" #: src/window.ui:43 src/window.ui:46 msgid "Open Preset" msgstr "Open Preset" #: src/window.ui:47 msgid "Open Saved Drum Pattern Preset" msgstr "Open Saved Drum Pattern Preset" #: src/window.ui:65 src/window.ui:67 msgid "Main Menu" msgstr "Main Menu" #: src/window.ui:68 msgid "Access Keyboard Shortcuts and Application Information" msgstr "Access Keyboard Shortcuts and Application Information" #: src/window.ui:75 src/window.ui:77 msgid "Save Drum Pattern" msgstr "Save Drum Pattern" #: src/window.ui:78 msgid "Save Current Drum Pattern as a Preset File" msgstr "Save Current Drum Pattern as a Preset File" #: src/window.ui:122 msgid "BPM" msgstr "BPM" #: src/window.ui:127 src/window.ui:131 msgid "Adjust Tempo In Beats per Minute (BPM)" msgstr "Adjust Tempo In Beats per Minute (BPM)" #: src/window.ui:130 msgid "Tempo" msgstr "Tempo" #: src/window.ui:172 msgid "Adjust Volume" msgstr "Adjust Volume" #: src/window.ui:195 msgid "Reset" msgstr "Reset" #: src/window.ui:196 msgid "Reset the Drum Sequence" msgstr "Reset the Drum Sequence" #: src/window.ui:209 msgid "_Keyboard Shortcuts" msgstr "_Keyboard Shortcuts" #: src/window.ui:213 msgid "_About Drum Machine" msgstr "_About Drum Machine" #: src/gtk/help-overlay.ui:11 msgctxt "shortcut window" msgid "General" msgstr "General" #: src/gtk/help-overlay.ui:14 msgctxt "shortcut window" msgid "Show Shortcuts" msgstr "Show Shortcuts" #: src/gtk/help-overlay.ui:20 msgctxt "shortcut window" msgid "Quit" msgstr "Quit" #: src/gtk/help-overlay.ui:29 msgctxt "shortcut window" msgid "Playback Controls" msgstr "Playback Controls" #: src/gtk/help-overlay.ui:32 msgctxt "shortcut window" msgid "Play/Pause" msgstr "Play/Pause" #: src/gtk/help-overlay.ui:39 msgctxt "shortcut window" msgid "Clear All" msgstr "Clear All" #: src/gtk/help-overlay.ui:48 msgctxt "shortcut window" msgid "BPM & Volume Controls" msgstr "BPM & Volume Controls" #: src/gtk/help-overlay.ui:51 msgctxt "shortcut window" msgid "Increase BPM" msgstr "Increase BPM" #: src/gtk/help-overlay.ui:58 msgctxt "shortcut window" msgid "Decrease BPM" msgstr "Decrease BPM" #: src/gtk/help-overlay.ui:65 msgctxt "shortcut window" msgid "Increase Volume" msgstr "Increase Volume" #: src/gtk/help-overlay.ui:72 msgctxt "shortcut window" msgid "Decrease Volume" msgstr "Decrease Volume" #: src/gtk/help-overlay.ui:81 msgctxt "shortcut window" msgid "Preset Management" msgstr "Preset Management" #: src/gtk/help-overlay.ui:84 msgctxt "shortcut window" msgid "Load Preset" msgstr "Load Preset" #: src/gtk/help-overlay.ui:91 msgctxt "shortcut window" msgid "Save Preset" msgstr "Save Preset" #: src/gtk/save_changes_dialog.ui:6 msgid "Save Changes?" msgstr "Save Changes?" #: src/gtk/save_changes_dialog.ui:7 msgid "" "Current preset contains unsaved changes. Changes which are not saved will be " "permanently lost." msgstr "" "Current preset contains unsaved changes. Changes which are not saved will be " "permanently lost." #. Cancel the operation #: src/gtk/save_changes_dialog.ui:14 msgid "_Cancel" msgstr "_Cancel" #. Discard all changes #: src/gtk/save_changes_dialog.ui:15 msgid "_Discard" msgstr "_Discard" #. Save current changes #: src/gtk/save_changes_dialog.ui:16 msgid "_Save" msgstr "_Save" drum-machine-2.2.0/po/es.po000066400000000000000000000316511514070543000154560ustar00rootroot00000000000000# Spanish translation for drum-machine. # Copyright (C) 2025 drum-machine's COPYRIGHT HOLDER # This file is distributed under the same license as the drum-machine package. # Julián Villodre , 2025. # msgid "" msgstr "" "Project-Id-Version: drum-machine master\n" "Report-Msgid-Bugs-To: https://github.com/revisto/drum-machine/issues\n" "POT-Creation-Date: 2025-10-12 15:26+0000\n" "PO-Revision-Date: 2025-10-12 19:36+0200\n" "Last-Translator: Julián Villodre \n" "Language-Team: es_ES\n" "Language: es_ES\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Gtranslator 49.0\n" #: data/io.github.revisto.drum-machine.desktop.in:2 #: data/io.github.revisto.drum-machine.metainfo.xml.in:6 src/window.ui:69 msgid "Drum Machine" msgstr "Drum Machine" #. Translators: Search terms to find this application. Do NOT translate or localise the semicolons! The list MUST also end with a semicolon! #: data/io.github.revisto.drum-machine.desktop.in:9 msgid "drum;drums;sequencer;rhythm;music;pattern;beats;percussion;loop;groove;" msgstr "drum;drums;sequencer;rhythm;music;pattern;beats;percussion;loop;groove;batería;secuenciador;ritmo;música;patrón;percusión;bucle;" #: data/io.github.revisto.drum-machine.metainfo.xml.in:7 msgid "Create and play drum beats" msgstr "Crea y reproduce ritmos de batería" #: data/io.github.revisto.drum-machine.metainfo.xml.in:9 msgid "" "Drum Machine is a modern and intuitive application for creating, playing, " "and managing drum patterns. Perfect for musicians, producers, and anyone " "interested in rhythm creation, this application provides a simple interface " "for drum pattern programming. Have fun!" msgstr "" "Drum Machine es una aplicación moderna e intuitiva para crear, reproducir y " "gestionar modelos de ritmos de batería. Perfecta para músicos, productores y " "cualquier persona interesada en la creación de ritmos, esta aplicación " "ofrece una interfaz sencilla para programar modelos de ritmos de batería. ¡A " "divertirse!" #: data/io.github.revisto.drum-machine.metainfo.xml.in:15 msgid "Features:" msgstr "Características:" #: data/io.github.revisto.drum-machine.metainfo.xml.in:17 msgid "Intuitive grid-based pattern editor" msgstr "Editor de modelo de ritmo intuitivo basado en cuadrícula" #: data/io.github.revisto.drum-machine.metainfo.xml.in:18 msgid "Adjustable BPM control" msgstr "Control de BPM ajustable" #: data/io.github.revisto.drum-machine.metainfo.xml.in:19 msgid "Volume control for overall mix" msgstr "Control de volumen para la mezcla general" #: data/io.github.revisto.drum-machine.metainfo.xml.in:20 msgid "Save and load preset patterns" msgstr "Guarde y cargue modelos de ritmos preestablecidos" #: data/io.github.revisto.drum-machine.metainfo.xml.in:21 msgid "Multiple drum sounds including kick, snare, hi-hat, and more" msgstr "Múltiples sonidos de batería, incluidos bombo, caja, charles y más" #: data/io.github.revisto.drum-machine.metainfo.xml.in:22 msgid "Audio export feature with support for WAV, FLAC, Ogg, and MP3 formats" msgstr "" "Función de exportación de sonido con soporte para formatos WAV, FLAC, Ogg y " "MP3" #: data/io.github.revisto.drum-machine.metainfo.xml.in:23 msgid "Metadata support for embedding artist name, song title, and cover art" msgstr "" "Soporte de metadatos para insertar el nombre del artista, el título de la " "canción y la carátula" #: data/io.github.revisto.drum-machine.metainfo.xml.in:24 msgid "Keyboard shortcuts for quick access to all functions" msgstr "Combinaciones de teclas para acceder rápidamente a todas las funciones" #: data/io.github.revisto.drum-machine.metainfo.xml.in:33 msgid "Drum Pattern Loaded in Light Mode" msgstr "Modelo de ritmo de batería cargado en modo claro" #: data/io.github.revisto.drum-machine.metainfo.xml.in:37 msgid "Drum Pattern Loaded in Dark Mode" msgstr "Modelo de ritmo de batería cargado en modo oscuro" #: src/application.py:69 msgid "translator-credits" msgstr "Julián Villodre , 2025" #: src/config/export_formats.py:43 msgid "MP3 files" msgstr "Archivos MP3" #: src/config/export_formats.py:44 msgid "MP3" msgstr "MP3" #: src/config/export_formats.py:50 msgid "FLAC files" msgstr "Archivos FLAC" #: src/config/export_formats.py:51 msgid "FLAC (Lossless)" msgstr "FLAC (sin pérdida)" #: src/config/export_formats.py:57 msgid "Ogg files" msgstr "Archivos Ogg" #: src/config/export_formats.py:58 msgid "Ogg Vorbis" msgstr "Ogg Vorbis" #: src/config/export_formats.py:64 msgid "WAV files" msgstr "Archivos WAV" #: src/config/export_formats.py:65 msgid "WAV (Uncompressed)" msgstr "WAV (sin comprimir)" #: src/dialogs/audio_export_dialog.py:115 msgid "Save Audio File" msgstr "Guardar archivo de sonido" #: src/dialogs/audio_export_dialog.py:139 msgid "Image files" msgstr "Archivos de imagen" #: src/dialogs/audio_export_dialog.py:145 msgid "Select Cover Art" msgstr "Seleccionar carátula" #: src/dialogs/audio_export_dialog.py:202 msgid "Audio exported to {}" msgstr "Se exportó el sonido a {}" #: src/dialogs/audio_export_dialog.py:207 msgid "Export failed" msgstr "Falló al exportar" #: src/dialogs/audio_export_dialog.py:214 msgid "Export cancelled successfully" msgstr "Se canceló con éxito la exportación" #: src/handlers/file_dialog_handler.py:51 msgid "Default Presets" msgstr "Preajustes predeterminados" #: src/handlers/file_dialog_handler.py:83 msgid "No Pattern" msgstr "Sin modelo de ritmo" #: src/handlers/file_dialog_handler.py:84 msgid "Please create a drum pattern before exporting audio." msgstr "Cree un modelo de ritmo de batería antes de exportar el sonido." #: src/handlers/file_dialog_handler.py:86 msgid "_OK" msgstr "_Aceptar" #: src/handlers/file_dialog_handler.py:109 #: src/handlers/file_dialog_handler.py:177 msgid "MIDI files" msgstr "Archivos MIDI" #: src/handlers/file_dialog_handler.py:115 msgid "Open MIDI File" msgstr "Abrir archivo MIDI" #: src/handlers/file_dialog_handler.py:185 msgid "Save Sequence" msgstr "Guardar secuencia" #: src/utils/export_progress.py:68 msgid "Preparing..." msgstr "Preparando…" #: src/utils/export_progress.py:69 msgid "Initializing..." msgstr "Inicializando…" #: src/utils/export_progress.py:71 msgid "Rendering audio..." msgstr "Renderizando sonido…" #: src/utils/export_progress.py:72 msgid "Processing beats..." msgstr "Procesando ritmos…" #: src/utils/export_progress.py:74 msgid "Saving file..." msgstr "Guardando archivo…" #: src/utils/export_progress.py:75 msgid "Writing to disk..." msgstr "Escribiendo en el disco…" #: src/utils/export_progress.py:77 msgid "Exporting..." msgstr "Exportando…" #: src/utils/export_progress.py:78 msgid "Processing..." msgstr "Procesando…" #. Update tooltip and accessibility with current BPM #: src/window.py:198 msgid "{} Beats per Minute (BPM)" msgstr "{} Ritmos por minuto (BPM)" #. Update button tooltip to show current volume level #: src/window.py:207 msgid "{:.0f}% Volume" msgstr "{:.0f}% Volumen" #: src/window.py:222 src/window.ui:170 msgid "Play" msgstr "Reproducir" #: src/window.py:226 msgid "Pause" msgstr "Pausar" #: src/window.py:264 src/window.ui:52 msgid "Open" msgstr "Abrir" #: src/window.ui:54 msgid "Open Preset" msgstr "Abrir preajuste" #: src/window.ui:57 msgctxt "accessibility" msgid "Open Preset" msgstr "Abrir preajuste" #: src/window.ui:58 msgid "Open Saved Drum Pattern Preset" msgstr "Abrir preajuste guardado de modelo de ritmo de batería" #: src/window.ui:76 msgid "Main Menu" msgstr "Menú principal" #: src/window.ui:78 msgctxt "accessibility" msgid "Main Menu" msgstr "Menú principal" #: src/window.ui:79 msgid "Access Keyboard Shortcuts and Application Information" msgstr "" "Acceder a las combinaciones de teclas y a la información de la aplicación" #: src/window.ui:86 src/gtk/audio-export-dialog.blp:6 #: src/gtk/audio-export-dialog.blp:96 msgid "Export Audio" msgstr "Exportar sonido" #: src/window.ui:88 msgctxt "accessibility" msgid "Export Audio" msgstr "Exportar sonido" #: src/window.ui:89 msgid "Export Current Drum Pattern as Audio File" msgstr "Exportar el modelo de ritmo de batería actual como archivo de sonido" #: src/window.ui:134 msgid "BPM" msgstr "BPM" #: src/window.ui:139 src/window.ui:143 msgid "Adjust Tempo In Beats per Minute (BPM)" msgstr "Ajustar tempo en ritmos por minuto (BPM)" #: src/window.ui:142 msgid "Tempo" msgstr "Tempo" #: src/window.ui:184 msgid "Adjust Volume" msgstr "Ajustar volumen" #: src/window.ui:207 msgid "Reset" msgstr "Reiniciar" #: src/window.ui:208 msgid "Reset the Drum Sequence" msgstr "Reiniciar la secuencia de la batería" #: src/window.ui:223 msgid "_Save Pattern" msgstr "_Guardar modelo de ritmo" #: src/window.ui:229 msgid "_Keyboard Shortcuts" msgstr "_Combinación de teclas" #: src/window.ui:233 msgid "_About Drum Machine" msgstr "_Acerca de Drum Machine" #: src/gtk/help-overlay.blp:11 msgctxt "shortcut window" msgid "General" msgstr "General" #: src/gtk/help-overlay.blp:14 msgctxt "shortcut window" msgid "Show Shortcuts" msgstr "Mostrar combinaciones de teclas" #: src/gtk/help-overlay.blp:19 msgctxt "shortcut window" msgid "Quit" msgstr "Salir" #: src/gtk/help-overlay.blp:26 msgctxt "shortcut window" msgid "Playback Controls" msgstr "Controles de reproducción" #: src/gtk/help-overlay.blp:29 msgctxt "shortcut window" msgid "Play/Pause" msgstr "Reproducir/Pausar" #: src/gtk/help-overlay.blp:35 msgctxt "shortcut window" msgid "Clear All" msgstr "Vaciar todo" #: src/gtk/help-overlay.blp:42 msgctxt "shortcut window" msgid "BPM & Volume Controls" msgstr "BPM y controles de volumen" #: src/gtk/help-overlay.blp:45 msgctxt "shortcut window" msgid "Increase BPM" msgstr "Aumentar BPM" #: src/gtk/help-overlay.blp:51 msgctxt "shortcut window" msgid "Decrease BPM" msgstr "Disminuir BPM" #: src/gtk/help-overlay.blp:57 msgctxt "shortcut window" msgid "Increase Volume" msgstr "Aumentar volumen" #: src/gtk/help-overlay.blp:63 msgctxt "shortcut window" msgid "Decrease Volume" msgstr "Disminuir volumen" #: src/gtk/help-overlay.blp:69 msgctxt "shortcut window" msgid "Mute" msgstr "Silenciar" #: src/gtk/help-overlay.blp:76 msgctxt "shortcut window" msgid "Preset Management" msgstr "Gestión de preajuste" #: src/gtk/help-overlay.blp:79 msgctxt "shortcut window" msgid "Load Preset" msgstr "Cargar preajuste" #: src/gtk/help-overlay.blp:85 msgctxt "shortcut window" msgid "Save Preset" msgstr "Guardar preajuste" #: src/gtk/help-overlay.blp:91 msgctxt "shortcut window" msgid "Export Audio" msgstr "Exportar sonido" #: src/gtk/help-overlay.blp:98 msgctxt "shortcut window" msgid "Navigation" msgstr "Navegación" #: src/gtk/help-overlay.blp:101 msgctxt "shortcut window" msgid "Go to Instrument" msgstr "Ir al instrumento" #: src/gtk/help-overlay.blp:107 msgctxt "shortcut window" msgid "Previous Page" msgstr "Página anterior" #: src/gtk/help-overlay.blp:113 msgctxt "shortcut window" msgid "Next Page" msgstr "Página siguiente" #: src/gtk/save-changes-dialog.blp:5 msgid "Save Changes?" msgstr "¿Guardar cambios?" #: src/gtk/save-changes-dialog.blp:6 msgid "" "Current preset contains unsaved changes. Changes which are not saved will be " "permanently lost." msgstr "" "El preajuste actual contiene cambios sin guardar. Los cambios que no se " "guarden se perderán permanentemente." #. Translators: Cancel the operation #: src/gtk/save-changes-dialog.blp:14 msgid "_Cancel" msgstr "_Cancelar" #. Translators: Discard all changes #: src/gtk/save-changes-dialog.blp:15 msgid "_Discard" msgstr "_Descartar" #. Translators: Save current changes #: src/gtk/save-changes-dialog.blp:16 msgid "_Save" msgstr "_Guardar" #: src/gtk/audio-export-dialog.blp:39 msgid "Audio Format" msgstr "Formato de sonido" #: src/gtk/audio-export-dialog.blp:45 msgid "Repeat Count" msgstr "Conteo de repeticiones" #: src/gtk/audio-export-dialog.blp:46 msgid "How many times to repeat the pattern" msgstr "Cuántas veces se repetirá el modelo" #: src/gtk/audio-export-dialog.blp:59 msgid "Metadata" msgstr "Metadatos" #: src/gtk/audio-export-dialog.blp:62 msgid "Artist Name" msgstr "Nombre del artista" #: src/gtk/audio-export-dialog.blp:67 msgid "Song Name" msgstr "Nombre de la canción" #: src/gtk/audio-export-dialog.blp:72 msgid "Cover Art" msgstr "Carátula" #: src/gtk/audio-export-dialog.blp:76 msgid "Choose File" msgstr "Seleccionar archivo" #: src/gtk/audio-export-dialog.blp:105 msgid "Cancel Export" msgstr "Cancelar exportación" #~ msgid "Export Settings" #~ msgstr "Exportar ajustes" #~ msgid "Configure your audio export options" #~ msgstr "Configurar las opciones de exportación de sonido" #~ msgid "Select the output audio format" #~ msgstr "Seleccionar el formato de sonido de salida" #~ msgid "Add metadata to your exported audio" #~ msgstr "Añadir metadatos al sonido exportado" #~ msgid "Select an image file for the cover art" #~ msgstr "Seleccionar un archivo de imagen para la carátula" #~ msgctxt "accessibility" #~ msgid "Save Drum Pattern" #~ msgstr "Guardar modelo de ritmo de batería" drum-machine-2.2.0/po/eu.po000066400000000000000000000537741514070543000154720ustar00rootroot00000000000000# Basque translation for drum-machine. # Copyright (C) 2025 drum-machine's COPYRIGHT HOLDER # This file is distributed under the same license as the drum-machine package. # Asier Saratsua Garmendia , 2025. # msgid "" msgstr "Project-Id-Version: drum-machine master\n" "Report-Msgid-Bugs-To: https://github.com/revisto/drum-machine/issues\n" "POT-Creation-Date: 2025-12-18 03:26+0000\n" "PO-Revision-Date: 2025-12-18 13:12+0000\n" "Last-Translator: Asier Saratsua Garmendia \n" "Language-Team: Basque \n" "Language: eu\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: data/io.github.revisto.drum-machine.desktop.in:2 #: data/io.github.revisto.drum-machine.metainfo.xml.in:6 src/application.py:67 #: src/window.ui:69 msgid "Drum Machine" msgstr "Drum Machine" #. Translators: Search terms to find this application. Do NOT translate or localise the semicolons! The list MUST also end with a semicolon! #: data/io.github.revisto.drum-machine.desktop.in:9 msgid "drum;drums;sequencer;rhythm;music;pattern;beats;percussion;loop;groove;" msgstr "danborra;danborrak;sekuentziatzailea;erritmoa;musika;eredua;kolpeak;perkusioa;begizta;errutina;" #: data/io.github.revisto.drum-machine.metainfo.xml.in:7 msgid "Create and play drum beats" msgstr "Sortu eta erreproduzitu danbor-hotsak" #: data/io.github.revisto.drum-machine.metainfo.xml.in:9 msgid "" "Drum Machine is a modern and intuitive application for creating, playing, " "and managing drum patterns. Perfect for musicians, producers, and anyone " "interested in rhythm creation, this application provides a simple interface " "for drum pattern programming. Have fun!" msgstr "Drum Machine danbor-ereduak sortu, erreproduzitu eta kudeatzeko aplikazio moderno eta erabilerraza da. Erritmoak sortu nahi duten musikari, produktore eta beste edozeinentzat pentsatua, aplikazio honek interfaze sinplea eskaintzen du danbor-ereduak programatzeko. Ondo pasa!" #: data/io.github.revisto.drum-machine.metainfo.xml.in:15 msgid "Features:" msgstr "Eginbideak:" #: data/io.github.revisto.drum-machine.metainfo.xml.in:17 #| msgid "Intuitive grid-based pattern editor" msgid "Intuitive grid-based pattern editor with infinite pages" msgstr "Ereduen editorea, sareta formakoa eta orri amaigabeak dituena" #: data/io.github.revisto.drum-machine.metainfo.xml.in:18 msgid "Custom samples: Add your own drum sounds with MIDI note mapping" msgstr "Lagin pertsonalizatuak: Gehitu zure dabor-soinuak MIDI noten mapatzearekin" #: data/io.github.revisto.drum-machine.metainfo.xml.in:19 msgid "Adjustable BPM control" msgstr "BPM kontrol doigarria" #: data/io.github.revisto.drum-machine.metainfo.xml.in:20 msgid "Volume control for overall mix" msgstr "Nahaste osorako bolumen-kontrola" #: data/io.github.revisto.drum-machine.metainfo.xml.in:21 msgid "Save and load patterns" msgstr "Gorde eta kargatu ereduak" #: data/io.github.revisto.drum-machine.metainfo.xml.in:22 msgid "Multiple drum sounds including kick, snare, hi-hat, and more" msgstr "Danbor-hots anitz, dunbala, kaxa, charlestona eta gehiago barne" #: data/io.github.revisto.drum-machine.metainfo.xml.in:23 #| msgid "" #| "Audio export feature with support for WAV, FLAC, Ogg, and MP3 formats" msgid "" "Audio and MIDI export with support for WAV, FLAC, Ogg, MP3, and MIDI formats" msgstr "Audioa eta MIDIa esportatzeko aukera, WAV, FLAC, Ogg, MP3 eta MIDI formatuak onartzen ditu" #: data/io.github.revisto.drum-machine.metainfo.xml.in:24 msgid "Metadata support for embedding artist name, song title, and cover art" msgstr "Metadatuak artisten izena, abestiaren izenburua eta azala kapsulatzeko" #: data/io.github.revisto.drum-machine.metainfo.xml.in:25 msgid "Keyboard shortcuts for quick access to all functions" msgstr "Lasterbideak funtzio guztiak azkar atzitzeko" #: data/io.github.revisto.drum-machine.metainfo.xml.in:34 msgid "Drum Pattern Loaded in Light Mode" msgstr "Danbor-eredua modu argian kargatua" #: data/io.github.revisto.drum-machine.metainfo.xml.in:38 msgid "Drum Pattern Loaded in Dark Mode" msgstr "Danbor-eredua modu ilunean kargatua" #: src/application.py:74 msgid "" "Drum Machine is a modern and intuitive application for creating, playing, " "and managing drum patterns." msgstr "Drum Machine danbor-ereduak sortu, erreproduzitu eta kudeatzeko aplikazio moderno eta erabilerraza da." #: src/application.py:79 msgid "translator-credits" msgstr "Asier Saratsua Garmendia " #: src/application.py:84 msgid "Special thanks" msgstr "Esker bereziak" #: src/application.py:87 msgid "Sounds" msgstr "Soinuak" #: src/application.py:88 #, python-brace-format msgid "The drum samples used in this application are from {link}." msgstr "Aplikazio honetan erabilitako danbor-laginak {link} gunekoak dira." #: src/config/export_formats.py:44 msgid "MP3 files" msgstr "MP3 fitxategiak" #: src/config/export_formats.py:45 msgid "MP3" msgstr "MP3" #: src/config/export_formats.py:51 msgid "FLAC files" msgstr "FLAC fitxategiak" #: src/config/export_formats.py:52 msgid "FLAC (Lossless)" msgstr "FLAC (galerarik gabea)" #: src/config/export_formats.py:58 msgid "Ogg files" msgstr "Ogg fitxategiak" #: src/config/export_formats.py:59 msgid "Ogg Vorbis" msgstr "Ogg Vorbis" #: src/config/export_formats.py:65 msgid "WAV files" msgstr "WAV fitxategiak" #: src/config/export_formats.py:66 msgid "WAV (Uncompressed)" msgstr "WAV (konprimatu gabea)" #: src/dialogs/audio_export_dialog.py:119 msgid "Save Audio File" msgstr "Gorde audio-fitxategia" #: src/dialogs/audio_export_dialog.py:148 msgid "Part “{}” is Silent" msgstr "“{}” atala isila da" #: src/dialogs/audio_export_dialog.py:150 msgid "Parts “{}” and “{}” are Silent" msgstr "“{}” eta “{}” atalak isilak dira" #: src/dialogs/audio_export_dialog.py:154 msgid "{} Parts are Silent" msgstr "{} atal isilak dira" #: src/dialogs/audio_export_dialog.py:179 msgid "Image files" msgstr "Irudi-fitxategiak" #: src/dialogs/audio_export_dialog.py:185 msgid "Select Cover Art" msgstr "Hautatu azala" #: src/dialogs/audio_export_dialog.py:245 msgid "Audio exported to {}" msgstr "Audioa hona esportatu da: {}" #: src/dialogs/audio_export_dialog.py:251 msgid "Export failed" msgstr "Esportazioak huts egin du" #: src/dialogs/audio_export_dialog.py:258 msgid "Export cancelled successfully" msgstr "Esportazioa ongi eten da" #: src/dialogs/midi_mapping_dialog.py:22 msgid "Acoustic Bass Drum" msgstr "Dunbal akustikoa" #: src/dialogs/midi_mapping_dialog.py:23 msgid "Bass Drum 1" msgstr "1. dunbala" #: src/dialogs/midi_mapping_dialog.py:24 msgid "Side Stick" msgstr "Alboko makila" #: src/dialogs/midi_mapping_dialog.py:25 msgid "Acoustic Snare" msgstr "Kaxa akustikoa" #: src/dialogs/midi_mapping_dialog.py:26 msgid "Hand Clap" msgstr "Txaloa" #: src/dialogs/midi_mapping_dialog.py:27 msgid "Electric Snare" msgstr "Kaxa elektrikoa" #: src/dialogs/midi_mapping_dialog.py:28 msgid "Low Floor Tom" msgstr "Zoru baxuko danborra" #: src/dialogs/midi_mapping_dialog.py:29 msgid "Closed Hi Hat" msgstr "Charleston itxia" #: src/dialogs/midi_mapping_dialog.py:30 msgid "High Floor Tom" msgstr "Zoru altuko danborra" #: src/dialogs/midi_mapping_dialog.py:31 msgid "Pedal Hi Hat" msgstr "Pedal-cahrlestona" #: src/dialogs/midi_mapping_dialog.py:32 msgid "Low Tom" msgstr "Danbor baxua" #: src/dialogs/midi_mapping_dialog.py:33 msgid "Open Hi Hat" msgstr "Charleston irekia" #: src/dialogs/midi_mapping_dialog.py:34 msgid "Low-Mid Tom" msgstr "Danbor baxu-ertaina" #: src/dialogs/midi_mapping_dialog.py:35 msgid "Hi-Mid Tom" msgstr "Danbora altu-ertaina" #: src/dialogs/midi_mapping_dialog.py:36 msgid "Crash Cymbal 1" msgstr "1. crash txindata" #: src/dialogs/midi_mapping_dialog.py:37 msgid "High Tom" msgstr "Danbor altua" #: src/dialogs/midi_mapping_dialog.py:38 msgid "Ride Cymbal 1" msgstr "1. ride txindata" #: src/dialogs/midi_mapping_dialog.py:39 msgid "Chinese Cymbal" msgstr "Txindata txinatarra" #: src/dialogs/midi_mapping_dialog.py:40 msgid "Ride Bell" msgstr "Ride kanpaina" #: src/dialogs/midi_mapping_dialog.py:41 msgid "Tambourine" msgstr "Panderoa" #: src/dialogs/midi_mapping_dialog.py:42 msgid "Splash Cymbal" msgstr "Splash txindata" #: src/dialogs/midi_mapping_dialog.py:43 msgid "Cowbell" msgstr "Zintzarria" #: src/dialogs/midi_mapping_dialog.py:44 msgid "Crash Cymbal 2" msgstr "2. crash txindata" #: src/dialogs/midi_mapping_dialog.py:45 msgid "Vibraslap" msgstr "Vibraslap-a" #: src/dialogs/midi_mapping_dialog.py:46 msgid "Ride Cymbal 2" msgstr "2. ride txindata" #: src/dialogs/midi_mapping_dialog.py:47 msgid "Hi Bongo" msgstr "Bongo altua" #: src/dialogs/midi_mapping_dialog.py:48 msgid "Low Bongo" msgstr "Bongo baxua" #: src/dialogs/midi_mapping_dialog.py:49 msgid "Mute Hi Conga" msgstr "Conga altu mutua" #: src/dialogs/midi_mapping_dialog.py:50 msgid "Open Hi Conga" msgstr "Conga altu irekia" #: src/dialogs/midi_mapping_dialog.py:51 msgid "Low Conga" msgstr "Conga baxua" #: src/dialogs/midi_mapping_dialog.py:52 msgid "High Timbale" msgstr "Tinbal altua" #: src/dialogs/midi_mapping_dialog.py:53 msgid "Low Timbale" msgstr "Tinbal baxua" #: src/dialogs/midi_mapping_dialog.py:54 msgid "High Agogo" msgstr "Agogo altua" #: src/dialogs/midi_mapping_dialog.py:55 msgid "Low Agogo" msgstr "Agogo baxua" #: src/dialogs/midi_mapping_dialog.py:56 msgid "Cabasa" msgstr "Kabasa" #: src/dialogs/midi_mapping_dialog.py:57 msgid "Maracas" msgstr "Marakak" #: src/dialogs/midi_mapping_dialog.py:58 msgid "Short Whistle" msgstr "Txilibitu laburra" #: src/dialogs/midi_mapping_dialog.py:59 msgid "Long Whistle" msgstr "Txilibitu luzea" #: src/dialogs/midi_mapping_dialog.py:60 msgid "Short Guiro" msgstr "Güiro laburra" #: src/dialogs/midi_mapping_dialog.py:61 msgid "Long Guiro" msgstr "Güiro luzea" #: src/dialogs/midi_mapping_dialog.py:62 msgid "Claves" msgstr "Klabezina" #: src/dialogs/midi_mapping_dialog.py:63 msgid "Hi Wood Block" msgstr "Kaxa txinatar altua" #: src/dialogs/midi_mapping_dialog.py:64 msgid "Low Wood Block" msgstr "Kaxa txinatar baxua" #: src/dialogs/midi_mapping_dialog.py:65 msgid "Mute Cuica" msgstr "Kuika mutua" #: src/dialogs/midi_mapping_dialog.py:66 msgid "Open Cuica" msgstr "Kuika irekia" #: src/dialogs/midi_mapping_dialog.py:67 msgid "Mute Triangle" msgstr "Triangelu mutua" #: src/dialogs/midi_mapping_dialog.py:68 msgid "Open Triangle" msgstr "Triangelu irekia" #: src/dialogs/midi_mapping_dialog.py:78 src/ui/drum_grid_builder.py:342 msgid "MIDI Mapping" msgstr "MIDI mapatzea" #. Group 1: Note Assignment #: src/dialogs/midi_mapping_dialog.py:108 msgid "Note Assignment" msgstr "Nota-esleipena" #: src/dialogs/midi_mapping_dialog.py:111 msgid "" "Assign a MIDI note for '{}'. This ensures correct playback when exporting." msgstr "Esleitu MIDI nota bat '{}' soinurako. Honek erreprodukzio zuzena ziurtatzen du esportatzean." #. Action Row for Note #: src/dialogs/midi_mapping_dialog.py:118 msgid "MIDI Note" msgstr "MIDI nota" #: src/dialogs/midi_mapping_dialog.py:119 msgid "The note number to trigger" msgstr "Abiaraziko den notaren zenbakia" #. Group 2: Standard Instruments #: src/dialogs/midi_mapping_dialog.py:137 msgid "Standard Instruments" msgstr "Musika-tresna estandarrak" #: src/dialogs/midi_mapping_dialog.py:139 msgid "Select a General MIDI instrument to automatically set the note." msgstr "Hautatu MIDI tresna orokor bat nota automatikoki ezartzeko." #: src/dialogs/midi_mapping_dialog.py:143 msgid "Instrument Preset" msgstr "Tresna-aurrezarpena" #: src/dialogs/midi_mapping_dialog.py:186 msgid "Save" msgstr "Gorde" #: src/dialogs/midi_mapping_dialog.py:229 msgid "Custom Note" msgstr "Nota pertsonalizatua" #: src/handlers/drag_drop_handler.py:299 msgid "Sound replaced" msgstr "Ordezkatutako soinua" #: src/handlers/drag_drop_handler.py:302 msgid "Failed to replace sound" msgstr "Huts egin du soinua ordezkatzeak" #: src/handlers/drag_drop_handler.py:312 msgid "Not a supported audio file" msgstr "Onartzen ez den audio-fitxategia" #: src/handlers/drag_drop_handler.py:320 msgid "File not found" msgstr "Ez da fitxategia aurkitu" #: src/handlers/drag_drop_handler.py:325 msgid "Selected item is not a file" msgstr "Hautatutako elementua ez da fitxategi bat" #: src/handlers/drag_drop_handler.py:332 msgid "File too large: {:.1f}MB (max 50MB)" msgstr "Fitxategi luzeegia: {:.1f}MB (max 50MB)" #: src/handlers/drag_drop_handler.py:362 msgid "No valid audio files found" msgstr "Ez da aurkitu baliozko audio-fitxategirik" #: src/handlers/drag_drop_handler.py:402 msgid "Error processing file: {}" msgstr "Errorea fitxategia prozesatzean: {}" #: src/handlers/drag_drop_handler.py:433 msgid "Added {} drum part, {} files skipped" msgstr "Danbor-atal {} gehitu da, {} fitxategi saltatu dira" #: src/handlers/drag_drop_handler.py:439 msgid "Added {} drum parts, {} files skipped" msgstr "{} danbor-atal gehitu dira, {} fitxategi saltatu dira" #: src/handlers/drag_drop_handler.py:444 msgid "Added {} drum parts" msgstr "{} danbor-atal gehitu dira" #. Only show skipped message if no replacement happened #: src/handlers/drag_drop_handler.py:447 msgid "{} files skipped" msgstr "{} fitxategi saltatu dira" #: src/handlers/file_dialog_handler.py:52 msgid "Default Patterns" msgstr "Eredu lehenetsiak" #: src/handlers/file_dialog_handler.py:92 #: src/handlers/file_dialog_handler.py:171 msgid "MIDI files" msgstr "MIDI fitxategiak" #: src/handlers/file_dialog_handler.py:98 msgid "Open MIDI File" msgstr "Ireki MIDI fitxategia" #: src/handlers/file_dialog_handler.py:127 msgid "Failed to open file" msgstr "Huts egin du fitxategia irekitzeak" #: src/handlers/file_dialog_handler.py:165 msgid "Failed to load pattern" msgstr "Huts egin du eredua kargatzeak" #: src/handlers/file_dialog_handler.py:179 msgid "Save Sequence" msgstr "Gorde sekuentzia" #: src/handlers/file_dialog_handler.py:205 msgid "Add Audio Samples" msgstr "Gehitu audio-laginak" #: src/handlers/file_dialog_handler.py:227 msgid "Audio files" msgstr "Audio-fitxategiak" #: src/utils/export_progress.py:76 msgid "Preparing…" msgstr "Prestatzen…" #: src/utils/export_progress.py:77 msgid "Initializing…" msgstr "Hasieratzen…" #: src/utils/export_progress.py:79 msgid "Rendering audio…" msgstr "Audioa errendatzen…" #: src/utils/export_progress.py:80 msgid "Processing beats…" msgstr "Kolpeak prozesatzen…" #: src/utils/export_progress.py:82 msgid "Saving file…" msgstr "Fitxategia gordetzen…" #: src/utils/export_progress.py:83 msgid "Writing to disk…" msgstr "Diskoan idazten…" #: src/utils/export_progress.py:85 msgid "Exporting…" msgstr "Esportatzen…" #: src/utils/export_progress.py:86 msgid "Processing…" msgstr "Prozesatzen…" #: src/utils/name_utils.py:36 msgid "Custom Sound" msgstr "Soinu pertsonalizatu" #: src/ui/drum_grid_builder.py:327 msgid "Preview" msgstr "Aurrebista" #: src/ui/drum_grid_builder.py:329 msgid "Replace…" msgstr "Ordeztu…" #: src/ui/drum_grid_builder.py:332 msgid "Replace with new sound" msgstr "Ordeztu soinu berriarekin" #: src/ui/drum_grid_builder.py:335 msgid "Remove" msgstr "Kendu" #: src/ui/drum_grid_builder.py:338 msgid "At least one drum part must remain" msgstr "Gutxienez danbor-atal bat mantendu behar da" #: src/ui/drum_grid_builder.py:345 msgid "Configure MIDI note for export" msgstr "Konfiguratu MIDI nota esportaziorako" #: src/ui/drum_grid_builder.py:402 msgid "MIDI note updated" msgstr "MIDI nota eguneratu da" #: src/ui/drum_grid_builder.py:410 msgid "Select New Sound" msgstr "Hautatu soinu berria" #: src/ui/drum_grid_builder.py:424 msgid "Removed drum part: {}" msgstr "Kendu danbor-atala: {}" #: src/ui/drum_grid_builder.py:429 msgid "Failed to remove drum part" msgstr "Huts egin du danbor-atala kentzeak" #. Update tooltip and accessibility with current BPM #: src/window.py:225 msgid "{} Beats per Minute (BPM)" msgstr "{} kolpe minutuko (BPM)" #. Update button tooltip to show current volume level #: src/window.py:234 msgid "{:.0f}% Volume" msgstr "{:.0f}% bolumena" #: src/window.py:251 src/window.ui:173 msgid "Play" msgstr "Erreproduzitu" #: src/window.py:255 msgid "Pause" msgstr "Pausatu" #: src/window.py:302 msgid "Open" msgstr "Ireki" #: src/window.py:320 msgid "Added: {}" msgstr "Gehitua: {}" #: src/window.py:335 msgid "Failed to add custom sound" msgstr "Huts egin du soinu pertsonalizatua gehitzeak" #: src/window.py:342 msgid "Replaced drum with: {}" msgstr "Ordeztu danborra honekin: {}" #: src/window.py:350 msgid "Failed to replace drum sound" msgstr "Huts egin du danbor-soinua ordezteak" #: src/window.ui:52 msgid "Open…" msgstr "Ireki…" #: src/window.ui:54 msgid "Open Pattern" msgstr "Ireki eredua" #: src/window.ui:57 msgctxt "accessibility" msgid "Open Pattern" msgstr "Ireki eredua" #: src/window.ui:58 msgid "Open Saved Drum Pattern" msgstr "Ireki gordetako danbor-eredua" #: src/window.ui:76 msgid "Main Menu" msgstr "Menu nagusia" #: src/window.ui:78 msgctxt "accessibility" msgid "Main Menu" msgstr "Menu nagusia" #: src/window.ui:79 msgid "Access Keyboard Shortcuts and Application Information" msgstr "Atzitu laster-teklak eta aplikazioaren informazioa" #: src/window.ui:86 msgid "Export Audio…" msgstr "Esportatu audioa…" #: src/window.ui:91 msgctxt "accessibility" msgid "Export Audio…" msgstr "Esportatu audioa…" #: src/window.ui:92 msgid "Export Current Drum Pattern as Audio File" msgstr "Esportatu uneko danbor-eredua audio-ftixategi gisa" #: src/window.ui:137 msgid "BPM" msgstr "BMP" #: src/window.ui:142 src/window.ui:146 msgid "Adjust Tempo In Beats per Minute (BPM)" msgstr "Doitu tempoa kolpeak minutukotan (BPM)" #: src/window.ui:145 msgid "Tempo" msgstr "Tempoa" #: src/window.ui:187 msgid "Adjust Volume" msgstr "Doitu bolumena" #: src/window.ui:210 msgid "Reset" msgstr "Berrezarri" #: src/window.ui:211 msgid "Reset the Drum Sequence" msgstr "Berrezarri danbor-sekuentzia" #: src/window.ui:226 msgid "_Add Samples…" msgstr "Gehitu _laginak…" #: src/window.ui:230 msgid "_Save Pattern…" msgstr "_Gorde eredua…" #: src/window.ui:236 msgid "_Keyboard Shortcuts" msgstr "Las_ter-teklak" #: src/window.ui:240 msgid "_About Drum Machine" msgstr "Drum Machine aplikazioari _buruz" #: src/gtk/help-overlay.blp:11 msgctxt "shortcut window" msgid "General" msgstr "Orokorra" #: src/gtk/help-overlay.blp:14 msgctxt "shortcut window" msgid "Show Shortcuts" msgstr "Erakutsi lasterbideak" #: src/gtk/help-overlay.blp:19 msgctxt "shortcut window" msgid "Quit" msgstr "Irten" #: src/gtk/help-overlay.blp:26 msgctxt "shortcut window" msgid "Playback Controls" msgstr "Erreprodukzio-kontrolak" #: src/gtk/help-overlay.blp:29 msgctxt "shortcut window" msgid "Play/Pause" msgstr "Erreproduzitu/pausarazi" #: src/gtk/help-overlay.blp:35 msgctxt "shortcut window" msgid "Clear All" msgstr "Garbitu denak" #: src/gtk/help-overlay.blp:42 msgctxt "shortcut window" msgid "BPM & Volume Controls" msgstr "BPMa eta bolumen-kontrolak" #: src/gtk/help-overlay.blp:45 msgctxt "shortcut window" msgid "Increase BPM" msgstr "Handitu BPMa" #: src/gtk/help-overlay.blp:51 msgctxt "shortcut window" msgid "Decrease BPM" msgstr "Txikitu BMPa" #: src/gtk/help-overlay.blp:57 msgctxt "shortcut window" msgid "Increase Volume" msgstr "Igo bolumena" #: src/gtk/help-overlay.blp:63 msgctxt "shortcut window" msgid "Decrease Volume" msgstr "Jaitsi bolumena" #: src/gtk/help-overlay.blp:69 msgctxt "shortcut window" msgid "Mute" msgstr "Mututu" #: src/gtk/help-overlay.blp:76 msgctxt "shortcut window" msgid "Pattern Management" msgstr "Eredu-kudeaketa" #: src/gtk/help-overlay.blp:79 msgctxt "shortcut window" msgid "Load Pattern" msgstr "Kargatu eredua" #: src/gtk/help-overlay.blp:85 msgctxt "shortcut window" msgid "Save Pattern" msgstr "Gorde eredua" #: src/gtk/help-overlay.blp:91 msgctxt "shortcut window" msgid "Export Audio" msgstr "Esportatu audioa" #: src/gtk/help-overlay.blp:98 msgctxt "shortcut window" msgid "Navigation" msgstr "Nabigazioa" #: src/gtk/help-overlay.blp:101 msgctxt "shortcut window" msgid "Go to Instrument" msgstr "Joan musika-tresnara" #: src/gtk/help-overlay.blp:107 msgctxt "shortcut window" msgid "Previous Page" msgstr "Aurreko orria" #: src/gtk/help-overlay.blp:113 msgctxt "shortcut window" msgid "Next Page" msgstr "Hurrengo orria" #: src/gtk/save-changes-dialog.blp:5 msgid "Save Changes?" msgstr "Gorde aldaketak?" #: src/gtk/save-changes-dialog.blp:6 msgid "" "Current pattern contains unsaved changes. Changes which are not saved will " "be permanently lost." msgstr "Uneko ereduak gorde gabeko aldaketak ditu. Gorde ez diren aldaketak betiko galduko dira." #. Translators: Cancel the operation #: src/gtk/save-changes-dialog.blp:14 msgid "_Cancel" msgstr "_Utzi" #. Translators: Discard all changes #: src/gtk/save-changes-dialog.blp:15 msgid "_Discard" msgstr "_Baztertu" #. Translators: Save current changes #: src/gtk/save-changes-dialog.blp:16 msgid "_Save" msgstr "_Gorde" #: src/gtk/audio-export-dialog.blp:6 src/gtk/audio-export-dialog.blp:101 msgid "Export Audio" msgstr "Esportatu audioa" #: src/gtk/audio-export-dialog.blp:44 msgid "Audio Format" msgstr "Aidio-formatua" #: src/gtk/audio-export-dialog.blp:50 msgid "Repeat Count" msgstr "Errepikatu zenbaketa" #: src/gtk/audio-export-dialog.blp:51 msgid "How many times to repeat the pattern" msgstr "Zenbat aldiz errepikatuko den eredua" #: src/gtk/audio-export-dialog.blp:64 msgid "Metadata" msgstr "Metadatuak" #: src/gtk/audio-export-dialog.blp:67 msgid "Artist Name" msgstr "Artistaren izena" #: src/gtk/audio-export-dialog.blp:72 msgid "Song Name" msgstr "Abestiaren izena" #: src/gtk/audio-export-dialog.blp:77 msgid "Cover Art" msgstr "Azala" #: src/gtk/audio-export-dialog.blp:81 msgid "Choose File…" msgstr "Aukeratu fitxategia…" #: src/gtk/audio-export-dialog.blp:110 msgid "Cancel Export" msgstr "Utzi esportazioa" #~ msgid "No Pattern" #~ msgstr "Eredurik ez" #~ msgid "Please create a drum pattern before exporting audio." #~ msgstr "Sortu danbor-eredua audioa esportatu baino lehen." #~ msgid "_OK" #~ msgstr "_Ados" #~ msgctxt "accessibility" #~ msgid "Open Preset" #~ msgstr "Ireki aurrezarpena" #~ msgctxt "accessibility" #~ msgid "Export Audio" #~ msgstr "Esportatu audioa" #~ msgctxt "shortcut window" #~ msgid "Load Preset" #~ msgstr "Kargatu aurrezarpena" #~ msgctxt "shortcut window" #~ msgid "Save Preset" #~ msgstr "Gorde aurrezarpena" drum-machine-2.2.0/po/fa.po000066400000000000000000000565171514070543000154450ustar00rootroot00000000000000# Persian translation for drum-machine. # Copyright (C) 2025 drum-machine's COPYRIGHT HOLDER # This file is distributed under the same license as the drum-machine package. # میر سبحان , 2025. # Danial Behzadi , 2025. # msgid "" msgstr "" "Project-Id-Version: drum-machine master\n" "Report-Msgid-Bugs-To: https://github.com/revisto/drum-machine/issues\n" "POT-Creation-Date: 2025-11-26 03:26+0000\n" "PO-Revision-Date: 2025-11-26 13:48+0330\n" "Last-Translator: Danial Behzadi \n" "Language-Team: Persian\n" "Language: fa\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: Poedit 3.8\n" "X-DL-Lang: fa\n" "X-DL-Module: drum-machine\n" "X-DL-Branch: master\n" "X-DL-Domain: po\n" "X-DL-State: None\n" #: data/io.github.revisto.drum-machine.desktop.in:2 #: data/io.github.revisto.drum-machine.metainfo.xml.in:6 src/application.py:67 #: src/window.ui:69 msgid "Drum Machine" msgstr "ماشین درام" #. Translators: Search terms to find this application. Do NOT translate or localise the semicolons! The list MUST also end with a semicolon! #: data/io.github.revisto.drum-machine.desktop.in:9 msgid "drum;drums;sequencer;rhythm;music;pattern;beats;percussion;loop;groove;" msgstr "" "drum;drums;sequencer;rhythm;music;pattern;beats;percussion;loop;groove;drum " "machine;درام;کوبه;کوبش;طبل;سنج;ریتم;آهنگ;موسیقی;الگو;پرکاشن;" #: data/io.github.revisto.drum-machine.metainfo.xml.in:7 msgid "Create and play drum beats" msgstr "ایجاد و پخش ضرب‌های کوبه‌ای" #: data/io.github.revisto.drum-machine.metainfo.xml.in:9 msgid "" "Drum Machine is a modern and intuitive application for creating, playing, and " "managing drum patterns. Perfect for musicians, producers, and anyone " "interested in rhythm creation, this application provides a simple interface " "for drum pattern programming. Have fun!" msgstr "" "ماشین درام برنامه‌ای نوین و ادراکی برای ایجاد، پخش و مدیریت الگوهای کوبه‌ای " "است. این برنامه که مناسب آهنگسازان، تهیه‌کنندگان و هرکسی در تولید ضرباهنگ است، " "میانایی ساده برای برنامه ریزی الگوهای کوبه‌ای فراهم می‌کند. خوش بگذرانید!" #: data/io.github.revisto.drum-machine.metainfo.xml.in:15 msgid "Features:" msgstr "ویژگی‌ها:" #: data/io.github.revisto.drum-machine.metainfo.xml.in:17 msgid "Intuitive grid-based pattern editor" msgstr "ویرایشگر ادراکی الگوی مبتنی بر شبکه" #: data/io.github.revisto.drum-machine.metainfo.xml.in:18 msgid "Adjustable BPM control" msgstr "واپایش ض‌د‌د تنظیم‌پذیر" #: data/io.github.revisto.drum-machine.metainfo.xml.in:19 msgid "Volume control for overall mix" msgstr "واپایش حجم صدا برای تنظیم کلی" #: data/io.github.revisto.drum-machine.metainfo.xml.in:20 msgid "Save and load patterns" msgstr "ذخیره و بار کردن الگوها" #: data/io.github.revisto.drum-machine.metainfo.xml.in:21 msgid "Multiple drum sounds including kick, snare, hi-hat, and more" msgstr "چندین صدای کوبه‌ای از جمله دهل، طبل، سنج و بیش‌تر" #: data/io.github.revisto.drum-machine.metainfo.xml.in:22 msgid "Audio export feature with support for WAV, FLAC, Ogg, and MP3 formats" msgstr "قابلیت خروجی صوتی با پشتیبانی از قالب‌های WAV، ‏FLAC، ‏Ogg و MP3" #: data/io.github.revisto.drum-machine.metainfo.xml.in:23 msgid "Metadata support for embedding artist name, song title, and cover art" msgstr "پشتیبانی از فراداده برای جاسازی نام هنرمند، عنوان آهنگ و طرح جلد" #: data/io.github.revisto.drum-machine.metainfo.xml.in:24 msgid "Keyboard shortcuts for quick access to all functions" msgstr "میان‌برهای صفحه‌کلید برای دسترسی سریع به همهٔ ویژگی‌ها" #: data/io.github.revisto.drum-machine.metainfo.xml.in:33 msgid "Drum Pattern Loaded in Light Mode" msgstr "الگوی کوبه‌ای بار شده در حالت روشن" #: data/io.github.revisto.drum-machine.metainfo.xml.in:37 msgid "Drum Pattern Loaded in Dark Mode" msgstr "الگوی کوبه‌ای بار شده در حالت تیره" #: src/application.py:74 msgid "" "Drum Machine is a modern and intuitive application for creating, playing, and " "managing drum patterns." msgstr "" "ماشین درام برنامه‌ای نوین و ادراکی برای ایجاد، پخش و مدیریت الگوهای کوبه‌ای است." #: src/application.py:79 msgid "translator-credits" msgstr "دانیال بهزادی " #: src/application.py:84 msgid "Special thanks" msgstr "سپاس ویژه" #: src/application.py:87 msgid "Sounds" msgstr "صداها" #: src/application.py:88 #, python-brace-format msgid "The drum samples used in this application are from {link}." msgstr "منبع نمونه‌های کوبی استفاده شده در این برنامه: {link}." #: src/config/export_formats.py:44 msgid "MP3 files" msgstr "پرونده‌های MP3" #: src/config/export_formats.py:45 msgid "MP3" msgstr "ام‌پی‌تری" #: src/config/export_formats.py:51 msgid "FLAC files" msgstr "پرونده‌های FLAC" #: src/config/export_formats.py:52 msgid "FLAC (Lossless)" msgstr "فلک (بدون کاهش کیفیت)" #: src/config/export_formats.py:58 msgid "Ogg files" msgstr "پرونده‌های Ogg" #: src/config/export_formats.py:59 msgid "Ogg Vorbis" msgstr "وربیس اوگ" #: src/config/export_formats.py:65 msgid "WAV files" msgstr "پرونده‌های WAV" #: src/config/export_formats.py:66 msgid "WAV (Uncompressed)" msgstr "ویو (فشرده نشده)" #: src/dialogs/audio_export_dialog.py:119 msgid "Save Audio File" msgstr "ذخیره پرونده صدا" #: src/dialogs/audio_export_dialog.py:148 msgid "Part “{}” is Silent" msgstr "بخش «{}» صامت است" #: src/dialogs/audio_export_dialog.py:150 msgid "Parts “{}” and “{}” are Silent" msgstr "بخش‌های «{}» و «{}» صامتند" #: src/dialogs/audio_export_dialog.py:154 msgid "{} Parts are Silent" msgstr "‏{} بخش صامتند" #: src/dialogs/audio_export_dialog.py:179 msgid "Image files" msgstr "پرونده‌های تصویر" #: src/dialogs/audio_export_dialog.py:185 msgid "Select Cover Art" msgstr "گزینش طرح جلد" #: src/dialogs/audio_export_dialog.py:245 msgid "Audio exported to {}" msgstr "صدا برون‌ریزی شد به {}" #: src/dialogs/audio_export_dialog.py:251 msgid "Export failed" msgstr "برون‌ریزی شکست خورد" #: src/dialogs/audio_export_dialog.py:258 msgid "Export cancelled successfully" msgstr "برون‌ریزی به طور موفق لغو شد" #: src/dialogs/midi_mapping_dialog.py:22 msgid "Acoustic Bass Drum" msgstr "" #: src/dialogs/midi_mapping_dialog.py:23 msgid "Bass Drum 1" msgstr "" #: src/dialogs/midi_mapping_dialog.py:24 msgid "Side Stick" msgstr "" #: src/dialogs/midi_mapping_dialog.py:25 msgid "Acoustic Snare" msgstr "" #: src/dialogs/midi_mapping_dialog.py:26 msgid "Hand Clap" msgstr "" #: src/dialogs/midi_mapping_dialog.py:27 msgid "Electric Snare" msgstr "" #: src/dialogs/midi_mapping_dialog.py:28 msgid "Low Floor Tom" msgstr "" #: src/dialogs/midi_mapping_dialog.py:29 msgid "Closed Hi Hat" msgstr "" #: src/dialogs/midi_mapping_dialog.py:30 msgid "High Floor Tom" msgstr "" #: src/dialogs/midi_mapping_dialog.py:31 msgid "Pedal Hi Hat" msgstr "" #: src/dialogs/midi_mapping_dialog.py:32 msgid "Low Tom" msgstr "" #: src/dialogs/midi_mapping_dialog.py:33 msgid "Open Hi Hat" msgstr "" #: src/dialogs/midi_mapping_dialog.py:34 msgid "Low-Mid Tom" msgstr "" #: src/dialogs/midi_mapping_dialog.py:35 msgid "Hi-Mid Tom" msgstr "" #: src/dialogs/midi_mapping_dialog.py:36 msgid "Crash Cymbal 1" msgstr "" #: src/dialogs/midi_mapping_dialog.py:37 msgid "High Tom" msgstr "" #: src/dialogs/midi_mapping_dialog.py:38 msgid "Ride Cymbal 1" msgstr "" #: src/dialogs/midi_mapping_dialog.py:39 msgid "Chinese Cymbal" msgstr "" #: src/dialogs/midi_mapping_dialog.py:40 msgid "Ride Bell" msgstr "" #: src/dialogs/midi_mapping_dialog.py:41 msgid "Tambourine" msgstr "" #: src/dialogs/midi_mapping_dialog.py:42 msgid "Splash Cymbal" msgstr "" #: src/dialogs/midi_mapping_dialog.py:43 msgid "Cowbell" msgstr "" #: src/dialogs/midi_mapping_dialog.py:44 msgid "Crash Cymbal 2" msgstr "" #: src/dialogs/midi_mapping_dialog.py:45 msgid "Vibraslap" msgstr "" #: src/dialogs/midi_mapping_dialog.py:46 msgid "Ride Cymbal 2" msgstr "" #: src/dialogs/midi_mapping_dialog.py:47 msgid "Hi Bongo" msgstr "" #: src/dialogs/midi_mapping_dialog.py:48 msgid "Low Bongo" msgstr "" #: src/dialogs/midi_mapping_dialog.py:49 msgid "Mute Hi Conga" msgstr "" #: src/dialogs/midi_mapping_dialog.py:50 msgid "Open Hi Conga" msgstr "" #: src/dialogs/midi_mapping_dialog.py:51 msgid "Low Conga" msgstr "" #: src/dialogs/midi_mapping_dialog.py:52 msgid "High Timbale" msgstr "" #: src/dialogs/midi_mapping_dialog.py:53 msgid "Low Timbale" msgstr "" #: src/dialogs/midi_mapping_dialog.py:54 msgid "High Agogo" msgstr "" #: src/dialogs/midi_mapping_dialog.py:55 msgid "Low Agogo" msgstr "" #: src/dialogs/midi_mapping_dialog.py:56 msgid "Cabasa" msgstr "" #: src/dialogs/midi_mapping_dialog.py:57 msgid "Maracas" msgstr "" #: src/dialogs/midi_mapping_dialog.py:58 msgid "Short Whistle" msgstr "" #: src/dialogs/midi_mapping_dialog.py:59 msgid "Long Whistle" msgstr "" #: src/dialogs/midi_mapping_dialog.py:60 msgid "Short Guiro" msgstr "" #: src/dialogs/midi_mapping_dialog.py:61 msgid "Long Guiro" msgstr "" #: src/dialogs/midi_mapping_dialog.py:62 msgid "Claves" msgstr "" #: src/dialogs/midi_mapping_dialog.py:63 msgid "Hi Wood Block" msgstr "" #: src/dialogs/midi_mapping_dialog.py:64 msgid "Low Wood Block" msgstr "" #: src/dialogs/midi_mapping_dialog.py:65 msgid "Mute Cuica" msgstr "" #: src/dialogs/midi_mapping_dialog.py:66 msgid "Open Cuica" msgstr "" #: src/dialogs/midi_mapping_dialog.py:67 msgid "Mute Triangle" msgstr "" #: src/dialogs/midi_mapping_dialog.py:68 msgid "Open Triangle" msgstr "" #: src/dialogs/midi_mapping_dialog.py:78 src/ui/drum_grid_builder.py:338 msgid "MIDI Mapping" msgstr "نگاشت MIDI" #. Group 1: Note Assignment #: src/dialogs/midi_mapping_dialog.py:108 msgid "Note Assignment" msgstr "تخصیص نت" #: src/dialogs/midi_mapping_dialog.py:111 msgid "" "Assign a MIDI note for '{}'. This ensures correct playback when exporting." msgstr "تخصیص نت MIDI برای «{}». برای اطمینان از پخش درست هنگام برون‌ریزی." #. Action Row for Note #: src/dialogs/midi_mapping_dialog.py:118 msgid "MIDI Note" msgstr "نت MIDI" #: src/dialogs/midi_mapping_dialog.py:119 msgid "The note number to trigger" msgstr "" #. Group 2: Standard Instruments #: src/dialogs/midi_mapping_dialog.py:137 msgid "Standard Instruments" msgstr "ساز استاندارد" #: src/dialogs/midi_mapping_dialog.py:139 msgid "Select a General MIDI instrument to automatically set the note." msgstr "گزینش ساز MIDI عمومی برای تنظیم خودکار نت" #: src/dialogs/midi_mapping_dialog.py:143 msgid "Instrument Preset" msgstr "پیش‌تنظیم ساز" #: src/dialogs/midi_mapping_dialog.py:186 msgid "Save" msgstr "ذخیره" #: src/dialogs/midi_mapping_dialog.py:229 msgid "Custom Note" msgstr "نت سفارشی" #: src/handlers/drag_drop_handler.py:113 msgid "Sound replaced" msgstr "صدا جایگزین شد" #: src/handlers/drag_drop_handler.py:116 msgid "Failed to replace sound" msgstr "شکست در جایگزینی صدا" #: src/handlers/drag_drop_handler.py:126 msgid "Not a supported audio file" msgstr "پروندهٔ صوتی پشتیبانی نشده" #: src/handlers/drag_drop_handler.py:134 msgid "File not found" msgstr "پرونده پیدا نشد" #: src/handlers/drag_drop_handler.py:139 msgid "Selected item is not a file" msgstr "ان‌چه گزیده شده پرونده نیست" #: src/handlers/drag_drop_handler.py:146 msgid "File too large: {:.1f}MB (max 50MB)" msgstr "پرونده بیش از حد بزرگ؛ {:.1f}م‌ب (بیشینه ۵۰م‌ب)" #: src/handlers/drag_drop_handler.py:174 msgid "No valid audio files found" msgstr "هیچ پروندهٔ صوتی معتبری پیدا نشد" #: src/handlers/drag_drop_handler.py:209 msgid "Error processing file: {}" msgstr "خطا در پردازش پرونده: {}" #: src/handlers/drag_drop_handler.py:237 msgid "Added {} drum part, {} files skipped" msgstr "" #: src/handlers/drag_drop_handler.py:243 msgid "Added {} drum parts, {} files skipped" msgstr "" #: src/handlers/drag_drop_handler.py:248 msgid "Added {} drum parts" msgstr "" #. Only show skipped message if no replacement happened #: src/handlers/drag_drop_handler.py:251 msgid "{} files skipped" msgstr "از {} پرونده پریده شد" #: src/handlers/file_dialog_handler.py:52 msgid "Default Patterns" msgstr "الگوهای پیش‌گزیده" #: src/handlers/file_dialog_handler.py:84 msgid "No Pattern" msgstr "بدون الگو" #: src/handlers/file_dialog_handler.py:85 msgid "Please create a drum pattern before exporting audio." msgstr "ایجاد الگوی کوبه‌ای پیش از برون‌ریزی صدا." #: src/handlers/file_dialog_handler.py:87 msgid "_OK" msgstr "_تأیید" #: src/handlers/file_dialog_handler.py:110 #: src/handlers/file_dialog_handler.py:187 msgid "MIDI files" msgstr "پرونده‌های MIDI" #: src/handlers/file_dialog_handler.py:116 msgid "Open MIDI File" msgstr "گشودن پروندهٔ MIDI" #: src/handlers/file_dialog_handler.py:144 msgid "Failed to open file" msgstr "شکست در گشودن پرونده" #: src/handlers/file_dialog_handler.py:181 msgid "Failed to load pattern" msgstr "شکست در بار کردن الگو" #: src/handlers/file_dialog_handler.py:195 msgid "Save Sequence" msgstr "ذخیرهٔ دنباله" #: src/handlers/file_dialog_handler.py:221 msgid "Add Audio Samples" msgstr "افزودن نمونه‌های صوتی" #: src/handlers/file_dialog_handler.py:243 msgid "Audio files" msgstr "پرونده‌های صوتی" #: src/utils/export_progress.py:76 msgid "Preparing…" msgstr "آماده سازی…" #: src/utils/export_progress.py:77 msgid "Initializing…" msgstr "مقدار دهی نخستین…" #: src/utils/export_progress.py:79 msgid "Rendering audio…" msgstr "پرداخت کردن صدا…" #: src/utils/export_progress.py:80 msgid "Processing beats…" msgstr "پردازش کردن ضرب‌ها…" #: src/utils/export_progress.py:82 msgid "Saving file…" msgstr "ذخیره کردن پرونده…" #: src/utils/export_progress.py:83 msgid "Writing to disk…" msgstr "نوشتن روی دیسک…" #: src/utils/export_progress.py:85 msgid "Exporting…" msgstr "برون ریختن…" #: src/utils/export_progress.py:86 msgid "Processing…" msgstr "پردازش کردن…" #: src/utils/name_utils.py:36 msgid "Custom Sound" msgstr "صدای سفارشی" #: src/ui/drum_grid_builder.py:323 msgid "Preview" msgstr "پیش‌نمایش" #: src/ui/drum_grid_builder.py:325 msgid "Replace…" msgstr "جایگزینی…" #: src/ui/drum_grid_builder.py:328 msgid "Replace with new sound" msgstr "جایگزینی با صدای جدید" #: src/ui/drum_grid_builder.py:331 msgid "Remove" msgstr "برداشتن" #: src/ui/drum_grid_builder.py:334 msgid "At least one drum part must remain" msgstr "" #: src/ui/drum_grid_builder.py:341 msgid "Configure MIDI note for export" msgstr "پیکربندی نت MIDI برای برون‌ریزی" #: src/ui/drum_grid_builder.py:398 msgid "MIDI note updated" msgstr "نت MIDI به‌روز شد" #: src/ui/drum_grid_builder.py:406 msgid "Select New Sound" msgstr "گزینش صدای جدید" #: src/ui/drum_grid_builder.py:420 msgid "Removed drum part: {}" msgstr "" #: src/ui/drum_grid_builder.py:424 msgid "Failed to remove drum part" msgstr "" #. Update tooltip and accessibility with current BPM #: src/window.py:203 msgid "{} Beats per Minute (BPM)" msgstr "{} ضرب در دقیقه (ض‌دد)" #. Update button tooltip to show current volume level #: src/window.py:212 msgid "{:.0f}% Volume" msgstr "{:I.0f}% حجم صدا" #: src/window.py:227 src/window.ui:170 msgid "Play" msgstr "پخش" #: src/window.py:231 msgid "Pause" msgstr "مکث" #: src/window.py:278 msgid "Open" msgstr "گشودن" #: src/window.py:296 msgid "Added: {}" msgstr "افزوده: {}" #: src/window.py:311 msgid "Failed to add custom sound" msgstr "شکست در افزودن صدای سفارشی" #: src/window.py:318 msgid "Replaced drum with: {}" msgstr "" #: src/window.py:326 msgid "Failed to replace drum sound" msgstr "" #: src/window.ui:52 msgid "Open…" msgstr "گشودن…" #: src/window.ui:54 msgid "Open Pattern" msgstr "گشودن الگو" #: src/window.ui:57 msgctxt "accessibility" msgid "Open Pattern" msgstr "گشودن الگو" #: src/window.ui:58 msgid "Open Saved Drum Pattern" msgstr "گشودن الگوی کوبه‌ای ذخیره شده" #: src/window.ui:76 msgid "Main Menu" msgstr "فهرست اصلی" #: src/window.ui:78 msgctxt "accessibility" msgid "Main Menu" msgstr "فهرست اصلی" #: src/window.ui:79 msgid "Access Keyboard Shortcuts and Application Information" msgstr "دسترسی به اطّلاعات برنامه و میان‌برهای صفحه‌کلید" #: src/window.ui:86 msgid "Export Audio…" msgstr "برون‌ریزی صدا…" #: src/window.ui:88 msgctxt "accessibility" msgid "Export Audio…" msgstr "برون‌ریزی صدا…" #: src/window.ui:89 msgid "Export Current Drum Pattern as Audio File" msgstr "ذخیرهٔ الگوی کوبه‌ای کنونی به شکل پروندهٔ صوتی" #: src/window.ui:134 msgid "BPM" msgstr "ض‌دد" #: src/window.ui:139 src/window.ui:143 msgid "Adjust Tempo In Beats per Minute (BPM)" msgstr "تنظیم سرعت بر اساس ضرب در دقیقه (ض‌دد)" #: src/window.ui:142 msgid "Tempo" msgstr "سرعت" #: src/window.ui:184 msgid "Adjust Volume" msgstr "تنظیم حجم صدا" #: src/window.ui:207 msgid "Reset" msgstr "بازنشانی" #: src/window.ui:208 msgid "Reset the Drum Sequence" msgstr "بازنشانی دنبالهٔ کوبه‌ای" #: src/window.ui:223 msgid "_Add Samples…" msgstr "_افزودن نمونه‌ها…" #: src/window.ui:227 msgid "_Save Pattern…" msgstr "_ذخیرهٔ الگو…" #: src/window.ui:233 msgid "_Keyboard Shortcuts" msgstr "_میان‌برهای صفحه‌کلید" #: src/window.ui:237 msgid "_About Drum Machine" msgstr "_دربارهٔ ماشین درام" #: src/gtk/help-overlay.blp:11 msgctxt "shortcut window" msgid "General" msgstr "عمومی" #: src/gtk/help-overlay.blp:14 msgctxt "shortcut window" msgid "Show Shortcuts" msgstr "نمایش میان‌برها" #: src/gtk/help-overlay.blp:19 msgctxt "shortcut window" msgid "Quit" msgstr "خروج" #: src/gtk/help-overlay.blp:26 msgctxt "shortcut window" msgid "Playback Controls" msgstr "واپایش‌های پخش" #: src/gtk/help-overlay.blp:29 msgctxt "shortcut window" msgid "Play/Pause" msgstr "پخش/مکث" #: src/gtk/help-overlay.blp:35 msgctxt "shortcut window" msgid "Clear All" msgstr "پاک‌سازی همه" #: src/gtk/help-overlay.blp:42 msgctxt "shortcut window" msgid "BPM & Volume Controls" msgstr "واپایش‌های حجم صدا و ض‌د‌د" #: src/gtk/help-overlay.blp:45 msgctxt "shortcut window" msgid "Increase BPM" msgstr "افزایش ض‌دد" #: src/gtk/help-overlay.blp:51 msgctxt "shortcut window" msgid "Decrease BPM" msgstr "کاهش ض‌دد" #: src/gtk/help-overlay.blp:57 msgctxt "shortcut window" msgid "Increase Volume" msgstr "افزایش حجم صدا" #: src/gtk/help-overlay.blp:63 msgctxt "shortcut window" msgid "Decrease Volume" msgstr "کاهش حجم صدا" #: src/gtk/help-overlay.blp:69 msgctxt "shortcut window" msgid "Mute" msgstr "خموش" #: src/gtk/help-overlay.blp:76 msgctxt "shortcut window" msgid "Pattern Management" msgstr "مدیریت الگو" #: src/gtk/help-overlay.blp:79 msgctxt "shortcut window" msgid "Load Pattern" msgstr "بار کردن الگو" #: src/gtk/help-overlay.blp:85 msgctxt "shortcut window" msgid "Save Pattern" msgstr "ذخیرهٔ الگو" #: src/gtk/help-overlay.blp:91 msgctxt "shortcut window" msgid "Export Audio" msgstr "برون‌ریزی صدا" #: src/gtk/help-overlay.blp:98 msgctxt "shortcut window" msgid "Navigation" msgstr "پیمایش" #: src/gtk/help-overlay.blp:101 msgctxt "shortcut window" msgid "Go to Instrument" msgstr "رفتن به ساز" #: src/gtk/help-overlay.blp:107 msgctxt "shortcut window" msgid "Previous Page" msgstr "صفحهٔ پیشین" #: src/gtk/help-overlay.blp:113 msgctxt "shortcut window" msgid "Next Page" msgstr "صفحهٔ بعدی" #: src/gtk/save-changes-dialog.blp:5 msgid "Save Changes?" msgstr "ذخیرهٔ تغییرات؟" #: src/gtk/save-changes-dialog.blp:6 msgid "" "Current pattern contains unsaved changes. Changes which are not saved will be " "permanently lost." msgstr "" "الگوی کنونی تغییراتی ذخیره نشده دارد. تغییراتی که ذخیره نشده‌اند برای همیشه از " "دست خواهند رفت." #. Translators: Cancel the operation #: src/gtk/save-changes-dialog.blp:14 msgid "_Cancel" msgstr "_لغو" #. Translators: Discard all changes #: src/gtk/save-changes-dialog.blp:15 msgid "_Discard" msgstr "_دور انداختن" #. Translators: Save current changes #: src/gtk/save-changes-dialog.blp:16 msgid "_Save" msgstr "_ذخیره" #: src/gtk/audio-export-dialog.blp:6 src/gtk/audio-export-dialog.blp:101 msgid "Export Audio" msgstr "برون‌ریزی صدا" #: src/gtk/audio-export-dialog.blp:44 msgid "Audio Format" msgstr "قالب صدا" #: src/gtk/audio-export-dialog.blp:50 msgid "Repeat Count" msgstr "تعداد تکرار" #: src/gtk/audio-export-dialog.blp:51 msgid "How many times to repeat the pattern" msgstr "چند دفعه الگو تکرار شود" #: src/gtk/audio-export-dialog.blp:64 msgid "Metadata" msgstr "فراداده" #: src/gtk/audio-export-dialog.blp:67 msgid "Artist Name" msgstr "نام هنرمند" #: src/gtk/audio-export-dialog.blp:72 msgid "Song Name" msgstr "نام آهنگ" #: src/gtk/audio-export-dialog.blp:77 msgid "Cover Art" msgstr "طرح جلد" #: src/gtk/audio-export-dialog.blp:81 msgid "Choose File…" msgstr "گزینش پرونده…" #: src/gtk/audio-export-dialog.blp:110 msgid "Cancel Export" msgstr "لغو برون‌ریزی" #~ msgctxt "accessibility" #~ msgid "Open Preset" #~ msgstr "گشودن پیش‌تنظیم" #~ msgctxt "accessibility" #~ msgid "Export Audio" #~ msgstr "برون‌ریزی صدا" #~ msgctxt "shortcut window" #~ msgid "Load Preset" #~ msgstr "بار کردن پیش‌تنظیم" #~ msgctxt "shortcut window" #~ msgid "Save Preset" #~ msgstr "ذخیرهٔ پیش‌تنظیم" #~ msgid "Export Settings" #~ msgstr "برون‌ریزی تنظیمات" #~ msgid "Select the output audio format" #~ msgstr "قالب خروجی صدا را بگزینید" #~ msgid "Add metadata to your exported audio" #~ msgstr "افزودن فراداده به صدای برون‌ریزی شده‌تان" #~ msgid "Select an image file for the cover art" #~ msgstr "یک نگاره را برای طرح جلد بگزینید" drum-machine-2.2.0/po/fi.po000066400000000000000000000300651514070543000154430ustar00rootroot00000000000000# Finnish translation for drum-machine. # Copyright (C) 2025 drum-machine's COPYRIGHT HOLDER # This file is distributed under the same license as the drum-machine package. # Jiri Grönroos , 2025. # msgid "" msgstr "" "Project-Id-Version: drum-machine master\n" "Report-Msgid-Bugs-To: https://github.com/revisto/drum-machine/issues\n" "POT-Creation-Date: 2025-09-13 15:26+0000\n" "PO-Revision-Date: 2025-09-13 19:48+0300\n" "Last-Translator: Jiri Grönroos \n" "Language-Team: Finnish \n" "Language: fi\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Poedit 3.7\n" #: data/io.github.revisto.drum-machine.desktop.in:2 #: data/io.github.revisto.drum-machine.metainfo.xml.in:6 src/window.ui:69 msgid "Drum Machine" msgstr "Rumpukone" #: data/io.github.revisto.drum-machine.metainfo.xml.in:7 msgid "Create and play drum beats" msgstr "Luo ja toista rumpubiittejä" #: data/io.github.revisto.drum-machine.metainfo.xml.in:9 msgid "" "Drum Machine is a modern and intuitive application for creating, playing, " "and managing drum patterns. Perfect for musicians, producers, and anyone " "interested in rhythm creation, this application provides a simple interface " "for drum pattern programming. Have fun!" msgstr "" "Drum Machine (Rumpukone) on moderni ja intuitiivinen sovellus rumpukuvioiden " "luomiseen, toistamiseen ja hallintaan. Se on täydellinen muusikoille, " "tuottajille ja kenelle tahansa rytmien luomisesta kiinnostuneelle. Sovellus " "tarjoaa yksinkertaisen käyttöliittymän rumpukuvioiden luomiseen. Pidä " "hauskaa!" #: data/io.github.revisto.drum-machine.metainfo.xml.in:15 msgid "Features:" msgstr "Ominaisuudet:" #: data/io.github.revisto.drum-machine.metainfo.xml.in:17 msgid "Intuitive grid-based pattern editor" msgstr "Intuitiivinen ruudukkopohjainen kuviomuokkain" #: data/io.github.revisto.drum-machine.metainfo.xml.in:18 msgid "Adjustable BPM control" msgstr "Säädettävä BPM" #: data/io.github.revisto.drum-machine.metainfo.xml.in:19 msgid "Volume control for overall mix" msgstr "Äänenvoimakkuuden kokonaisvaltainen säätö" #: data/io.github.revisto.drum-machine.metainfo.xml.in:20 msgid "Save and load preset patterns" msgstr "Tallenna ja lataa kuvioiden esiasetuksia" #: data/io.github.revisto.drum-machine.metainfo.xml.in:21 msgid "Multiple drum sounds including kick, snare, hi-hat, and more" msgstr "Lukuisia rumpuääniä kuten potku, pikkurumpu, hi-hat ja paljon muuta" #: data/io.github.revisto.drum-machine.metainfo.xml.in:22 msgid "Audio export feature with support for WAV, FLAC, Ogg, and MP3 formats" msgstr "Äänen vientitoiminto, tuetut muodot ovat WAV, FLAC, Ogg ja MP3" #: data/io.github.revisto.drum-machine.metainfo.xml.in:23 msgid "Metadata support for embedding artist name, song title, and cover art" msgstr "" "Tuki metatiedoille, kuten esittäjän nimen, kappaleen nimen ja kansikuvan " "upottaminen" #: data/io.github.revisto.drum-machine.metainfo.xml.in:24 msgid "Keyboard shortcuts for quick access to all functions" msgstr "Pikanäppäimet mahdollistavat kaikkien toimintojen käytön" #: data/io.github.revisto.drum-machine.metainfo.xml.in:33 msgid "Drum Pattern Loaded in Light Mode" msgstr "Rumpukuvio ladattu, vaalea tila" #: data/io.github.revisto.drum-machine.metainfo.xml.in:37 msgid "Drum Pattern Loaded in Dark Mode" msgstr "Rumpukuvio ladattu, tumma tila" #: src/application.py:69 msgid "translator-credits" msgstr "Jiri Grönroos" #: src/config/export_formats.py:43 msgid "MP3 files" msgstr "MP3-tiedostot" #: src/config/export_formats.py:44 msgid "MP3" msgstr "MP3" #: src/config/export_formats.py:50 msgid "FLAC files" msgstr "FLAC-tiedostot" #: src/config/export_formats.py:51 msgid "FLAC (Lossless)" msgstr "FLAC (häviötön)" #: src/config/export_formats.py:57 msgid "Ogg files" msgstr "Ogg-tiedostot" #: src/config/export_formats.py:58 #| msgid "OGG Vorbis" msgid "Ogg Vorbis" msgstr "Ogg Vorbis" #: src/config/export_formats.py:64 msgid "WAV files" msgstr "WAV-tiedostot" #: src/config/export_formats.py:65 msgid "WAV (Uncompressed)" msgstr "WAV (pakkaamaton)" #: src/dialogs/audio_export_dialog.py:104 msgid "Save Audio File" msgstr "Tallenna äänitiedosto" #: src/dialogs/audio_export_dialog.py:128 msgid "Image files" msgstr "Kuvatiedostot" #: src/dialogs/audio_export_dialog.py:134 msgid "Select Cover Art" msgstr "Valitse kansikuva" #: src/dialogs/audio_export_dialog.py:191 msgid "Audio exported to {}" msgstr "Ääni viety tiedostoon {}" #: src/dialogs/audio_export_dialog.py:196 msgid "Export failed" msgstr "Vienti epäonnistui" #: src/dialogs/audio_export_dialog.py:203 msgid "Export cancelled successfully" msgstr "Vienti peruttu" #: src/handlers/file_dialog_handler.py:50 msgid "Default Presets" msgstr "Oletusarvoiset esiasetukset" #: src/handlers/file_dialog_handler.py:82 msgid "No Pattern" msgstr "Ei kuviota" #: src/handlers/file_dialog_handler.py:83 msgid "Please create a drum pattern before exporting audio." msgstr "Luo rumpukuvio ennen äänen vientiä." #: src/handlers/file_dialog_handler.py:85 msgid "_OK" msgstr "_OK" #: src/handlers/file_dialog_handler.py:107 #: src/handlers/file_dialog_handler.py:173 msgid "MIDI files" msgstr "MIDI-tiedostot" #: src/handlers/file_dialog_handler.py:113 msgid "Open MIDI File" msgstr "Avaa MIDI-tiedosto" #: src/handlers/file_dialog_handler.py:179 msgid "Save Sequence" msgstr "Tallenna sekvenssi" #: src/utils/export_progress.py:68 msgid "Preparing..." msgstr "Valmistellaan…" #: src/utils/export_progress.py:69 msgid "Initializing..." msgstr "Alustetaan…" #: src/utils/export_progress.py:71 msgid "Rendering audio..." msgstr "Renderöidään ääntä…" #: src/utils/export_progress.py:72 msgid "Processing beats..." msgstr "Käsitellään iskuja…" #: src/utils/export_progress.py:74 msgid "Saving file..." msgstr "Tallennetaan tiedostoa…" #: src/utils/export_progress.py:75 msgid "Writing to disk..." msgstr "Kirjoitetaan levylle…" #: src/utils/export_progress.py:77 msgid "Exporting..." msgstr "Viedään…" #: src/utils/export_progress.py:78 msgid "Processing..." msgstr "Käsitellään…" #. Update tooltip and accessibility with current BPM #: src/window.py:198 msgid "{} Beats per Minute (BPM)" msgstr "{} iskua minuutissa (BPM)" #. Update button tooltip to show current volume level #: src/window.py:207 msgid "{:.0f}% Volume" msgstr "{:.0f}% äänenvoimakkuus" #: src/window.py:222 src/window.ui:170 msgid "Play" msgstr "Toista" #: src/window.py:226 msgid "Pause" msgstr "Keskeytä" #: src/window.py:264 src/window.ui:52 msgid "Open" msgstr "Avaa" #: src/window.ui:54 msgid "Open Preset" msgstr "Avaa esiasetus" #: src/window.ui:57 msgctxt "accessibility" msgid "Open Preset" msgstr "Avaa esiasetus" #: src/window.ui:58 msgid "Open Saved Drum Pattern Preset" msgstr "Avaa tallennettu rumpukuvion esiasetus" #: src/window.ui:76 msgid "Main Menu" msgstr "Päävalikko" #: src/window.ui:78 msgctxt "accessibility" msgid "Main Menu" msgstr "Päävalikko" #: src/window.ui:79 msgid "Access Keyboard Shortcuts and Application Information" msgstr "Näytä pikanäppäimet ja sovelluksen tiedot" #: src/window.ui:86 src/gtk/audio-export-dialog.blp:6 #: src/gtk/audio-export-dialog.blp:96 msgid "Export Audio" msgstr "Vie ääni" #: src/window.ui:88 msgctxt "accessibility" msgid "Export Audio" msgstr "Vie ääni" #: src/window.ui:89 msgid "Export Current Drum Pattern as Audio File" msgstr "Tallenna rumpukuvio äänitiedostona" #: src/window.ui:134 msgid "BPM" msgstr "BPM" #: src/window.ui:139 src/window.ui:143 msgid "Adjust Tempo In Beats per Minute (BPM)" msgstr "Määritä tempo iskuina minuutissa (BPM)" #: src/window.ui:142 msgid "Tempo" msgstr "Tempo" #: src/window.ui:184 msgid "Adjust Volume" msgstr "Säädä äänenvoimakkuutta" #: src/window.ui:207 msgid "Reset" msgstr "Nollaa" #: src/window.ui:208 msgid "Reset the Drum Sequence" msgstr "Nollaa rumpusekvenssi" #: src/window.ui:223 msgid "_Save Pattern" msgstr "_Tallenna kuvio" #: src/window.ui:229 msgid "_Keyboard Shortcuts" msgstr "_Pikanäppäimet" #: src/window.ui:233 msgid "_About Drum Machine" msgstr "_Tietoja - Rumpukone" #: src/gtk/help-overlay.blp:11 msgctxt "shortcut window" msgid "General" msgstr "Yleiset" #: src/gtk/help-overlay.blp:14 msgctxt "shortcut window" msgid "Show Shortcuts" msgstr "Näytä pikanäppäimet" #: src/gtk/help-overlay.blp:19 msgctxt "shortcut window" msgid "Quit" msgstr "Lopeta" #: src/gtk/help-overlay.blp:26 msgctxt "shortcut window" msgid "Playback Controls" msgstr "Toistosäätimet" #: src/gtk/help-overlay.blp:29 msgctxt "shortcut window" msgid "Play/Pause" msgstr "Toista/keskeytä" #: src/gtk/help-overlay.blp:35 msgctxt "shortcut window" msgid "Clear All" msgstr "Tyhjennä kaikki" #: src/gtk/help-overlay.blp:42 msgctxt "shortcut window" msgid "BPM & Volume Controls" msgstr "BPM & äänenvoimakkuuden säätimet" #: src/gtk/help-overlay.blp:45 msgctxt "shortcut window" msgid "Increase BPM" msgstr "Lisää BPM:ää" #: src/gtk/help-overlay.blp:51 msgctxt "shortcut window" msgid "Decrease BPM" msgstr "Vähennä BPM:ää" #: src/gtk/help-overlay.blp:57 msgctxt "shortcut window" msgid "Increase Volume" msgstr "Lisää äänenvoimakkuutta" #: src/gtk/help-overlay.blp:63 msgctxt "shortcut window" msgid "Decrease Volume" msgstr "Vähennä äänenvoimakkuutta" #: src/gtk/help-overlay.blp:69 msgctxt "shortcut window" msgid "Mute" msgstr "Vaimenna" #: src/gtk/help-overlay.blp:76 msgctxt "shortcut window" msgid "Preset Management" msgstr "Esiasetusten hallinta" #: src/gtk/help-overlay.blp:79 msgctxt "shortcut window" msgid "Load Preset" msgstr "Lataa esiasetus" #: src/gtk/help-overlay.blp:85 msgctxt "shortcut window" msgid "Save Preset" msgstr "Tallenna esiasetus" #: src/gtk/help-overlay.blp:91 msgctxt "shortcut window" msgid "Export Audio" msgstr "Vie ääni" #: src/gtk/help-overlay.blp:98 msgctxt "shortcut window" msgid "Navigation" msgstr "Liikkuminen" #: src/gtk/help-overlay.blp:101 msgctxt "shortcut window" msgid "Go to Instrument" msgstr "Siirry instrumenttiin" #: src/gtk/help-overlay.blp:107 msgctxt "shortcut window" msgid "Previous Page" msgstr "Edellinen sivu" #: src/gtk/help-overlay.blp:113 msgctxt "shortcut window" msgid "Next Page" msgstr "Seuraava sivu" #: src/gtk/save-changes-dialog.blp:5 msgid "Save Changes?" msgstr "Tallennetaanko muutokset?" #: src/gtk/save-changes-dialog.blp:6 msgid "" "Current preset contains unsaved changes. Changes which are not saved will be " "permanently lost." msgstr "" "Nykyinen esiasetus sisältää tallentamattomia muutoksia. Tallentamattomat " "muutokset katoavat." #. Translators: Cancel the operation #: src/gtk/save-changes-dialog.blp:14 msgid "_Cancel" msgstr "_Peru" #. Translators: Discard all changes #: src/gtk/save-changes-dialog.blp:15 msgid "_Discard" msgstr "_Hylkää" #. Translators: Save current changes #: src/gtk/save-changes-dialog.blp:16 msgid "_Save" msgstr "_Tallenna" #: src/gtk/audio-export-dialog.blp:39 msgid "Audio Format" msgstr "Äänimuoto" #: src/gtk/audio-export-dialog.blp:45 msgid "Repeat Count" msgstr "Toistakerrat" #: src/gtk/audio-export-dialog.blp:46 msgid "How many times to repeat the pattern" msgstr "Kuinka monta kertaa kuvio toistetaan" #: src/gtk/audio-export-dialog.blp:59 msgid "Metadata" msgstr "Metatiedot" #: src/gtk/audio-export-dialog.blp:62 msgid "Artist Name" msgstr "Esittäjän nimi" #: src/gtk/audio-export-dialog.blp:67 msgid "Song Name" msgstr "Kappaleen nimi" #: src/gtk/audio-export-dialog.blp:72 msgid "Cover Art" msgstr "Kansikuva" #: src/gtk/audio-export-dialog.blp:76 msgid "Choose File" msgstr "Valitse tiedosto" #: src/gtk/audio-export-dialog.blp:105 msgid "Cancel Export" msgstr "Peru vienti" #~ msgid "Export Settings" #~ msgstr "Viennin asetukset" #~ msgid "Configure your audio export options" #~ msgstr "Määrit äänen viennin asetukset" #~ msgid "Select the output audio format" #~ msgstr "Valitse valmiin tiedoston äänimuoto" #~ msgid "Add metadata to your exported audio" #~ msgstr "Lisää metatiedot vietäviin äänitiedostoihin" #~ msgid "Select an image file for the cover art" #~ msgstr "Valitse kansikuvaksi asetettava kuva" drum-machine-2.2.0/po/fr.po000066400000000000000000000250601514070543000154530ustar00rootroot00000000000000# French translations for drum-machine package. # Copyright (C) 2025 drum-machine's COPYRIGHT HOLDER # This file is distributed under the same license as the drum-machine package. # Thomas Silvestre , 2025. # msgid "" msgstr "" "Project-Id-Version: drum-machine\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2025-02-15 17:06-0300\n" "PO-Revision-Date: 2025-03-30 18:00+0100\n" "Last-Translator: Thomas Silvestre \n" "Language-Team: \n" "Language: fr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: data/io.github.revisto.drum-machine.desktop.in:3 #: data/io.github.revisto.drum-machine.metainfo.xml.in:6 src/window.ui:58 msgid "Drum Machine" msgstr "Drum Machine" #: data/io.github.revisto.drum-machine.metainfo.xml.in:7 msgid "Create and play drum beats" msgstr "Créer et jouer des drum beats" #: data/io.github.revisto.drum-machine.metainfo.xml.in:9 msgid "" "Drum Machine is a modern and intuitive application for creating, playing, " "and managing drum patterns. Perfect for musicians, producers, and anyone " "interested in rhythm creation, this application provides a simple interface " "for drum pattern programming. Have fun!" msgstr "" "Drum Machine est une application moderne et intuitive pour créer, jouer, " "et gérer des motifs de batterie. Parfait pour les musiciens, les producteurs " "et tous ceux qui sont intéressés par la création de rythmes. Cette application " "founit une interface simple pour la programmation de motifs de batterie. " "Amusez-vous!" #: data/io.github.revisto.drum-machine.metainfo.xml.in:15 msgid "Features:" msgstr "Fonctionnalités:" #: data/io.github.revisto.drum-machine.metainfo.xml.in:17 msgid "Intuitive grid-based pattern editor" msgstr "Éditeur de modèles intuitif basé sur une grille" #: data/io.github.revisto.drum-machine.metainfo.xml.in:18 msgid "Adjustable BPM control" msgstr "Contrôle de BPM ajustable" #: data/io.github.revisto.drum-machine.metainfo.xml.in:19 msgid "Volume control for overall mix" msgstr "Contrôle du volume pour l'ensemble du mix" #: data/io.github.revisto.drum-machine.metainfo.xml.in:20 msgid "Save and load preset patterns" msgstr "Enregistrer et charger des modèles prédéfinis" #: data/io.github.revisto.drum-machine.metainfo.xml.in:21 msgid "Multiple drum sounds including kick, snare, hi-hat, and more" msgstr "" #: data/io.github.revisto.drum-machine.metainfo.xml.in:22 msgid "Keyboard shortcuts for quick access to all functions" msgstr "Raccourcis clavier pour un accès rapide à toutes les fonctions" #: data/io.github.revisto.drum-machine.metainfo.xml.in:31 msgid "Drum Pattern Loaded in Light Mode" msgstr "Motif de batterie chargé en mode clair" #: data/io.github.revisto.drum-machine.metainfo.xml.in:35 msgid "Drum Pattern Loaded in Dark Mode" msgstr "Motif de batterie chargé en mode sombre" #: data/io.github.revisto.drum-machine.metainfo.xml.in:46 msgid "drum" msgstr "batterie" #: data/io.github.revisto.drum-machine.metainfo.xml.in:47 msgid "machine" msgstr "machine" #: data/io.github.revisto.drum-machine.metainfo.xml.in:48 msgid "rhythm" msgstr "rythme" #: data/io.github.revisto.drum-machine.metainfo.xml.in:49 msgid "music" msgstr "musique" #: data/io.github.revisto.drum-machine.metainfo.xml.in:50 msgid "pattern" msgstr "modèle" #: data/io.github.revisto.drum-machine.metainfo.xml.in:51 msgid "beats" msgstr "battements" #: data/io.github.revisto.drum-machine.metainfo.xml.in:60 msgid "Revisto" msgstr "Revisto" #: data/io.github.revisto.drum-machine.metainfo.xml.in:66 msgid "" "This release of Drum Machine 1.3.1 brings significant UI and functionality " "improvements:" msgstr "" "Cette version de Drum Machine 1.3.1 apporte des améliorations significatives " "de l'interface utilisateur et des fonctionnalités:" #: data/io.github.revisto.drum-machine.metainfo.xml.in:68 msgid "" "Refactored headerbar and background styling for a flat, integrated visual " "experience." msgstr "" "Barre d'en-tête et style d'arrière-plan refactorisés pour une expérience " "visuelle plate et intégrée." #: data/io.github.revisto.drum-machine.metainfo.xml.in:69 msgid "" "Enhanced accessibility with improved tooltips and descriptive labels for BPM " "and volume controls." msgstr "" "Accessibilité améliorée avec des info-bulles améliorées et des étiquettes " "descriptives pour les contrôles de BPM et de volume." #: data/io.github.revisto.drum-machine.metainfo.xml.in:70 msgid "" "Redesigned app icon and updated text styling for clearer user interface " "elements." msgstr "" "Icône d'application repensée et style de texte mis à jour pour des éléments " "d'interface utilisateur plus clairs." #: data/io.github.revisto.drum-machine.metainfo.xml.in:71 msgid "" "Optimized layout breakpoints to improve responsiveness and reduce early " "scrolling." msgstr "" "Points d'arrêt de mise en page optimisés pour améliorer la réactivité et " "réduire le défilement précoce." #: data/io.github.revisto.drum-machine.metainfo.xml.in:72 msgid "" "Fixed padding, border-radius, and vertical alignment issues across multiple " "controls." msgstr "" "Correction des problèmes de remplissage, de rayon de bordure et d'alignement " "vertical sur plusieurs contrôles." #: data/io.github.revisto.drum-machine.metainfo.xml.in:73 msgid "" "Updated file dialogs to use the Nautilus file chooser for a more modern " "approach." msgstr "" "Boîtes de dialogue de fichiers mises à jour pour utiliser le sélecteur de " "fichiers Nautilus pour une approche plus moderne." #: data/io.github.revisto.drum-machine.metainfo.xml.in:74 msgid "" "Improved keyboard navigation focus and updated tooltips, including dedicated " "play and pause hints." msgstr "" "Navigation au clavier améliorée et infobulles mises à jour, y compris des " "conseils de lecture et de pause dédiés." #: data/io.github.revisto.drum-machine.metainfo.xml.in:75 msgid "" "Transitioned to the Nautilus file chooser for a more contemporary interface." msgstr "" "Transition vers le sélecteur de fichiers Nautilus pour une interface plus " "contemporaine." #: data/io.github.revisto.drum-machine.metainfo.xml.in:76 msgid "Now accessible on narrow mobile screens with adaptive UI elements." msgstr "" "Désormais accessible sur les écrans mobiles étroits avec des éléments " "d'interface utilisateur adaptatifs." #: data/io.github.revisto.drum-machine.metainfo.xml.in:77 msgid "Refined app icon, and adjusted brand colors for better contrast." msgstr "" "Icône de l'application raffinée et couleurs de la marque ajustées pour un " "meilleur contraste." #. Update tooltip and accessibility with current BPM #: src/window.py:270 msgid "{} Beats per Minute (BPM)" msgstr "{} Battements par Minute (BPM)" #. Update button tooltip to show current volume level #: src/window.py:279 msgid "{:.0f}% Volume" msgstr "{:.0f}% Volume" #: src/window.py:290 src/window.ui:158 msgid "Play" msgstr "Jouer" #: src/window.py:294 msgid "Pause" msgstr "Pause" #: src/window.py:309 msgid "Default Presets" msgstr "Préréglages par défaut" #: src/window.py:336 msgid "MIDI files" msgstr "Fichier MIDI" #: src/window.py:342 msgid "Open MIDI File" msgstr "Ouvrir un fichier MIDI" #: src/window.ui:41 msgid "Open" msgstr "Ouvrir" #: src/window.ui:43 src/window.ui:46 msgid "Open Preset" msgstr "Ouvrir un préréglage" #: src/window.ui:47 msgid "Open Saved Drum Pattern Preset" msgstr "Ouvrir le préréglage de motif de batterie enregistré" #: src/window.ui:65 src/window.ui:67 msgid "Main Menu" msgstr "Menu principal" #: src/window.ui:68 msgid "Access Keyboard Shortcuts and Application Information" msgstr "Accéder aux raccourcis clavier et aux informations sur l'application" #: src/window.ui:75 src/window.ui:77 msgid "Save Drum Pattern" msgstr "Enregistrer le motif de batterie" #: src/window.ui:78 msgid "Save Current Drum Pattern as a Preset File" msgstr "Enregistrer le motif de batterie actuel en tant que fichier prédéfini" #: src/window.ui:122 msgid "BPM" msgstr "BPM" #: src/window.ui:127 src/window.ui:131 msgid "Adjust Tempo In Beats per Minute (BPM)" msgstr "Ajuster le Tempo en Battements par Minute (BPM)" #: src/window.ui:130 msgid "Tempo" msgstr "Tempo" #: src/window.ui:172 msgid "Adjust Volume" msgstr "Ajuster le volume" #: src/window.ui:195 msgid "Reset" msgstr "Réinitialiser" #: src/window.ui:208 msgid "_Keyboard Shortcuts" msgstr "_Raccourci Clavier" #: src/window.ui:212 msgid "_About Drum Machine" msgstr "_À propos de Drum Machine" #: src/gtk/help-overlay.ui:11 msgctxt "shortcut window" msgid "General" msgstr "Général" #: src/gtk/help-overlay.ui:14 msgctxt "shortcut window" msgid "Show Shortcuts" msgstr "Montrer les Raccourcis" #: src/gtk/help-overlay.ui:20 msgctxt "shortcut window" msgid "Quit" msgstr "Quitter" #: src/gtk/help-overlay.ui:29 msgctxt "shortcut window" msgid "Playback Controls" msgstr "Commandes de lecture" #: src/gtk/help-overlay.ui:32 msgctxt "shortcut window" msgid "Play/Pause" msgstr "Jouer/Pause" #: src/gtk/help-overlay.ui:39 msgctxt "shortcut window" msgid "Clear All" msgstr "Tout Effacer" #: src/gtk/help-overlay.ui:48 msgctxt "shortcut window" msgid "BPM & Volume Controls" msgstr "Contrôles du BPM et du volume" #: src/gtk/help-overlay.ui:51 msgctxt "shortcut window" msgid "Increase BPM" msgstr "Augmenter le BPM" #: src/gtk/help-overlay.ui:58 msgctxt "shortcut window" msgid "Decrease BPM" msgstr "Diminuer le BPM" #: src/gtk/help-overlay.ui:65 msgctxt "shortcut window" msgid "Increase Volume" msgstr "Augmenter le Volume" #: src/gtk/help-overlay.ui:72 msgctxt "shortcut window" msgid "Decrease Volume" msgstr "Diminuer le Volume" #: src/gtk/help-overlay.ui:81 msgctxt "shortcut window" msgid "Preset Management" msgstr "Gestion des préréglages" #: src/gtk/help-overlay.ui:84 msgctxt "shortcut window" msgid "Load Preset" msgstr "Charger un préréglage" #: src/gtk/help-overlay.ui:91 msgctxt "shortcut window" msgid "Save Preset" msgstr "Enregistrer un préréglage" #: src/gtk/save_changes_dialog.ui:6 msgid "Save Changes?" msgstr "Enregistrer les Modifications?" #: src/gtk/save_changes_dialog.ui:7 msgid "" "Current preset contains unsaved changes. Changes which are not saved will be " "permanently lost." msgstr "" "Le préréglage actuel contient des modifications non enregistrées. Les modifications " "non enregistrées seront définitivement perdues." #. Cancel the operation #: src/gtk/save_changes_dialog.ui:14 msgid "_Cancel" msgstr "_Annuler" #. Discard all changes #: src/gtk/save_changes_dialog.ui:15 msgid "_Discard" msgstr "_Annuler" #. Save current changes #: src/gtk/save_changes_dialog.ui:16 msgid "_Save" msgstr "_Enregistrer" drum-machine-2.2.0/po/he.po000066400000000000000000000206171514070543000154430ustar00rootroot00000000000000# Hebrew translation for drum-machine. # Copyright (C) 2025 drum-machine's COPYRIGHT HOLDER # This file is distributed under the same license as the drum-machine package. # Yaron Shahrabani , 2025. # msgid "" msgstr "" "Project-Id-Version: drum-machine master\n" "Report-Msgid-Bugs-To: https://github.com/revisto/drum-machine/issues\n" "POT-Creation-Date: 2025-08-15 03:26+0000\n" "PO-Revision-Date: 2025-08-15 14:39+0300\n" "Last-Translator: Yaron Shahrabani \n" "Language-Team: Hebrew \n" "Language: he\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Poedit 3.6\n" #: data/io.github.revisto.drum-machine.desktop.in:2 #: data/io.github.revisto.drum-machine.metainfo.xml.in:6 src/window.ui:67 msgid "Drum Machine" msgstr "מכונת תופים" #: data/io.github.revisto.drum-machine.metainfo.xml.in:7 msgid "Create and play drum beats" msgstr "יצירת ונגינה של צלילי תופים" #: data/io.github.revisto.drum-machine.metainfo.xml.in:9 msgid "" "Drum Machine is a modern and intuitive application for creating, playing, " "and managing drum patterns. Perfect for musicians, producers, and anyone " "interested in rhythm creation, this application provides a simple interface " "for drum pattern programming. Have fun!" msgstr "" "מכונת תופים הוא יישום ברור וחדיש ליצירת, נגינת וניהול תבניות נגינה על תופים. " "מושלם למוזיקאים, מפיקים וכל מי שמתעניין ביצירת מקצבים, היישום הזה מספק מנשק " "פשוט לתכנות תבניות תיפוף. שיהיה בכיף!" #: data/io.github.revisto.drum-machine.metainfo.xml.in:15 msgid "Features:" msgstr "יכולות:" #: data/io.github.revisto.drum-machine.metainfo.xml.in:17 msgid "Intuitive grid-based pattern editor" msgstr "עורך תבניות מבוסס רשת ברור" #: data/io.github.revisto.drum-machine.metainfo.xml.in:18 msgid "Adjustable BPM control" msgstr "בקרת BPM מתכווננת" #: data/io.github.revisto.drum-machine.metainfo.xml.in:19 msgid "Volume control for overall mix" msgstr "בקרת עוצמת שמע לערבול כולל" #: data/io.github.revisto.drum-machine.metainfo.xml.in:20 msgid "Save and load preset patterns" msgstr "שמירת וטעינת תבניות שנערכו מראש" #: data/io.github.revisto.drum-machine.metainfo.xml.in:21 msgid "Multiple drum sounds including kick, snare, hi-hat, and more" msgstr "מגוון צלילי תיפוף כגון קיק, סנר ,הייהט ועוד" #: data/io.github.revisto.drum-machine.metainfo.xml.in:22 msgid "Keyboard shortcuts for quick access to all functions" msgstr "קיצורי מקלדת לגישה מהירה לכל הפונקציות" #: data/io.github.revisto.drum-machine.metainfo.xml.in:31 msgid "Drum Pattern Loaded in Light Mode" msgstr "תבנית תיפוף טעונה במצב בהיר" #: data/io.github.revisto.drum-machine.metainfo.xml.in:35 msgid "Drum Pattern Loaded in Dark Mode" msgstr "תבנית תיפוף טעונה במצב כהה" #: src/application.py:69 msgid "translator-credits" msgstr "ירון שהרבני " #. Update tooltip and accessibility with current BPM #: src/window.py:190 msgid "{} Beats per Minute (BPM)" msgstr "{} פעימות בדקה (BPM)" #. Update button tooltip to show current volume level #: src/window.py:199 msgid "{:.0f}% Volume" msgstr "{:.0f}% עוצמת שמע" #: src/window.py:214 src/window.ui:167 msgid "Play" msgstr "נגינה" #: src/window.py:218 msgid "Pause" msgstr "השהיה" #: src/window.ui:50 msgid "Open" msgstr "פתיחה" #: src/window.ui:52 msgid "Open Preset" msgstr "פתיחת ערכה" #: src/window.ui:55 msgctxt "accessibility" msgid "Open Preset" msgstr "פתיחת ערכה" #: src/window.ui:56 msgid "Open Saved Drum Pattern Preset" msgstr "פתיחת ערכת תבנית תיפוף שמורה" #: src/window.ui:74 msgid "Main Menu" msgstr "תפריט ראשי" #: src/window.ui:76 msgctxt "accessibility" msgid "Main Menu" msgstr "תפריט ראשי" #: src/window.ui:77 msgid "Access Keyboard Shortcuts and Application Information" msgstr "גישה לקיצורי מקלדת ולפרטים על היישום" #: src/window.ui:84 msgid "Save Drum Pattern" msgstr "שמירת תבנית תיפוף" #: src/window.ui:86 msgctxt "accessibility" msgid "Save Drum Pattern" msgstr "שמירת תבנית תיפוף" #: src/window.ui:87 msgid "Save Current Drum Pattern as a Preset File" msgstr "שמירת תבנית התיפוף הנוכחית כקובץ ערכה" #: src/window.ui:131 msgid "BPM" msgstr "BPM" #: src/window.ui:136 src/window.ui:140 msgid "Adjust Tempo In Beats per Minute (BPM)" msgstr "כיוון הקצב בפעימות לדקה (BPM)" #: src/window.ui:139 msgid "Tempo" msgstr "קצב" #: src/window.ui:181 msgid "Adjust Volume" msgstr "כיוון עוצמת שמע" #: src/window.ui:204 msgid "Reset" msgstr "איפוס" #: src/window.ui:205 msgid "Reset the Drum Sequence" msgstr "איפוס רצף התיפוף" #: src/window.ui:218 msgid "_Keyboard Shortcuts" msgstr "_קיצורי מקלדת" #: src/window.ui:222 msgid "_About Drum Machine" msgstr "על מכונת _תופים" #: src/gtk/help-overlay.ui:11 msgctxt "shortcut window" msgid "General" msgstr "כללי" #: src/gtk/help-overlay.ui:14 msgctxt "shortcut window" msgid "Show Shortcuts" msgstr "הצגת קיצורי מקלדת" #: src/gtk/help-overlay.ui:20 msgctxt "shortcut window" msgid "Quit" msgstr "יציאה" #: src/gtk/help-overlay.ui:29 msgctxt "shortcut window" msgid "Playback Controls" msgstr "פקדי נגינה" #: src/gtk/help-overlay.ui:32 msgctxt "shortcut window" msgid "Play/Pause" msgstr "נגינה / השהיה" #: src/gtk/help-overlay.ui:39 msgctxt "shortcut window" msgid "Clear All" msgstr "לרוקן הכול" #: src/gtk/help-overlay.ui:48 msgctxt "shortcut window" msgid "BPM & Volume Controls" msgstr "BPM ובקרת עוצמת שמע" #: src/gtk/help-overlay.ui:51 msgctxt "shortcut window" msgid "Increase BPM" msgstr "האצת פעימות לדקה" #: src/gtk/help-overlay.ui:58 msgctxt "shortcut window" msgid "Decrease BPM" msgstr "האטת פעימות לדקה" #: src/gtk/help-overlay.ui:65 msgctxt "shortcut window" msgid "Increase Volume" msgstr "הגברת עוצמת שמע" #: src/gtk/help-overlay.ui:72 msgctxt "shortcut window" msgid "Decrease Volume" msgstr "הנמכת עוצמת שמע" #: src/gtk/help-overlay.ui:79 msgctxt "shortcut window" msgid "Mute" msgstr "השתקה" #: src/gtk/help-overlay.ui:88 msgctxt "shortcut window" msgid "Preset Management" msgstr "ניהול ערכות" #: src/gtk/help-overlay.ui:91 msgctxt "shortcut window" msgid "Load Preset" msgstr "טעינת ערכה" #: src/gtk/help-overlay.ui:98 msgctxt "shortcut window" msgid "Save Preset" msgstr "שמירת ערכה" #: src/gtk/help-overlay.ui:107 msgctxt "shortcut window" msgid "Navigation" msgstr "ניווט" #: src/gtk/help-overlay.ui:110 msgctxt "shortcut window" msgid "Go to Instrument" msgstr "מעבר לכלי" #: src/gtk/help-overlay.ui:117 msgctxt "shortcut window" msgid "Previous Page" msgstr "העמוד הקודם" #: src/gtk/help-overlay.ui:124 msgctxt "shortcut window" msgid "Next Page" msgstr "העמוד הבא" #: src/gtk/save_changes_dialog.ui:6 msgid "Save Changes?" msgstr "לשמור את השינויים?" #: src/gtk/save_changes_dialog.ui:7 msgid "" "Current preset contains unsaved changes. Changes which are not saved will be " "permanently lost." msgstr "" "הערכה הנוכחית מכילה שינויים שלא נשמרו. השינויים שלא יישמרו יאבדו לצמיתות." #. Cancel the operation #: src/gtk/save_changes_dialog.ui:14 msgid "_Cancel" msgstr "_ביטול" #. Discard all changes #: src/gtk/save_changes_dialog.ui:15 msgid "_Discard" msgstr "הת_עלמות" #. Save current changes #: src/gtk/save_changes_dialog.ui:16 msgid "_Save" msgstr "_שמירה" #: src/handlers/file_dialog_handler.py:48 msgid "Default Presets" msgstr "ערכות ברירת מחדל" #: src/handlers/file_dialog_handler.py:76 #: src/handlers/file_dialog_handler.py:142 msgid "MIDI files" msgstr "קובצי MIDI" #: src/handlers/file_dialog_handler.py:82 msgid "Open MIDI File" msgstr "פתיחת קובץ MIDI" #: src/handlers/file_dialog_handler.py:148 msgid "Save Sequence" msgstr "שמירת הרצף" drum-machine-2.2.0/po/hu.po000066400000000000000000000204351514070543000154610ustar00rootroot00000000000000# Hungarian translation for drum-machine. # Copyright (C) 2025 Free Software Foundation, Inc. # This file is distributed under the same license as the drum-machine package. # # Balázs Meskó , 2025. # Balázs Úr , 2025. msgid "" msgstr "" "Project-Id-Version: drum-machine master\n" "Report-Msgid-Bugs-To: https://github.com/revisto/drum-machine/issues\n" "POT-Creation-Date: 2025-09-01 15:26+0000\n" "PO-Revision-Date: 2025-09-01 17:35+0200\n" "Last-Translator: Balázs Úr \n" "Language-Team: Hungarian \n" "Language: hu\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Lokalize 24.12.3\n" #: data/io.github.revisto.drum-machine.desktop.in:2 #: data/io.github.revisto.drum-machine.metainfo.xml.in:6 src/window.ui:67 msgid "Drum Machine" msgstr "Dobgép" #: data/io.github.revisto.drum-machine.metainfo.xml.in:7 msgid "Create and play drum beats" msgstr "Dobütések létrehozása és lejátszása" #: data/io.github.revisto.drum-machine.metainfo.xml.in:9 msgid "" "Drum Machine is a modern and intuitive application for creating, playing, " "and managing drum patterns. Perfect for musicians, producers, and anyone " "interested in rhythm creation, this application provides a simple interface " "for drum pattern programming. Have fun!" msgstr "" "A Dobgép egy modern és intuitív alkalmazás dobminták létrehozásához, lejátszás" "ához és kezeléséhez. Ez az alkalmazás tökéletes zenészek, producerek és minden" "ki számára, aki érdeklődik a ritmusalkotás iránt, mivel egyszerű felületet biz" "tosít a dobminták programozásához. Jó szórakozást!" #: data/io.github.revisto.drum-machine.metainfo.xml.in:15 msgid "Features:" msgstr "Jellemzők:" #: data/io.github.revisto.drum-machine.metainfo.xml.in:17 msgid "Intuitive grid-based pattern editor" msgstr "Intuitív rácsalapú mintaszerkesztő" #: data/io.github.revisto.drum-machine.metainfo.xml.in:18 msgid "Adjustable BPM control" msgstr "Állítható BPM-vezérlés" #: data/io.github.revisto.drum-machine.metainfo.xml.in:19 msgid "Volume control for overall mix" msgstr "Hangerőszabályzó a teljes keveréshez" #: data/io.github.revisto.drum-machine.metainfo.xml.in:20 msgid "Save and load preset patterns" msgstr "Minta-előbeállítások mentése és betöltése" #: data/io.github.revisto.drum-machine.metainfo.xml.in:21 msgid "Multiple drum sounds including kick, snare, hi-hat, and more" msgstr "Többféle dobhang, köztük lábdob, pergődob, lábcin és egyebek" #: data/io.github.revisto.drum-machine.metainfo.xml.in:22 msgid "Keyboard shortcuts for quick access to all functions" msgstr "Gyorsbillentyűk az összes funkció gyors eléréséhez" #: data/io.github.revisto.drum-machine.metainfo.xml.in:31 msgid "Drum Pattern Loaded in Light Mode" msgstr "Dobminta világos módban betöltve" #: data/io.github.revisto.drum-machine.metainfo.xml.in:35 msgid "Drum Pattern Loaded in Dark Mode" msgstr "Dobminta sötét módban betöltve" #: src/application.py:69 msgid "translator-credits" msgstr "" "Meskó Balázs , 2025.\n" "Úr Balázs , 2025." #. Update tooltip and accessibility with current BPM #: src/window.py:190 msgid "{} Beats per Minute (BPM)" msgstr "{} ütés percenként (BPM)" #. Update button tooltip to show current volume level #: src/window.py:199 msgid "{:.0f}% Volume" msgstr "{:.0f}%-os hangerő" #: src/window.py:214 src/window.ui:167 msgid "Play" msgstr "Lejátszás" #: src/window.py:218 msgid "Pause" msgstr "Szüneteltetés" #: src/window.ui:50 msgid "Open" msgstr "Megnyitás" #: src/window.ui:52 msgid "Open Preset" msgstr "Előbeállítás megnyitása" #: src/window.ui:55 msgctxt "accessibility" msgid "Open Preset" msgstr "Előbeállítás megnyitása" #: src/window.ui:56 msgid "Open Saved Drum Pattern Preset" msgstr "Mentett dobminta-előbeállítás megnyitása" #: src/window.ui:74 msgid "Main Menu" msgstr "Főmenü" #: src/window.ui:76 msgctxt "accessibility" msgid "Main Menu" msgstr "Főmenü" #: src/window.ui:77 msgid "Access Keyboard Shortcuts and Application Information" msgstr "Gyorsbillentyűk és alkalmazásinformációk elérése" #: src/window.ui:84 msgid "Save Drum Pattern" msgstr "Dobminta mentése" #: src/window.ui:86 msgctxt "accessibility" msgid "Save Drum Pattern" msgstr "Dobminta mentése" #: src/window.ui:87 msgid "Save Current Drum Pattern as a Preset File" msgstr "A jelenlegi dobminta mentése előbeállítás-fájlként" #: src/window.ui:131 msgid "BPM" msgstr "BPM" #: src/window.ui:136 src/window.ui:140 msgid "Adjust Tempo In Beats per Minute (BPM)" msgstr "A tempó módosítása percenkénti ütésszámban (BPM)" #: src/window.ui:139 msgid "Tempo" msgstr "Tempó" #: src/window.ui:181 msgid "Adjust Volume" msgstr "Hangerő módosítása" #: src/window.ui:204 msgid "Reset" msgstr "Visszaállítás" #: src/window.ui:205 msgid "Reset the Drum Sequence" msgstr "A dobsorozat visszaállítása" #: src/window.ui:218 msgid "_Keyboard Shortcuts" msgstr "_Gyorsbillentyűk" #: src/window.ui:222 msgid "_About Drum Machine" msgstr "A Dobgép _névjegye" #: src/gtk/help-overlay.ui:11 msgctxt "shortcut window" msgid "General" msgstr "Általános" #: src/gtk/help-overlay.ui:14 msgctxt "shortcut window" msgid "Show Shortcuts" msgstr "Gyorsbillentyűk megjelenítése" #: src/gtk/help-overlay.ui:20 msgctxt "shortcut window" msgid "Quit" msgstr "Kilépés" #: src/gtk/help-overlay.ui:29 msgctxt "shortcut window" msgid "Playback Controls" msgstr "Lejátszásvezérlők" #: src/gtk/help-overlay.ui:32 msgctxt "shortcut window" msgid "Play/Pause" msgstr "Lejátszás és szüneteltetés" #: src/gtk/help-overlay.ui:39 msgctxt "shortcut window" msgid "Clear All" msgstr "Összes törlése" #: src/gtk/help-overlay.ui:48 msgctxt "shortcut window" msgid "BPM & Volume Controls" msgstr "BPM- és hangerőszabályzás" #: src/gtk/help-overlay.ui:51 msgctxt "shortcut window" msgid "Increase BPM" msgstr "BPM növelése" #: src/gtk/help-overlay.ui:58 msgctxt "shortcut window" msgid "Decrease BPM" msgstr "BPM csökkentése" #: src/gtk/help-overlay.ui:65 msgctxt "shortcut window" msgid "Increase Volume" msgstr "Hangerő növelése" #: src/gtk/help-overlay.ui:72 msgctxt "shortcut window" msgid "Decrease Volume" msgstr "Hangerő csökkentése" #: src/gtk/help-overlay.ui:79 msgctxt "shortcut window" msgid "Mute" msgstr "Némítás" #: src/gtk/help-overlay.ui:88 msgctxt "shortcut window" msgid "Preset Management" msgstr "Előbeállítás-kezelés" #: src/gtk/help-overlay.ui:91 msgctxt "shortcut window" msgid "Load Preset" msgstr "Előbeállítás betöltése" #: src/gtk/help-overlay.ui:98 msgctxt "shortcut window" msgid "Save Preset" msgstr "Előbeállítás mentése" #: src/gtk/help-overlay.ui:107 msgctxt "shortcut window" msgid "Navigation" msgstr "Navigáció" #: src/gtk/help-overlay.ui:110 msgctxt "shortcut window" msgid "Go to Instrument" msgstr "Ugrás a hangszerhez" #: src/gtk/help-overlay.ui:117 msgctxt "shortcut window" msgid "Previous Page" msgstr "Előző oldal" #: src/gtk/help-overlay.ui:124 msgctxt "shortcut window" msgid "Next Page" msgstr "Következő oldal" #: src/gtk/save_changes_dialog.ui:6 msgid "Save Changes?" msgstr "Menti a változtatásokat?" #: src/gtk/save_changes_dialog.ui:7 msgid "" "Current preset contains unsaved changes. Changes which are not saved will be " "permanently lost." msgstr "" "A jelenlegi előbeállítás mentetlen változtatásokat tartalmaz. A mentetlen " "változtatások végleg el fognak veszni." #. Cancel the operation #: src/gtk/save_changes_dialog.ui:14 msgid "_Cancel" msgstr "_Mégse" #. Discard all changes #: src/gtk/save_changes_dialog.ui:15 msgid "_Discard" msgstr "_Elvetés" #. Save current changes #: src/gtk/save_changes_dialog.ui:16 msgid "_Save" msgstr "Me_ntés" #: src/handlers/file_dialog_handler.py:48 msgid "Default Presets" msgstr "Alapértelmezett előbeállítások" #: src/handlers/file_dialog_handler.py:76 #: src/handlers/file_dialog_handler.py:142 msgid "MIDI files" msgstr "MIDI-fájlok" #: src/handlers/file_dialog_handler.py:82 msgid "Open MIDI File" msgstr "MIDI-fájl megnyitása" #: src/handlers/file_dialog_handler.py:148 msgid "Save Sequence" msgstr "Sorozat mentése" drum-machine-2.2.0/po/it.po000066400000000000000000000157711514070543000154700ustar00rootroot00000000000000# Italian translation for drum-machine. # Copyright (C) 2025 drum-machine's COPYRIGHT HOLDER # This file is distributed under the same license as the drum-machine package. # catoblepa , 2025. # msgid "" msgstr "" "Project-Id-Version: drum-machine master\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2025-03-24 13:12+0000\n" "PO-Revision-Date: 2025-03-26 23:36+0100\n" "Last-Translator: catoblepa \n" "Language-Team: Italian\n" "Language: it\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Gtranslator 47.1\n" #: data/io.github.revisto.drum-machine.desktop.in:3 #: data/io.github.revisto.drum-machine.metainfo.xml.in:6 src/window.ui:58 msgid "Drum Machine" msgstr "Drum Machine" #: data/io.github.revisto.drum-machine.metainfo.xml.in:7 msgid "Create and play drum beats" msgstr "Crea e suona ritmi di batteria" #: data/io.github.revisto.drum-machine.metainfo.xml.in:9 msgid "" "Drum Machine is a modern and intuitive application for creating, playing, " "and managing drum patterns. Perfect for musicians, producers, and anyone " "interested in rhythm creation, this application provides a simple interface " "for drum pattern programming. Have fun!" msgstr "" "Drum Machine è un'applicazione moderna e intuitiva per creare, suonare e " "gestire pattern di batteria. Perfetta per musicisti, produttori e chiunque " "sia interessato alla creazione di ritmi, questa applicazione offre " "un'interfaccia semplice per programmare pattern di batteria. Buon " "divertimento!" #: data/io.github.revisto.drum-machine.metainfo.xml.in:15 msgid "Features:" msgstr "Funzionalità:" #: data/io.github.revisto.drum-machine.metainfo.xml.in:17 msgid "Intuitive grid-based pattern editor" msgstr "Editor di pattern intuitivo basato su griglia" #: data/io.github.revisto.drum-machine.metainfo.xml.in:18 msgid "Adjustable BPM control" msgstr "Regolazione dei battiti al minuto" #: data/io.github.revisto.drum-machine.metainfo.xml.in:19 msgid "Volume control for overall mix" msgstr "Controllo del volume per il mix generale" #: data/io.github.revisto.drum-machine.metainfo.xml.in:20 msgid "Save and load preset patterns" msgstr "Salva e carica pattern preimpostati" #: data/io.github.revisto.drum-machine.metainfo.xml.in:21 msgid "Multiple drum sounds including kick, snare, hi-hat, and more" msgstr "" "Suoni di batteria multipli, inclusi cassa, rullante, charleston e altro" #: data/io.github.revisto.drum-machine.metainfo.xml.in:22 msgid "Keyboard shortcuts for quick access to all functions" msgstr "Scorciatoie da tastiera per un accesso rapido a tutte le funzioni" #: data/io.github.revisto.drum-machine.metainfo.xml.in:31 msgid "Drum Pattern Loaded in Light Mode" msgstr "Pattern di batteria caricato in modalità chiara" #: data/io.github.revisto.drum-machine.metainfo.xml.in:35 msgid "Drum Pattern Loaded in Dark Mode" msgstr "Pattern di batteria caricato in modalità scura" #. Update tooltip and accessibility with current BPM #: src/window.py:278 msgid "{} Beats per Minute (BPM)" msgstr "{} battiti al minuto (BPM)" #. Update button tooltip to show current volume level #: src/window.py:287 msgid "{:.0f}% Volume" msgstr "Volume al {:.0f}%" #: src/window.py:298 src/window.ui:158 msgid "Play" msgstr "Riproduci" #: src/window.py:302 msgid "Pause" msgstr "Pausa" #: src/window.py:317 msgid "Default Presets" msgstr "Preimpostazioni predefinite" #: src/window.py:344 msgid "MIDI files" msgstr "File MIDI" #: src/window.py:350 msgid "Open MIDI File" msgstr "Apri file MIDI" #: src/window.ui:41 msgid "Open" msgstr "Apri" #: src/window.ui:43 src/window.ui:46 msgid "Open Preset" msgstr "Apri preimpostazione" #: src/window.ui:47 msgid "Open Saved Drum Pattern Preset" msgstr "Apri preimpostazione di pattern di batteria salvata" #: src/window.ui:65 src/window.ui:67 msgid "Main Menu" msgstr "Menù principale" #: src/window.ui:68 msgid "Access Keyboard Shortcuts and Application Information" msgstr "" "Accedi alle scorciatoie da tastiera e alle informazioni sull'applicazione" #: src/window.ui:75 src/window.ui:77 msgid "Save Drum Pattern" msgstr "Salva pattern di batteria" #: src/window.ui:78 msgid "Save Current Drum Pattern as a Preset File" msgstr "Salva il pattern di batteria attuale come file di preimpostazione" #: src/window.ui:122 msgid "BPM" msgstr "BPM" #: src/window.ui:127 src/window.ui:131 msgid "Adjust Tempo In Beats per Minute (BPM)" msgstr "Regola il tempo in battiti al minuto (BPM)" #: src/window.ui:130 msgid "Tempo" msgstr "Tempo" #: src/window.ui:172 msgid "Adjust Volume" msgstr "Regola il volume" #: src/window.ui:195 msgid "Reset" msgstr "Reimposta" #: src/window.ui:196 msgid "Reset the Drum Sequence" msgstr "Reimposta la sequenza di batteria" #: src/window.ui:209 msgid "_Keyboard Shortcuts" msgstr "Scorciatoie da _tastiera" #: src/window.ui:213 msgid "_About Drum Machine" msgstr "_Informazioni su Drum Machine" #: src/gtk/help-overlay.ui:11 msgctxt "shortcut window" msgid "General" msgstr "Generali" #: src/gtk/help-overlay.ui:14 msgctxt "shortcut window" msgid "Show Shortcuts" msgstr "Mostra scorciatoie" #: src/gtk/help-overlay.ui:20 msgctxt "shortcut window" msgid "Quit" msgstr "Esce" #: src/gtk/help-overlay.ui:29 msgctxt "shortcut window" msgid "Playback Controls" msgstr "Controlli di riproduzione" #: src/gtk/help-overlay.ui:32 msgctxt "shortcut window" msgid "Play/Pause" msgstr "Riproduci/Pausa" #: src/gtk/help-overlay.ui:39 msgctxt "shortcut window" msgid "Clear All" msgstr "Cancella tutto" #: src/gtk/help-overlay.ui:48 msgctxt "shortcut window" msgid "BPM & Volume Controls" msgstr "Controlli BPM e volume" #: src/gtk/help-overlay.ui:51 msgctxt "shortcut window" msgid "Increase BPM" msgstr "Aumenta i BPM" #: src/gtk/help-overlay.ui:58 msgctxt "shortcut window" msgid "Decrease BPM" msgstr "Diminuisce i BPM" #: src/gtk/help-overlay.ui:65 msgctxt "shortcut window" msgid "Increase Volume" msgstr "Aumenta il volume" #: src/gtk/help-overlay.ui:72 msgctxt "shortcut window" msgid "Decrease Volume" msgstr "Diminuisce il volume" #: src/gtk/help-overlay.ui:81 msgctxt "shortcut window" msgid "Preset Management" msgstr "Gestione preimpostazioni" #: src/gtk/help-overlay.ui:84 msgctxt "shortcut window" msgid "Load Preset" msgstr "Carica preimpostazioni" #: src/gtk/help-overlay.ui:91 msgctxt "shortcut window" msgid "Save Preset" msgstr "Salva preimpostazioni" #: src/gtk/save_changes_dialog.ui:6 msgid "Save Changes?" msgstr "Salvare le modifiche?" #: src/gtk/save_changes_dialog.ui:7 msgid "" "Current preset contains unsaved changes. Changes which are not saved will be " "permanently lost." msgstr "" "La preimpostazione corrente contiene modifiche non salvate. Le modifiche non " "salvate saranno perse definitivamente." #. Cancel the operation #: src/gtk/save_changes_dialog.ui:14 msgid "_Cancel" msgstr "_Annulla" #. Discard all changes #: src/gtk/save_changes_dialog.ui:15 msgid "_Discard" msgstr "S_carta" #. Save current changes #: src/gtk/save_changes_dialog.ui:16 msgid "_Save" msgstr "_Salva" drum-machine-2.2.0/po/ka.po000066400000000000000000000716051514070543000154450ustar00rootroot00000000000000# Georgian translation for drum-machine. # Copyright (C) 2025 drum-machine's authors # This file is distributed under the same license as the drum-machine package. # Ekaterine Papava , 2025. # msgid "" msgstr "" "Project-Id-Version: drum-machine master\n" "Report-Msgid-Bugs-To: https://github.com/revisto/drum-machine/issues\n" "POT-Creation-Date: 2025-11-27 03:26+0000\n" "PO-Revision-Date: 2025-11-27 07:38+0100\n" "Last-Translator: Ekaterine Papava \n" "Language-Team: Georgian \n" "Language: ka\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 3.8\n" #: data/io.github.revisto.drum-machine.desktop.in:2 #: data/io.github.revisto.drum-machine.metainfo.xml.in:6 src/application.py:67 #: src/window.ui:69 msgid "Drum Machine" msgstr "დრამ-მანქანა" #. Translators: Search terms to find this application. Do NOT translate or localise the semicolons! The list MUST also end with a semicolon! #: data/io.github.revisto.drum-machine.desktop.in:9 msgid "drum;drums;sequencer;rhythm;music;pattern;beats;percussion;loop;groove;" msgstr "drum;drums;sequencer;rhythm;music;pattern;beats;percussion;loop;groove;ბარაბანი;" #: data/io.github.revisto.drum-machine.metainfo.xml.in:7 msgid "Create and play drum beats" msgstr "შექმენით და დაუკარით დრამის დარტყმები" #: data/io.github.revisto.drum-machine.metainfo.xml.in:9 msgid "" "Drum Machine is a modern and intuitive application for creating, playing, and managing " "drum patterns. Perfect for musicians, producers, and anyone interested in rhythm " "creation, this application provides a simple interface for drum pattern programming. " "Have fun!" msgstr "" "Drum Machine თანამედროვე და ინტუიციური აპლიკაციაა დრამის ნიმუშების შესაქმნელად, " "დასაკრავად და სამართავად. გადასარევია მუსიკოსებისთვის, პროდიუსერებისთვის და " "ყველასთვის, რომელიც რითმის შექმნითაა დაინტერესებული, ეს აპლიკაცია უმარტივეს ინტერფეისს " "სთავაზობს დრამის ნიმუშის პროგრამირებისთვის. აბა, თქვენ იცით!" #: data/io.github.revisto.drum-machine.metainfo.xml.in:15 msgid "Features:" msgstr "თვისებები:" #: data/io.github.revisto.drum-machine.metainfo.xml.in:17 msgid "Intuitive grid-based pattern editor" msgstr "ინტუიციური ბადეზე დაფუძნებული ნიმუშების რედაქტორი" #: data/io.github.revisto.drum-machine.metainfo.xml.in:18 msgid "Adjustable BPM control" msgstr "რეგულირებადი BPM კონტროლი" #: data/io.github.revisto.drum-machine.metainfo.xml.in:19 msgid "Volume control for overall mix" msgstr "ხმის დონის კონტროლი მთელი მიქსისთვის" #: data/io.github.revisto.drum-machine.metainfo.xml.in:20 msgid "Save and load patterns" msgstr "ნიმუშების შენახვა და ჩატვირთვა" #: data/io.github.revisto.drum-machine.metainfo.xml.in:21 msgid "Multiple drum sounds including kick, snare, hi-hat, and more" msgstr "ერთზე მეტი დრამის ხმები თეფშის, დოლის, დიდი დეფშის და ა.შ. ჩათვლით" #: data/io.github.revisto.drum-machine.metainfo.xml.in:22 msgid "Audio export feature with support for WAV, FLAC, Ogg, and MP3 formats" msgstr "აუდიოს გატანის ფუნქციები WAV, FLAC, Ogg და MP3 ფორმატების მხარდაჭერით" #: data/io.github.revisto.drum-machine.metainfo.xml.in:23 msgid "Metadata support for embedding artist name, song title, and cover art" msgstr "" "მეტამონაცემების მხარდაჭერა შემსრულებლის სახელის, სიმღერის სახელის და ყდის ჩასაშენებლად" #: data/io.github.revisto.drum-machine.metainfo.xml.in:24 msgid "Keyboard shortcuts for quick access to all functions" msgstr "კლავიატურის მალსახმობები ფუნქციებთან სწრაფი წვდომისთვის" #: data/io.github.revisto.drum-machine.metainfo.xml.in:33 msgid "Drum Pattern Loaded in Light Mode" msgstr "Drum Pattern ჩატვირთულია ღია რეჟიმში" #: data/io.github.revisto.drum-machine.metainfo.xml.in:37 msgid "Drum Pattern Loaded in Dark Mode" msgstr "Drum Pattern ჩატვირთულია მუქ რეჟიმში" #: src/application.py:74 msgid "" "Drum Machine is a modern and intuitive application for creating, playing, and managing " "drum patterns." msgstr "" "Drum Machine თანამედროვე და ინტუიციური აპლიკაციაა დრამის ნიმუშების შესაქმნელად, " "დასაკრავად და სამართავად." #: src/application.py:79 msgid "translator-credits" msgstr "თემური დოღონაძე" #: src/application.py:84 msgid "Special thanks" msgstr "განსაკუთრებული მადლობა" #: src/application.py:87 msgid "Sounds" msgstr "ხმები" #: src/application.py:88 #, python-brace-format msgid "The drum samples used in this application are from {link}." msgstr "დრამის ნუმუშები, რომლებიც ამ აპლიკაციაში გამოიყენება, მოდის ბმულიდან {link}." #: src/config/export_formats.py:44 msgid "MP3 files" msgstr "MP3 ფაილები" #: src/config/export_formats.py:45 msgid "MP3" msgstr "MP3" #: src/config/export_formats.py:51 msgid "FLAC files" msgstr "FLAC ფაილები" #: src/config/export_formats.py:52 msgid "FLAC (Lossless)" msgstr "FLAC (კარგვის გარეშე)" #: src/config/export_formats.py:58 msgid "Ogg files" msgstr "Ogg ფაილები" #: src/config/export_formats.py:59 msgid "Ogg Vorbis" msgstr "Ogg Vorbis" #: src/config/export_formats.py:65 msgid "WAV files" msgstr "WAV ფაილები" #: src/config/export_formats.py:66 msgid "WAV (Uncompressed)" msgstr "WAV (შეუკუმშავი)" #: src/dialogs/audio_export_dialog.py:119 msgid "Save Audio File" msgstr "აუდიოფაილის შენახვა" #: src/dialogs/audio_export_dialog.py:148 msgid "Part “{}” is Silent" msgstr "ნაწილი “{}” ჩუმია" #: src/dialogs/audio_export_dialog.py:150 msgid "Parts “{}” and “{}” are Silent" msgstr "ნაწილები “{}” და “{}” ჩუმია" #: src/dialogs/audio_export_dialog.py:154 msgid "{} Parts are Silent" msgstr "{} ნაწილი ჩუმია" #: src/dialogs/audio_export_dialog.py:179 msgid "Image files" msgstr "გამოსახულების ფაილები" #: src/dialogs/audio_export_dialog.py:185 msgid "Select Cover Art" msgstr "აირჩიეთ ყდის სურათი" #: src/dialogs/audio_export_dialog.py:245 msgid "Audio exported to {}" msgstr "აუდიო გატანილია ფაილში {}" #: src/dialogs/audio_export_dialog.py:251 msgid "Export failed" msgstr "გატანის შეცდომა" #: src/dialogs/audio_export_dialog.py:258 msgid "Export cancelled successfully" msgstr "გატანა წარმატებით გაუქმდა" #: src/dialogs/midi_mapping_dialog.py:22 msgid "Acoustic Bass Drum" msgstr "აკუსტიკური ბას-დრამი" #: src/dialogs/midi_mapping_dialog.py:23 msgid "Bass Drum 1" msgstr "ბას-დრამი 1" #: src/dialogs/midi_mapping_dialog.py:24 msgid "Side Stick" msgstr "გვერდითი ჯოხი" #: src/dialogs/midi_mapping_dialog.py:25 msgid "Acoustic Snare" msgstr "აკუსტიკური დოლი" #: src/dialogs/midi_mapping_dialog.py:26 msgid "Hand Clap" msgstr "ტაშის დაკვრა" #: src/dialogs/midi_mapping_dialog.py:27 msgid "Electric Snare" msgstr "ელექტროდოლი" #: src/dialogs/midi_mapping_dialog.py:28 msgid "Low Floor Tom" msgstr "Low Floor Tom" #: src/dialogs/midi_mapping_dialog.py:29 msgid "Closed Hi Hat" msgstr "დახურული ჰაი ჰეტი" #: src/dialogs/midi_mapping_dialog.py:30 msgid "High Floor Tom" msgstr "High Floor Tom" #: src/dialogs/midi_mapping_dialog.py:31 msgid "Pedal Hi Hat" msgstr "Pedal Hi Hat" #: src/dialogs/midi_mapping_dialog.py:32 msgid "Low Tom" msgstr "Low Tom" #: src/dialogs/midi_mapping_dialog.py:33 msgid "Open Hi Hat" msgstr "Open Hi Hat" #: src/dialogs/midi_mapping_dialog.py:34 msgid "Low-Mid Tom" msgstr "Low-Mid Tom" #: src/dialogs/midi_mapping_dialog.py:35 msgid "Hi-Mid Tom" msgstr "Hi-Mid Tom" #: src/dialogs/midi_mapping_dialog.py:36 msgid "Crash Cymbal 1" msgstr "დასარტყამი თეფში 1" #: src/dialogs/midi_mapping_dialog.py:37 msgid "High Tom" msgstr "High Tom" #: src/dialogs/midi_mapping_dialog.py:38 msgid "Ride Cymbal 1" msgstr "Ride Cymbal 1" #: src/dialogs/midi_mapping_dialog.py:39 msgid "Chinese Cymbal" msgstr "ჩინური თეფში" #: src/dialogs/midi_mapping_dialog.py:40 msgid "Ride Bell" msgstr "Ride Bell" #: src/dialogs/midi_mapping_dialog.py:41 msgid "Tambourine" msgstr "დაირა" #: src/dialogs/midi_mapping_dialog.py:42 msgid "Splash Cymbal" msgstr "Splash Cymbal" #: src/dialogs/midi_mapping_dialog.py:43 msgid "Cowbell" msgstr "ეჟვანი" #: src/dialogs/midi_mapping_dialog.py:44 msgid "Crash Cymbal 2" msgstr "Crash Cymbal 2" #: src/dialogs/midi_mapping_dialog.py:45 msgid "Vibraslap" msgstr "Vibraslap" #: src/dialogs/midi_mapping_dialog.py:46 msgid "Ride Cymbal 2" msgstr "Ride Cymbal 2" #: src/dialogs/midi_mapping_dialog.py:47 msgid "Hi Bongo" msgstr "Hi Bongo" #: src/dialogs/midi_mapping_dialog.py:48 msgid "Low Bongo" msgstr "Low Bongo" #: src/dialogs/midi_mapping_dialog.py:49 msgid "Mute Hi Conga" msgstr "მაღალი კონგას დადუმება" #: src/dialogs/midi_mapping_dialog.py:50 msgid "Open Hi Conga" msgstr "მაღალი კონგას გახსნა" #: src/dialogs/midi_mapping_dialog.py:51 msgid "Low Conga" msgstr "დაბალი კონნგა" #: src/dialogs/midi_mapping_dialog.py:52 msgid "High Timbale" msgstr "High Timbale" #: src/dialogs/midi_mapping_dialog.py:53 msgid "Low Timbale" msgstr "Low Timbale" #: src/dialogs/midi_mapping_dialog.py:54 msgid "High Agogo" msgstr "High Agogo" #: src/dialogs/midi_mapping_dialog.py:55 msgid "Low Agogo" msgstr "Low Agogo" #: src/dialogs/midi_mapping_dialog.py:56 msgid "Cabasa" msgstr "Cabasa" #: src/dialogs/midi_mapping_dialog.py:57 msgid "Maracas" msgstr "მარაკები" #: src/dialogs/midi_mapping_dialog.py:58 msgid "Short Whistle" msgstr "მოკლე სტვენა" #: src/dialogs/midi_mapping_dialog.py:59 msgid "Long Whistle" msgstr "გრძელი სტვენა" #: src/dialogs/midi_mapping_dialog.py:60 msgid "Short Guiro" msgstr "მოკლე პერკუსია" #: src/dialogs/midi_mapping_dialog.py:61 msgid "Long Guiro" msgstr "გრძელი პერკუსია" #: src/dialogs/midi_mapping_dialog.py:62 msgid "Claves" msgstr "Claves" #: src/dialogs/midi_mapping_dialog.py:63 msgid "Hi Wood Block" msgstr "მაღალი ხის ბლოკი" #: src/dialogs/midi_mapping_dialog.py:64 msgid "Low Wood Block" msgstr "დაბალი ის ბლოკი" #: src/dialogs/midi_mapping_dialog.py:65 msgid "Mute Cuica" msgstr "Mute Cuica" #: src/dialogs/midi_mapping_dialog.py:66 msgid "Open Cuica" msgstr "Open Cuica" #: src/dialogs/midi_mapping_dialog.py:67 msgid "Mute Triangle" msgstr "სამკუთხედის დადუმება" #: src/dialogs/midi_mapping_dialog.py:68 msgid "Open Triangle" msgstr "სამკუთხედის გახსნა" #: src/dialogs/midi_mapping_dialog.py:78 src/ui/drum_grid_builder.py:338 msgid "MIDI Mapping" msgstr "MIDI-ის ასახვა" #. Group 1: Note Assignment #: src/dialogs/midi_mapping_dialog.py:108 msgid "Note Assignment" msgstr "ნოტის მინიჭება" #: src/dialogs/midi_mapping_dialog.py:111 msgid "Assign a MIDI note for '{}'. This ensures correct playback when exporting." msgstr "მიანიჭეთ MIDI ნოტა '{}'-ისთვის. ეს უზრუნველყოფს სწორად დაკვრას გატანისას." #. Action Row for Note #: src/dialogs/midi_mapping_dialog.py:118 msgid "MIDI Note" msgstr "MIDI ნოტა" #: src/dialogs/midi_mapping_dialog.py:119 msgid "The note number to trigger" msgstr "ნოტის ნომერი გასააქტიურებლად" #. Group 2: Standard Instruments #: src/dialogs/midi_mapping_dialog.py:137 msgid "Standard Instruments" msgstr "სტანდარტული ინსტრუმენტები" #: src/dialogs/midi_mapping_dialog.py:139 msgid "Select a General MIDI instrument to automatically set the note." msgstr "აირჩიეთ ზოგადი MIDI ინსტრუმენტი ნოტის ავტომატურად დასაყენებლად." #: src/dialogs/midi_mapping_dialog.py:143 msgid "Instrument Preset" msgstr "ინსტრუმენტის პრესეტი" #: src/dialogs/midi_mapping_dialog.py:186 msgid "Save" msgstr "შენახვა" #: src/dialogs/midi_mapping_dialog.py:229 msgid "Custom Note" msgstr "მორგებული ნოტა" #: src/handlers/drag_drop_handler.py:113 msgid "Sound replaced" msgstr "ხმა შეიცვალა" #: src/handlers/drag_drop_handler.py:116 msgid "Failed to replace sound" msgstr "ხმის შეცვლა ჩავარდა" #: src/handlers/drag_drop_handler.py:126 msgid "Not a supported audio file" msgstr "მხარდაჭერილი აუდიოფაილი არაა" #: src/handlers/drag_drop_handler.py:134 msgid "File not found" msgstr "ფაილი ვერ მოიძებნა" #: src/handlers/drag_drop_handler.py:139 msgid "Selected item is not a file" msgstr "მონიშნული ელემენტი ფაილი არაა" #: src/handlers/drag_drop_handler.py:146 msgid "File too large: {:.1f}MB (max 50MB)" msgstr "ფაილი მეტისმეტად დიდია: {:.1f}მბ (მაქს 50მბ)" #: src/handlers/drag_drop_handler.py:174 msgid "No valid audio files found" msgstr "სწორი აუდიოფაილები აღმოჩენილი არაა" #: src/handlers/drag_drop_handler.py:209 msgid "Error processing file: {}" msgstr "ფაილის დამუშავების შეცდომა: {}" #: src/handlers/drag_drop_handler.py:237 msgid "Added {} drum part, {} files skipped" msgstr "დაემატა {} დრამის ნაწილი. გამოტოვებულია {} ფაილი" #: src/handlers/drag_drop_handler.py:243 msgid "Added {} drum parts, {} files skipped" msgstr "დაემატა {} დრამის ნაწილი. გამოტოვებულია {} ფაილი" #: src/handlers/drag_drop_handler.py:248 msgid "Added {} drum parts" msgstr "დაემატა {} დრამის ნაწილი" #. Only show skipped message if no replacement happened #: src/handlers/drag_drop_handler.py:251 msgid "{} files skipped" msgstr "გამოტოვებულია {} ფაილი" #: src/handlers/file_dialog_handler.py:52 msgid "Default Patterns" msgstr "ნაგულისხმევი ნიმუშები" #: src/handlers/file_dialog_handler.py:84 msgid "No Pattern" msgstr "ნიმუშების გარეშე" #: src/handlers/file_dialog_handler.py:85 msgid "Please create a drum pattern before exporting audio." msgstr "აირჩიეთ დრამის ნიმუში აუდიოს გატანამდე." #: src/handlers/file_dialog_handler.py:87 msgid "_OK" msgstr "_დიახ" #: src/handlers/file_dialog_handler.py:110 src/handlers/file_dialog_handler.py:187 msgid "MIDI files" msgstr "MIDI ფაილები" #: src/handlers/file_dialog_handler.py:116 msgid "Open MIDI File" msgstr "MIDI ფაილის გახსნა" #: src/handlers/file_dialog_handler.py:144 msgid "Failed to open file" msgstr "ფაილის გახსნის შეცდომა" #: src/handlers/file_dialog_handler.py:181 msgid "Failed to load pattern" msgstr "ნიმუშის ჩატვირთვა ჩავარდა" #: src/handlers/file_dialog_handler.py:195 msgid "Save Sequence" msgstr "მიმდევრობის შენახვა" #: src/handlers/file_dialog_handler.py:221 msgid "Add Audio Samples" msgstr "აუდიოს ნიმუშების დამატება" #: src/handlers/file_dialog_handler.py:243 msgid "Audio files" msgstr "აუდიო ფაილები" #: src/utils/export_progress.py:76 msgid "Preparing…" msgstr "მომზადება…" #: src/utils/export_progress.py:77 msgid "Initializing…" msgstr "ინიციალიზაცია…" #: src/utils/export_progress.py:79 msgid "Rendering audio…" msgstr "აუდიოს რენდერი…" #: src/utils/export_progress.py:80 msgid "Processing beats…" msgstr "ტაქტის დამუშავება…" #: src/utils/export_progress.py:82 msgid "Saving file…" msgstr "ფაილის შენახვა…" #: src/utils/export_progress.py:83 msgid "Writing to disk…" msgstr "დისკზე ჩაწერა…" #: src/utils/export_progress.py:85 msgid "Exporting…" msgstr "გატანა…" #: src/utils/export_progress.py:86 msgid "Processing…" msgstr "დამუშავება…" #: src/utils/name_utils.py:36 msgid "Custom Sound" msgstr "მორგებული ხმა" #: src/ui/drum_grid_builder.py:323 msgid "Preview" msgstr "მინიატურა" #: src/ui/drum_grid_builder.py:325 msgid "Replace…" msgstr "ჩანაცვლება…" #: src/ui/drum_grid_builder.py:328 msgid "Replace with new sound" msgstr "ჩანაცვლება ახალი ხმით" #: src/ui/drum_grid_builder.py:331 msgid "Remove" msgstr "წაშლა" #: src/ui/drum_grid_builder.py:334 msgid "At least one drum part must remain" msgstr "უნდა დარჩეს, სულ ცოტა, ერთი დრამის ნაწილი" #: src/ui/drum_grid_builder.py:341 msgid "Configure MIDI note for export" msgstr "მოირგეთ MIDI ნოტა გასატანად" #: src/ui/drum_grid_builder.py:398 msgid "MIDI note updated" msgstr "MIDI-ის ნოტა განახლდა" #: src/ui/drum_grid_builder.py:406 msgid "Select New Sound" msgstr "ახალი ხმის არჩევა" #: src/ui/drum_grid_builder.py:420 msgid "Removed drum part: {}" msgstr "წაიშალა დრამის ნაწილი: {}" #: src/ui/drum_grid_builder.py:424 msgid "Failed to remove drum part" msgstr "დრამის ნაწილის წაშლის შეცდომა" #. Update tooltip and accessibility with current BPM #: src/window.py:203 msgid "{} Beats per Minute (BPM)" msgstr "{} დარტყმა წუთში (BPM)" #. Update button tooltip to show current volume level #: src/window.py:212 msgid "{:.0f}% Volume" msgstr "{:.0f}% ხმა" #: src/window.py:227 src/window.ui:170 msgid "Play" msgstr "დაკვრა" #: src/window.py:231 msgid "Pause" msgstr "შეჩერება" #: src/window.py:278 msgid "Open" msgstr "გახსნა" #: src/window.py:296 msgid "Added: {}" msgstr "დაემატა: {}" #: src/window.py:311 msgid "Failed to add custom sound" msgstr "მორგებული ხმის დამატება ჩავარდა" #: src/window.py:318 msgid "Replaced drum with: {}" msgstr "დრამი ჩანაცვლდა: {}" #: src/window.py:326 msgid "Failed to replace drum sound" msgstr "დრამის ხმის ჩანაცვლების შეცდომა" #: src/window.ui:52 msgid "Open…" msgstr "გახსნა…" #: src/window.ui:54 msgid "Open Pattern" msgstr "ნიმუშის გახსნა" #: src/window.ui:57 msgctxt "accessibility" msgid "Open Pattern" msgstr "ნიმუშის გახსნა" #: src/window.ui:58 msgid "Open Saved Drum Pattern" msgstr "შენახული დრამის ნიმუშის გახსნა" #: src/window.ui:76 msgid "Main Menu" msgstr "მთავარი მენიუ" #: src/window.ui:78 msgctxt "accessibility" msgid "Main Menu" msgstr "მთავარი მენიუ" #: src/window.ui:79 msgid "Access Keyboard Shortcuts and Application Information" msgstr "წვდომა კლავიატურის მალსახმობებთან და აპლიკაციის ინფორმაციასთან" #: src/window.ui:86 msgid "Export Audio…" msgstr "აუდიოს გატანა…" #: src/window.ui:88 msgctxt "accessibility" msgid "Export Audio…" msgstr "აუდიოს გატანა…" #: src/window.ui:89 msgid "Export Current Drum Pattern as Audio File" msgstr "მიმდინარე დრამის ნიმუშის შენახვა აუდიო ფაილის სახით" #: src/window.ui:134 msgid "BPM" msgstr "BPM" #: src/window.ui:139 src/window.ui:143 msgid "Adjust Tempo In Beats per Minute (BPM)" msgstr "გაასწორეთ ტემპი 'დარტყმა წუთში' ერთეულით (BPM)" #: src/window.ui:142 msgid "Tempo" msgstr "ტემპი" #: src/window.ui:184 msgid "Adjust Volume" msgstr "ხმის მორგება" #: src/window.ui:207 msgid "Reset" msgstr "ჩამოყრა" #: src/window.ui:208 msgid "Reset the Drum Sequence" msgstr "დრამის მიმდევრობის ჩამოყრა" #: src/window.ui:223 msgid "_Add Samples…" msgstr "ნიმუშების დ_ამატება…" #: src/window.ui:227 msgid "_Save Pattern…" msgstr "ნიმუში_ს შენახვა…" #: src/window.ui:233 msgid "_Keyboard Shortcuts" msgstr "_კლავიატურის მალსახმობები" #: src/window.ui:237 msgid "_About Drum Machine" msgstr "დრამის მანქანის შეს_ახებ" #: src/gtk/help-overlay.blp:11 msgctxt "shortcut window" msgid "General" msgstr "ზოგადი" #: src/gtk/help-overlay.blp:14 msgctxt "shortcut window" msgid "Show Shortcuts" msgstr "მალსახმობების ჩვენება" #: src/gtk/help-overlay.blp:19 msgctxt "shortcut window" msgid "Quit" msgstr "გასვლა" #: src/gtk/help-overlay.blp:26 msgctxt "shortcut window" msgid "Playback Controls" msgstr "დაკვრის ელემენტები" #: src/gtk/help-overlay.blp:29 msgctxt "shortcut window" msgid "Play/Pause" msgstr "დაკვრა/პაუზა" #: src/gtk/help-overlay.blp:35 msgctxt "shortcut window" msgid "Clear All" msgstr "ყველას გასუფთავება" #: src/gtk/help-overlay.blp:42 msgctxt "shortcut window" msgid "BPM & Volume Controls" msgstr "BPM & ხმის კონტროლი" #: src/gtk/help-overlay.blp:45 msgctxt "shortcut window" msgid "Increase BPM" msgstr "BPM-ის გაზრდა" #: src/gtk/help-overlay.blp:51 msgctxt "shortcut window" msgid "Decrease BPM" msgstr "BPM-ის შემცირება" #: src/gtk/help-overlay.blp:57 msgctxt "shortcut window" msgid "Increase Volume" msgstr "ხმის აწევა" #: src/gtk/help-overlay.blp:63 msgctxt "shortcut window" msgid "Decrease Volume" msgstr "ხმის დაწევა" #: src/gtk/help-overlay.blp:69 msgctxt "shortcut window" msgid "Mute" msgstr "დადუმება" #: src/gtk/help-overlay.blp:76 msgctxt "shortcut window" msgid "Pattern Management" msgstr "ნიმუშების მართვა" #: src/gtk/help-overlay.blp:79 msgctxt "shortcut window" msgid "Load Pattern" msgstr "ნიმუშის ჩატვირთვა" #: src/gtk/help-overlay.blp:85 msgctxt "shortcut window" msgid "Save Pattern" msgstr "ნიმუშის შენახვა" #: src/gtk/help-overlay.blp:91 msgctxt "shortcut window" msgid "Export Audio" msgstr "აუდიოს გატანა" #: src/gtk/help-overlay.blp:98 msgctxt "shortcut window" msgid "Navigation" msgstr "ნავიგაცია" #: src/gtk/help-overlay.blp:101 msgctxt "shortcut window" msgid "Go to Instrument" msgstr "ინსტრუმენტზე გადასვლა" #: src/gtk/help-overlay.blp:107 msgctxt "shortcut window" msgid "Previous Page" msgstr "წინა გვერდი" #: src/gtk/help-overlay.blp:113 msgctxt "shortcut window" msgid "Next Page" msgstr "შემდეგი გვერდი" #: src/gtk/save-changes-dialog.blp:5 msgid "Save Changes?" msgstr "შევინახო ცვლილებები?" #: src/gtk/save-changes-dialog.blp:6 msgid "" "Current pattern contains unsaved changes. Changes which are not saved will be " "permanently lost." msgstr "" "მიმდინარე ნიმუში შეუნახავ ცვლილებს შეიცავს. ცვლილებები, რომლებსაც არ შეინახავთ, " "სამუდამოდ დაიკარგება." #. Translators: Cancel the operation #: src/gtk/save-changes-dialog.blp:14 msgid "_Cancel" msgstr "_შეწყვეტა" #. Translators: Discard all changes #: src/gtk/save-changes-dialog.blp:15 msgid "_Discard" msgstr "_მოცილება" #. Translators: Save current changes #: src/gtk/save-changes-dialog.blp:16 msgid "_Save" msgstr "_შენახვა" #: src/gtk/audio-export-dialog.blp:6 src/gtk/audio-export-dialog.blp:101 msgid "Export Audio" msgstr "აუდიოს გატანა" #: src/gtk/audio-export-dialog.blp:44 msgid "Audio Format" msgstr "აუდიოფორმატი" #: src/gtk/audio-export-dialog.blp:50 msgid "Repeat Count" msgstr "გამეორების რაოდენობა" #: src/gtk/audio-export-dialog.blp:51 msgid "How many times to repeat the pattern" msgstr "რამდენჯერ გავიმეორო ნიმუში" #: src/gtk/audio-export-dialog.blp:64 msgid "Metadata" msgstr "მეტამონაცემები" #: src/gtk/audio-export-dialog.blp:67 msgid "Artist Name" msgstr "შემსრულებლის სახელი" #: src/gtk/audio-export-dialog.blp:72 msgid "Song Name" msgstr "სიმღერის სახელი" #: src/gtk/audio-export-dialog.blp:77 msgid "Cover Art" msgstr "ყდის სურათი" #: src/gtk/audio-export-dialog.blp:81 msgid "Choose File…" msgstr "აირჩიეთ ფაილი…" #: src/gtk/audio-export-dialog.blp:110 msgid "Cancel Export" msgstr "გატანის გაუქმება" #~ msgctxt "accessibility" #~ msgid "Open Preset" #~ msgstr "პრესეტის გახსნა" #~ msgctxt "accessibility" #~ msgid "Export Audio" #~ msgstr "აუდიოს გატანა" #~ msgctxt "shortcut window" #~ msgid "Load Preset" #~ msgstr "პრესეტის ჩატვირთვა" #~ msgctxt "shortcut window" #~ msgid "Save Preset" #~ msgstr "პრესეტის შენახვა" #~ msgid "Export Settings" #~ msgstr "გატანის მორგება" #~ msgid "Select the output audio format" #~ msgstr "აირჩიეთ გამოტანის აუდიოფორმატი" #~ msgid "Add metadata to your exported audio" #~ msgstr "მეტამონაცემების დამატება თქვენი გატანილი აუდიოსთვის" #~ msgid "Select an image file for the cover art" #~ msgstr "აირჩიეთ გამოსახულების ფაილი ყდის სურათისთვის" #~ msgctxt "accessibility" #~ msgid "Save Drum Pattern" #~ msgstr "დრამის ნიმუშის შენახვა" drum-machine-2.2.0/po/meson.build000066400000000000000000000000551514070543000166430ustar00rootroot00000000000000i18n.gettext('drum-machine', preset: 'glib') drum-machine-2.2.0/po/nl.po000066400000000000000000000303131514070543000154520ustar00rootroot00000000000000# Dutch translation for drum-machine. # Copyright (C) 2025 drum-machine's COPYRIGHT HOLDER # This file is distributed under the same license as the drum-machine package. # Dick Groskamp , 2025. # Nathan Follens , 2025. # msgid "" msgstr "" "Project-Id-Version: drum-machine master\n" "Report-Msgid-Bugs-To: https://github.com/revisto/drum-machine/issues\n" "POT-Creation-Date: 2025-10-12 03:26+0000\n" "PO-Revision-Date: 2025-10-12 17:06+0200\n" "Last-Translator: Nathan Follens \n" "Language-Team: GNOME-NL https://matrix.to/#/#nl:gnome.org\n" "Language: nl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Poedit 3.6\n" #: data/io.github.revisto.drum-machine.desktop.in:2 data/io.github.revisto.drum-machine.metainfo.xml.in:6 src/window.ui:69 msgid "Drum Machine" msgstr "Drummachine" #. Translators: Search terms to find this application. Do NOT translate or localise the semicolons! The list MUST also end with a semicolon! #: data/io.github.revisto.drum-machine.desktop.in:9 msgid "drum;drums;sequencer;rhythm;music;pattern;beats;percussion;loop;groove;" msgstr "drum;drums;sequencer;rhythm;music;pattern;beats;percussion;loop;groove;drummen;ritme;muziek;patroon,slagen;percussie;" #: data/io.github.revisto.drum-machine.metainfo.xml.in:7 msgid "Create and play drum beats" msgstr "Maak drumbeats en speel ze af" #: data/io.github.revisto.drum-machine.metainfo.xml.in:9 msgid "" "Drum Machine is a modern and intuitive application for creating, playing, and managing drum patterns. Perfect for " "musicians, producers, and anyone interested in rhythm creation, this application provides a simple interface for drum " "pattern programming. Have fun!" msgstr "" "Drummachine is een moderne en intuïtieve toepassing voor het maken, afspelen en beheren van drumpatronen. Perfect voor " "musici, producers en iedereen die is geïnteresseerd in het maken van ritmes, verschaft deze toepassing een eenvoudige " "interface voor het programmeren van drumpatronen. Veel plezier!" #: data/io.github.revisto.drum-machine.metainfo.xml.in:15 msgid "Features:" msgstr "Functies:" #: data/io.github.revisto.drum-machine.metainfo.xml.in:17 msgid "Intuitive grid-based pattern editor" msgstr "Intuïtieve op raster gebaseerde bewerker voor patronen" #: data/io.github.revisto.drum-machine.metainfo.xml.in:18 msgid "Adjustable BPM control" msgstr "Aanpasbare bpm-besturing" #: data/io.github.revisto.drum-machine.metainfo.xml.in:19 msgid "Volume control for overall mix" msgstr "Volume beheren voor algehele mix" #: data/io.github.revisto.drum-machine.metainfo.xml.in:20 msgid "Save and load preset patterns" msgstr "Vooringestelde patronen opslaan en laden" #: data/io.github.revisto.drum-machine.metainfo.xml.in:21 msgid "Multiple drum sounds including kick, snare, hi-hat, and more" msgstr "Meerdere drumgeluiden, inclusief kick, snare, hi-hat en meer" #: data/io.github.revisto.drum-machine.metainfo.xml.in:22 msgid "Audio export feature with support for WAV, FLAC, Ogg, and MP3 formats" msgstr "Audio-exportfunctie met ondersteuning voor WAV-, FLAC-, Ogg- en MP3-indelingen" #: data/io.github.revisto.drum-machine.metainfo.xml.in:23 msgid "Metadata support for embedding artist name, song title, and cover art" msgstr "Metadata-ondersteuning voor inbedden van artiestnamen, tracktitels en albumhoezen" #: data/io.github.revisto.drum-machine.metainfo.xml.in:24 msgid "Keyboard shortcuts for quick access to all functions" msgstr "Sneltoetsen voor snelle toegang tot alle functies" #: data/io.github.revisto.drum-machine.metainfo.xml.in:33 msgid "Drum Pattern Loaded in Light Mode" msgstr "Drumpatroon geladen in modus Licht" #: data/io.github.revisto.drum-machine.metainfo.xml.in:37 msgid "Drum Pattern Loaded in Dark Mode" msgstr "Drumpatroon geladen in modus Donker" #: src/application.py:69 msgid "translator-credits" msgstr "" "Nathan Follens \n" "Dick Groskamp \n" "Meer info over GNOME-NL https://nl.gnome.org" #: src/config/export_formats.py:43 msgid "MP3 files" msgstr "MP3-bestanden" #: src/config/export_formats.py:44 msgid "MP3" msgstr "MP3" #: src/config/export_formats.py:50 msgid "FLAC files" msgstr "FLAC-bestanden" #: src/config/export_formats.py:51 msgid "FLAC (Lossless)" msgstr "FLAC (verliesloos)" #: src/config/export_formats.py:57 msgid "Ogg files" msgstr "Ogg-bestanden" #: src/config/export_formats.py:58 msgid "Ogg Vorbis" msgstr "Ogg Vorbis" #: src/config/export_formats.py:64 msgid "WAV files" msgstr "WAV-bestanden" #: src/config/export_formats.py:65 msgid "WAV (Uncompressed)" msgstr "WAV (niet gecomprimeerd)" #: src/dialogs/audio_export_dialog.py:115 msgid "Save Audio File" msgstr "Audiobestand opslaan" #: src/dialogs/audio_export_dialog.py:139 msgid "Image files" msgstr "Afbeeldingsbestanden" #: src/dialogs/audio_export_dialog.py:145 msgid "Select Cover Art" msgstr "Selecteer een albumhoes" #: src/dialogs/audio_export_dialog.py:202 msgid "Audio exported to {}" msgstr "Audio geëxporteerd naar {}" #: src/dialogs/audio_export_dialog.py:207 msgid "Export failed" msgstr "Exporteren mislukt" #: src/dialogs/audio_export_dialog.py:214 msgid "Export cancelled successfully" msgstr "Exporteren met succes geannuleerd" #: src/handlers/file_dialog_handler.py:51 msgid "Default Presets" msgstr "Standaardvoorinstellingen" #: src/handlers/file_dialog_handler.py:83 msgid "No Pattern" msgstr "Geen patroon" #: src/handlers/file_dialog_handler.py:84 msgid "Please create a drum pattern before exporting audio." msgstr "Maak een drumpatroon voordat u de audio exporteert." #: src/handlers/file_dialog_handler.py:86 msgid "_OK" msgstr "_Oké" #: src/handlers/file_dialog_handler.py:109 src/handlers/file_dialog_handler.py:177 msgid "MIDI files" msgstr "MIDI-bestanden" #: src/handlers/file_dialog_handler.py:115 msgid "Open MIDI File" msgstr "MIDI-bestand openen" #: src/handlers/file_dialog_handler.py:185 msgid "Save Sequence" msgstr "Reeks opslaan" #: src/utils/export_progress.py:68 msgid "Preparing..." msgstr "Voorbereiden…" #: src/utils/export_progress.py:69 msgid "Initializing..." msgstr "Initialiseren…" #: src/utils/export_progress.py:71 msgid "Rendering audio..." msgstr "Audio renderen…" #: src/utils/export_progress.py:72 msgid "Processing beats..." msgstr "Beats verwerken…" #: src/utils/export_progress.py:74 msgid "Saving file..." msgstr "Bestand opslaan…" #: src/utils/export_progress.py:75 msgid "Writing to disk..." msgstr "Schrijven naar schijf…" #: src/utils/export_progress.py:77 msgid "Exporting..." msgstr "Exporteren…" #: src/utils/export_progress.py:78 msgid "Processing..." msgstr "Verwerken…" #. Update tooltip and accessibility with current BPM #: src/window.py:198 msgid "{} Beats per Minute (BPM)" msgstr "{} beats per minuut (bpm)" #. Update button tooltip to show current volume level #: src/window.py:207 msgid "{:.0f}% Volume" msgstr "{:.0f}% volume" #: src/window.py:222 src/window.ui:170 msgid "Play" msgstr "Afspelen" #: src/window.py:226 msgid "Pause" msgstr "Pauzeren" #: src/window.py:264 src/window.ui:52 msgid "Open" msgstr "Openen" #: src/window.ui:54 msgid "Open Preset" msgstr "Voorinstelling openen" #: src/window.ui:57 msgctxt "accessibility" msgid "Open Preset" msgstr "Voorinstelling openen" #: src/window.ui:58 msgid "Open Saved Drum Pattern Preset" msgstr "Opgeslagen voorinstelling voor drumpatroon openen" #: src/window.ui:76 msgid "Main Menu" msgstr "Hoofdmenu" #: src/window.ui:78 msgctxt "accessibility" msgid "Main Menu" msgstr "Hoofdmenu" #: src/window.ui:79 msgid "Access Keyboard Shortcuts and Application Information" msgstr "Toegang tot sneltoetsen en informatie over de toepassing" #: src/window.ui:86 src/gtk/audio-export-dialog.blp:6 src/gtk/audio-export-dialog.blp:96 msgid "Export Audio" msgstr "Audio exporteren" #: src/window.ui:88 msgctxt "accessibility" msgid "Export Audio" msgstr "Audio exporteren" #: src/window.ui:89 msgid "Export Current Drum Pattern as Audio File" msgstr "Huidige drumpatroon exporteren als audiobestand" #: src/window.ui:134 msgid "BPM" msgstr "Bpm" #: src/window.ui:139 src/window.ui:143 msgid "Adjust Tempo In Beats per Minute (BPM)" msgstr "Tempo aanpassen in beats per minuut (bpm)" #: src/window.ui:142 msgid "Tempo" msgstr "Tempo" #: src/window.ui:184 msgid "Adjust Volume" msgstr "Volume aanpassen" #: src/window.ui:207 msgid "Reset" msgstr "Opnieuw instellen" #: src/window.ui:208 msgid "Reset the Drum Sequence" msgstr "Drumreeks opnieuw instellen" #: src/window.ui:223 msgid "_Save Pattern" msgstr "Patroon op_slaan" #: src/window.ui:229 msgid "_Keyboard Shortcuts" msgstr "_Sneltoetsen" #: src/window.ui:233 msgid "_About Drum Machine" msgstr "_Over Drummachine" #: src/gtk/help-overlay.blp:11 msgctxt "shortcut window" msgid "General" msgstr "Algemeen" #: src/gtk/help-overlay.blp:14 msgctxt "shortcut window" msgid "Show Shortcuts" msgstr "Sneltoetsen tonen" #: src/gtk/help-overlay.blp:19 msgctxt "shortcut window" msgid "Quit" msgstr "Afsluiten" #: src/gtk/help-overlay.blp:26 msgctxt "shortcut window" msgid "Playback Controls" msgstr "Besturingselementen voor afspelen" #: src/gtk/help-overlay.blp:29 msgctxt "shortcut window" msgid "Play/Pause" msgstr "Afspelen/pauzeren" #: src/gtk/help-overlay.blp:35 msgctxt "shortcut window" msgid "Clear All" msgstr "Alles leegmaken" #: src/gtk/help-overlay.blp:42 msgctxt "shortcut window" msgid "BPM & Volume Controls" msgstr "Besturingselementen voor bpm & volume" #: src/gtk/help-overlay.blp:45 msgctxt "shortcut window" msgid "Increase BPM" msgstr "Bpm verhogen" #: src/gtk/help-overlay.blp:51 msgctxt "shortcut window" msgid "Decrease BPM" msgstr "Bpm verlagen" #: src/gtk/help-overlay.blp:57 msgctxt "shortcut window" msgid "Increase Volume" msgstr "Volume verhogen" #: src/gtk/help-overlay.blp:63 msgctxt "shortcut window" msgid "Decrease Volume" msgstr "Volume verlagen" #: src/gtk/help-overlay.blp:69 msgctxt "shortcut window" msgid "Mute" msgstr "Dempen" #: src/gtk/help-overlay.blp:76 msgctxt "shortcut window" msgid "Preset Management" msgstr "Voorinstellingen beheren" #: src/gtk/help-overlay.blp:79 msgctxt "shortcut window" msgid "Load Preset" msgstr "Voorinstelling laden" #: src/gtk/help-overlay.blp:85 msgctxt "shortcut window" msgid "Save Preset" msgstr "Voorinstelling opslaan" #: src/gtk/help-overlay.blp:91 msgctxt "shortcut window" msgid "Export Audio" msgstr "Audio exporteren" #: src/gtk/help-overlay.blp:98 msgctxt "shortcut window" msgid "Navigation" msgstr "Navigatie" #: src/gtk/help-overlay.blp:101 msgctxt "shortcut window" msgid "Go to Instrument" msgstr "Ga naar instrument" #: src/gtk/help-overlay.blp:107 msgctxt "shortcut window" msgid "Previous Page" msgstr "Vorige pagina" #: src/gtk/help-overlay.blp:113 msgctxt "shortcut window" msgid "Next Page" msgstr "Volgende pagina" #: src/gtk/save-changes-dialog.blp:5 msgid "Save Changes?" msgstr "Wijzigingen opslaan?" #: src/gtk/save-changes-dialog.blp:6 msgid "Current preset contains unsaved changes. Changes which are not saved will be permanently lost." msgstr "" "De huidige voorinstelling bevat niet-opgeslagen wijzigingen. Wijzigingen die u niet opslaat gaan definitief verloren." #. Translators: Cancel the operation #: src/gtk/save-changes-dialog.blp:14 msgid "_Cancel" msgstr "_Annuleren" #. Translators: Discard all changes #: src/gtk/save-changes-dialog.blp:15 msgid "_Discard" msgstr "_Verwerpen" #. Translators: Save current changes #: src/gtk/save-changes-dialog.blp:16 msgid "_Save" msgstr "Op_slaan" #: src/gtk/audio-export-dialog.blp:39 msgid "Audio Format" msgstr "Audioformaat" #: src/gtk/audio-export-dialog.blp:45 msgid "Repeat Count" msgstr "Aantal herhalingen" #: src/gtk/audio-export-dialog.blp:46 msgid "How many times to repeat the pattern" msgstr "Hoeveel keer het patroon herhaald moet worden" #: src/gtk/audio-export-dialog.blp:59 msgid "Metadata" msgstr "Metadata" #: src/gtk/audio-export-dialog.blp:62 msgid "Artist Name" msgstr "Artiestennaam" #: src/gtk/audio-export-dialog.blp:67 msgid "Song Name" msgstr "Liedjesnaam" #: src/gtk/audio-export-dialog.blp:72 msgid "Cover Art" msgstr "Albumhoes" #: src/gtk/audio-export-dialog.blp:76 msgid "Choose File" msgstr "Bestand kiezen" #: src/gtk/audio-export-dialog.blp:105 msgid "Cancel Export" msgstr "Exporteren annuleren" drum-machine-2.2.0/po/pt_BR.po000066400000000000000000000374121514070543000160560ustar00rootroot00000000000000# Brazilian Portuguese translations for drum-machine package. # Copyright (C) 2025 drum-machine'S COPYRIGHT HOLDER # This file is distributed under the same license as the drum-machine package. # Tiago Lucas FLach , 2025. # Rafael Fontenelle , 2025. # Álvaro Burns <>, 2025. # Juliano de Souza Camargo , 2025. # msgid "" msgstr "" "Project-Id-Version: drum-machine\n" "Report-Msgid-Bugs-To: https://github.com/revisto/drum-machine/issues\n" "POT-Creation-Date: 2025-09-20 15:25+0000\n" "PO-Revision-Date: 2025-09-20 18:56-0300\n" "Last-Translator: Juliano de Souza Camargo \n" "Language-Team: Brazilian Portuguese \n" "Language: pt_BR\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Gtranslator 49.0\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" #: data/io.github.revisto.drum-machine.desktop.in:2 #: data/io.github.revisto.drum-machine.metainfo.xml.in:6 src/window.ui:69 msgid "Drum Machine" msgstr "Drum Machine" #. Translators: Search terms to find this application. Do NOT translate or localise the semicolons! The list MUST also end with a semicolon! #: data/io.github.revisto.drum-machine.desktop.in:9 msgid "drum;drums;sequencer;rhythm;music;pattern;beats;percussion;loop;groove;" msgstr "drum;drums;sequenciador;ritmo;música;padrão;batidas;percussão;loop;groove;" #: data/io.github.revisto.drum-machine.metainfo.xml.in:7 msgid "Create and play drum beats" msgstr "Crie e toque batidas de bateria" #: data/io.github.revisto.drum-machine.metainfo.xml.in:9 msgid "" "Drum Machine is a modern and intuitive application for creating, playing, " "and managing drum patterns. Perfect for musicians, producers, and anyone " "interested in rhythm creation, this application provides a simple interface " "for drum pattern programming. Have fun!" msgstr "" "Drum Machine é um aplicativo moderno e intuitivo para criar, tocar e " "gerenciar padrões de bateria. Perfeito para músicos, produtores e qualquer " "pessoa interessada em criação de ritmos, este aplicativo fornece uma " "interface simples para programação de padrões de bateria. Divirta-se!" #: data/io.github.revisto.drum-machine.metainfo.xml.in:15 msgid "Features:" msgstr "Características:" #: data/io.github.revisto.drum-machine.metainfo.xml.in:17 msgid "Intuitive grid-based pattern editor" msgstr "Editor de padrões intuitivo baseado em grade" #: data/io.github.revisto.drum-machine.metainfo.xml.in:18 msgid "Adjustable BPM control" msgstr "Controle de BPM ajustável" #: data/io.github.revisto.drum-machine.metainfo.xml.in:19 msgid "Volume control for overall mix" msgstr "Controle de volume para mixagem geral" #: data/io.github.revisto.drum-machine.metainfo.xml.in:20 msgid "Save and load preset patterns" msgstr "Salvar e carregar padrões predefinidos" #: data/io.github.revisto.drum-machine.metainfo.xml.in:21 msgid "Multiple drum sounds including kick, snare, hi-hat, and more" msgstr "Vários sons de bateria, incluindo bumbo, caixa, chimbau e muito mais" #: data/io.github.revisto.drum-machine.metainfo.xml.in:22 msgid "Audio export feature with support for WAV, FLAC, Ogg, and MP3 formats" msgstr "" "Funcionalidade de exportar áudio com suporte para os formatos WAV, FLAC, Ogg " "e MP3" #: data/io.github.revisto.drum-machine.metainfo.xml.in:23 msgid "Metadata support for embedding artist name, song title, and cover art" msgstr "" "Suporte de metadados para embutir nome de artista, título da música, e arte " "da capa" #: data/io.github.revisto.drum-machine.metainfo.xml.in:24 msgid "Keyboard shortcuts for quick access to all functions" msgstr "Atalhos de teclado para acesso rápido a todas as funções" #: data/io.github.revisto.drum-machine.metainfo.xml.in:33 msgid "Drum Pattern Loaded in Light Mode" msgstr "Padrão de bateria carregado no modo claro" #: data/io.github.revisto.drum-machine.metainfo.xml.in:37 msgid "Drum Pattern Loaded in Dark Mode" msgstr "Padrão de bateria carregado no modo escuro" #: src/application.py:69 msgid "translator-credits" msgstr "" "Álvaro Burns\n" "Rafael Fontenelle \n" "Tiago Lucas FLach \n" "Juliano de Souza Camargo " #: src/config/export_formats.py:43 msgid "MP3 files" msgstr "Arquivos MP3" #: src/config/export_formats.py:44 msgid "MP3" msgstr "MP3" #: src/config/export_formats.py:50 msgid "FLAC files" msgstr "Arquivos FLAC" #: src/config/export_formats.py:51 msgid "FLAC (Lossless)" msgstr "FLAC (sem perdas)" #: src/config/export_formats.py:57 msgid "Ogg files" msgstr "Arquivos Ogg" #: src/config/export_formats.py:58 msgid "Ogg Vorbis" msgstr "Ogg Vorbis" #: src/config/export_formats.py:64 msgid "WAV files" msgstr "Arquivos WAV" #: src/config/export_formats.py:65 msgid "WAV (Uncompressed)" msgstr "WAV (sem compressão)" #: src/dialogs/audio_export_dialog.py:115 msgid "Save Audio File" msgstr "Salvar arquivo de áudio" #: src/dialogs/audio_export_dialog.py:139 msgid "Image files" msgstr "Arquivos de imagem" #: src/dialogs/audio_export_dialog.py:145 msgid "Select Cover Art" msgstr "Selecione a arte da capa" #: src/dialogs/audio_export_dialog.py:202 msgid "Audio exported to {}" msgstr "Áudio exportado para {}" #: src/dialogs/audio_export_dialog.py:207 msgid "Export failed" msgstr "Falha ao exportar" #: src/dialogs/audio_export_dialog.py:214 msgid "Export cancelled successfully" msgstr "Exportar cancelado com sucesso" #: src/handlers/file_dialog_handler.py:51 msgid "Default Presets" msgstr "Predefinições padrão" #: src/handlers/file_dialog_handler.py:83 msgid "No Pattern" msgstr "Sem padrão" #: src/handlers/file_dialog_handler.py:84 msgid "Please create a drum pattern before exporting audio." msgstr "Favor criar um padrão de bateria antes de exportar o áudio." #: src/handlers/file_dialog_handler.py:86 msgid "_OK" msgstr "_OK" #: src/handlers/file_dialog_handler.py:109 #: src/handlers/file_dialog_handler.py:177 msgid "MIDI files" msgstr "Arquivos MIDI" #: src/handlers/file_dialog_handler.py:115 msgid "Open MIDI File" msgstr "Abrir arquivo MIDI" #: src/handlers/file_dialog_handler.py:185 msgid "Save Sequence" msgstr "Salvar sequência" #: src/utils/export_progress.py:68 msgid "Preparing..." msgstr "Preparando..." #: src/utils/export_progress.py:69 msgid "Initializing..." msgstr "Inicializando..." #: src/utils/export_progress.py:71 msgid "Rendering audio..." msgstr "Renderizando áudio..." #: src/utils/export_progress.py:72 msgid "Processing beats..." msgstr "Processando batidas..." #: src/utils/export_progress.py:74 msgid "Saving file..." msgstr "Guardando o arquivo..." #: src/utils/export_progress.py:75 msgid "Writing to disk..." msgstr "Escrevendo no disco..." #: src/utils/export_progress.py:77 msgid "Exporting..." msgstr "Exportando..." #: src/utils/export_progress.py:78 msgid "Processing..." msgstr "Processando..." #. Update tooltip and accessibility with current BPM #: src/window.py:198 msgid "{} Beats per Minute (BPM)" msgstr "{} batidas por minuto (BPM)" #. Update button tooltip to show current volume level #: src/window.py:207 msgid "{:.0f}% Volume" msgstr "{:.0f}% volume" #: src/window.py:222 src/window.ui:170 msgid "Play" msgstr "Reproduz" #: src/window.py:226 msgid "Pause" msgstr "Pausa" #: src/window.py:264 src/window.ui:52 msgid "Open" msgstr "Abrir" #: src/window.ui:54 msgid "Open Preset" msgstr "Abrir predefinição" #: src/window.ui:57 msgctxt "accessibility" msgid "Open Preset" msgstr "Abrir predefinição" #: src/window.ui:58 msgid "Open Saved Drum Pattern Preset" msgstr "Abrir predefinição padrão de bateria salva" #: src/window.ui:76 msgid "Main Menu" msgstr "Menu principal" #: src/window.ui:78 msgctxt "accessibility" msgid "Main Menu" msgstr "Menu principal" #: src/window.ui:79 msgid "Access Keyboard Shortcuts and Application Information" msgstr "Acesse atalhos de teclado e informações do aplicativo" #: src/window.ui:86 src/gtk/audio-export-dialog.blp:6 #: src/gtk/audio-export-dialog.blp:96 msgid "Export Audio" msgstr "Exportar áudio" #: src/window.ui:88 msgctxt "accessibility" msgid "Export Audio" msgstr "Exportar áudio" #: src/window.ui:89 msgid "Export Current Drum Pattern as Audio File" msgstr "Exporta o atual padrão de bateria como um arquivo de áudio" #: src/window.ui:134 msgid "BPM" msgstr "BPM" #: src/window.ui:139 src/window.ui:143 msgid "Adjust Tempo In Beats per Minute (BPM)" msgstr "Ajusta o tempo em batidas por minuto (BPM)" #: src/window.ui:142 msgid "Tempo" msgstr "Tempo" #: src/window.ui:184 msgid "Adjust Volume" msgstr "Ajusta o volume" #: src/window.ui:207 msgid "Reset" msgstr "Reiniciar" #: src/window.ui:208 msgid "Reset the Drum Sequence" msgstr "Reinicia a sequência de bateria" #: src/window.ui:223 msgid "_Save Pattern" msgstr "_Salvar padrão" #: src/window.ui:229 msgid "_Keyboard Shortcuts" msgstr "Atalhos de _teclado" #: src/window.ui:233 msgid "_About Drum Machine" msgstr "_Sobre o Drum Machine" #: src/gtk/help-overlay.blp:11 msgctxt "shortcut window" msgid "General" msgstr "Geral" #: src/gtk/help-overlay.blp:14 msgctxt "shortcut window" msgid "Show Shortcuts" msgstr "Mostra os atalhos" #: src/gtk/help-overlay.blp:19 msgctxt "shortcut window" msgid "Quit" msgstr "Sai" #: src/gtk/help-overlay.blp:26 msgctxt "shortcut window" msgid "Playback Controls" msgstr "Controles de reprodução" #: src/gtk/help-overlay.blp:29 msgctxt "shortcut window" msgid "Play/Pause" msgstr "Reproduzir/Pausar" #: src/gtk/help-overlay.blp:35 msgctxt "shortcut window" msgid "Clear All" msgstr "Limpa tudo" #: src/gtk/help-overlay.blp:42 msgctxt "shortcut window" msgid "BPM & Volume Controls" msgstr "Controles de BPM e volume" #: src/gtk/help-overlay.blp:45 msgctxt "shortcut window" msgid "Increase BPM" msgstr "Aumenta o BPM" #: src/gtk/help-overlay.blp:51 msgctxt "shortcut window" msgid "Decrease BPM" msgstr "Diminui o BPM" #: src/gtk/help-overlay.blp:57 msgctxt "shortcut window" msgid "Increase Volume" msgstr "Aumenta o volume" #: src/gtk/help-overlay.blp:63 msgctxt "shortcut window" msgid "Decrease Volume" msgstr "Diminui o volume" #: src/gtk/help-overlay.blp:69 msgctxt "shortcut window" msgid "Mute" msgstr "Mudo" #: src/gtk/help-overlay.blp:76 msgctxt "shortcut window" msgid "Preset Management" msgstr "Gerenciamento de predefinições" #: src/gtk/help-overlay.blp:79 msgctxt "shortcut window" msgid "Load Preset" msgstr "Carrega a predefinição" #: src/gtk/help-overlay.blp:85 msgctxt "shortcut window" msgid "Save Preset" msgstr "Salva a predefinição" #: src/gtk/help-overlay.blp:91 msgctxt "shortcut window" msgid "Export Audio" msgstr "Exporta áudio" #: src/gtk/help-overlay.blp:98 msgctxt "shortcut window" msgid "Navigation" msgstr "Navegação" #: src/gtk/help-overlay.blp:101 msgctxt "shortcut window" msgid "Go to Instrument" msgstr "Vai para o instrumento" #: src/gtk/help-overlay.blp:107 msgctxt "shortcut window" msgid "Previous Page" msgstr "Página anterior" #: src/gtk/help-overlay.blp:113 msgctxt "shortcut window" msgid "Next Page" msgstr "Próxima página" #: src/gtk/save-changes-dialog.blp:5 msgid "Save Changes?" msgstr "Salvar alterações?" #: src/gtk/save-changes-dialog.blp:6 msgid "" "Current preset contains unsaved changes. Changes which are not saved will be " "permanently lost." msgstr "" "A predefinição atual contém alterações não salvas. As alterações que não " "forem salvas serão perdidas permanentemente." #. Translators: Cancel the operation #: src/gtk/save-changes-dialog.blp:14 msgid "_Cancel" msgstr "_Cancelar" #. Translators: Discard all changes #: src/gtk/save-changes-dialog.blp:15 msgid "_Discard" msgstr "_Descartar" #. Translators: Save current changes #: src/gtk/save-changes-dialog.blp:16 msgid "_Save" msgstr "_Salvar" #: src/gtk/audio-export-dialog.blp:39 msgid "Audio Format" msgstr "Formato de áudio" #: src/gtk/audio-export-dialog.blp:45 msgid "Repeat Count" msgstr "Contagem de repetições" #: src/gtk/audio-export-dialog.blp:46 msgid "How many times to repeat the pattern" msgstr "Quantas vezes para se repetir o padrão" #: src/gtk/audio-export-dialog.blp:59 msgid "Metadata" msgstr "Metadados" #: src/gtk/audio-export-dialog.blp:62 msgid "Artist Name" msgstr "Nome do artista" #: src/gtk/audio-export-dialog.blp:67 msgid "Song Name" msgstr "Nome da música" #: src/gtk/audio-export-dialog.blp:72 msgid "Cover Art" msgstr "Arte da capa" #: src/gtk/audio-export-dialog.blp:76 msgid "Choose File" msgstr "Escolher arquivo" #: src/gtk/audio-export-dialog.blp:105 msgid "Cancel Export" msgstr "Cancelar exportação" #~ msgid "Export Settings" #~ msgstr "Exportar configurações" #~ msgid "Configure your audio export options" #~ msgstr "Configure as opções de exportação de áudio" #~ msgid "Select the output audio format" #~ msgstr "Selecionar o formato de áudio da saída" #~ msgid "Add metadata to your exported audio" #~ msgstr "Adicionar metadados no seu áudio exportado" #~ msgid "Select an image file for the cover art" #~ msgstr "Selecionar um arquivo de imagem para a arte da capa" #~ msgctxt "accessibility" #~ msgid "Save Drum Pattern" #~ msgstr "Salvar padrão de bateria" #~ msgid "drum" #~ msgstr "bateria" #~ msgid "machine" #~ msgstr "máquina" #~ msgid "rhythm" #~ msgstr "ritmo" #~ msgid "music" #~ msgstr "música" #~ msgid "beats" #~ msgstr "batidas" #~ msgid "Revisto" #~ msgstr "Revisão" #~ msgid "" #~ "This release of Drum Machine 1.3.1 brings significant UI and " #~ "functionality improvements:" #~ msgstr "" #~ "Esta versão do Drum Machine 1.3.1 traz melhorias significativas na " #~ "interface do usuário e na funcionalidade:" #~ msgid "" #~ "Refactored headerbar and background styling for a flat, integrated visual " #~ "experience." #~ msgstr "" #~ "Barra de cabeçalho e estilo de fundo reformulados para uma experiência " #~ "visual plana e integrada." #~ msgid "" #~ "Enhanced accessibility with improved tooltips and descriptive labels for " #~ "BPM and volume controls." #~ msgstr "" #~ "Acessibilidade aprimorada com dicas de ferramentas aprimoradas e rótulos " #~ "descritivos para controles de BPM e volume." #~ msgid "" #~ "Redesigned app icon and updated text styling for clearer user interface " #~ "elements." #~ msgstr "" #~ "Ícone do aplicativo redesenhado e estilo de texto atualizado para " #~ "elementos de interface de usuário mais claros." #~ msgid "" #~ "Optimized layout breakpoints to improve responsiveness and reduce early " #~ "scrolling." #~ msgstr "" #~ "Pontos de interrupção de layout otimizados para melhorar a capacidade de " #~ "resposta e reduzir a rolagem inicial." #~ msgid "" #~ "Fixed padding, border-radius, and vertical alignment issues across " #~ "multiple controls." #~ msgstr "" #~ "Problemas corrigidos de preenchimento, raio de borda e alinhamento " #~ "vertical em vários controles." #~ msgid "" #~ "Updated file dialogs to use the Nautilus file chooser for a more modern " #~ "approach." #~ msgstr "" #~ "Caixas de diálogo de arquivo atualizadas para usar o seletor de arquivos " #~ "Nautilus para uma abordagem mais moderna." #~ msgid "" #~ "Improved keyboard navigation focus and updated tooltips, including " #~ "dedicated play and pause hints." #~ msgstr "" #~ "Foco de navegação do teclado aprimorado e dicas de ferramentas " #~ "atualizadas, incluindo dicas dedicadas de reprodução e pausa." #~ msgid "" #~ "Transitioned to the Nautilus file chooser for a more contemporary " #~ "interface." #~ msgstr "" #~ "Transição para o seletor de arquivos Nautilus para uma interface mais " #~ "contemporânea." #~ msgid "Now accessible on narrow mobile screens with adaptive UI elements." #~ msgstr "" #~ "Agora acessível em telas estreitas de dispositivos móveis com elementos " #~ "de interface de usuário adaptáveis." #~ msgid "Refined app icon, and adjusted brand colors for better contrast." #~ msgstr "" #~ "Ícone do aplicativo refinado e cores da marca ajustadas para melhor " #~ "contraste." drum-machine-2.2.0/po/ru.po000066400000000000000000000233161514070543000154740ustar00rootroot00000000000000# Russian translation for drum-machine. # Copyright (C) 2025 drum-machine's COPYRIGHT HOLDER # This file is distributed under the same license as the drum-machine package. # wineT , 2025. # FULL NAME , 2025. # Анатолий Богомолов (wineT) , 2025. # msgid "" msgstr "" "Project-Id-Version: drum-machine master\n" "Report-Msgid-Bugs-To: https://github.com/revisto/drum-machine/issues\n" "POT-Creation-Date: 2025-08-13 03:26+0000\n" "PO-Revision-Date: 2025-08-13 14:20+0300\n" "Last-Translator: Artur So \n" "Language-Team: Russian\n" "Language: ru\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && " "n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" "X-Generator: Poedit 3.6\n" #: data/io.github.revisto.drum-machine.desktop.in:2 #: data/io.github.revisto.drum-machine.metainfo.xml.in:6 src/window.ui:67 msgid "Drum Machine" msgstr "Ритм-машина" #: data/io.github.revisto.drum-machine.metainfo.xml.in:7 msgid "Create and play drum beats" msgstr "Создавайте и проигрывайте барабанные ритмы" #: data/io.github.revisto.drum-machine.metainfo.xml.in:9 msgid "" "Drum Machine is a modern and intuitive application for creating, playing, " "and managing drum patterns. Perfect for musicians, producers, and anyone " "interested in rhythm creation, this application provides a simple interface " "for drum pattern programming. Have fun!" msgstr "" "Ритм-машина - это современное и интуитивно понятное приложение для создания, " "воспроизведения и управления барабанными рисунками. Это приложение идеально " "подходит для музыкантов, продюсеров и всех, кто интересуется созданием " "ритмов. Приложение предоставляет простой интерфейс для программирования " "барабанных рисунков. Веселитесь!" #: data/io.github.revisto.drum-machine.metainfo.xml.in:15 msgid "Features:" msgstr "Функции:" #: data/io.github.revisto.drum-machine.metainfo.xml.in:17 msgid "Intuitive grid-based pattern editor" msgstr "Интуитивный сеточный редактор ритмов" #: data/io.github.revisto.drum-machine.metainfo.xml.in:18 msgid "Adjustable BPM control" msgstr "Настраиваемый BPM" #: data/io.github.revisto.drum-machine.metainfo.xml.in:19 msgid "Volume control for overall mix" msgstr "Управление громкостью для всего микса" #: data/io.github.revisto.drum-machine.metainfo.xml.in:20 msgid "Save and load preset patterns" msgstr "Сохранение и загрузка предустановленных рисунков" #: data/io.github.revisto.drum-machine.metainfo.xml.in:21 msgid "Multiple drum sounds including kick, snare, hi-hat, and more" msgstr "Множество звуков ударных, включая бочку, малый, хай-хэт и прочее" #: data/io.github.revisto.drum-machine.metainfo.xml.in:22 msgid "Keyboard shortcuts for quick access to all functions" msgstr "Комбинации клавиш для быстрого доступа ко всем функциям" #: data/io.github.revisto.drum-machine.metainfo.xml.in:31 msgid "Drum Pattern Loaded in Light Mode" msgstr "Барабанный рисунок загружен в светлом режиме" #: data/io.github.revisto.drum-machine.metainfo.xml.in:35 msgid "Drum Pattern Loaded in Dark Mode" msgstr "Барабанный рисунок загружен в тёмном режиме" #: src/application.py:69 msgid "translator-credits" msgstr "Анатолий Богомолов (wineT) " #. Update tooltip and accessibility with current BPM #: src/window.py:190 msgid "{} Beats per Minute (BPM)" msgstr "{} Ударов в минуту (BPM)" #. Update button tooltip to show current volume level #: src/window.py:199 msgid "{:.0f}% Volume" msgstr "Громкость {:.0f}%" #: src/window.py:214 src/window.ui:167 msgid "Play" msgstr "Проиграть" #: src/window.py:218 msgid "Pause" msgstr "Пауза" #: src/window.ui:50 msgid "Open" msgstr "Открыть" #: src/window.ui:52 msgid "Open Preset" msgstr "Открыть рисунок" #: src/window.ui:55 msgctxt "accessibility" msgid "Open Preset" msgstr "Открыть рисунок" #: src/window.ui:56 msgid "Open Saved Drum Pattern Preset" msgstr "Открыть сохранённый барабанный рисунок" #: src/window.ui:74 msgid "Main Menu" msgstr "Главное меню" #: src/window.ui:76 msgctxt "accessibility" msgid "Main Menu" msgstr "Главное меню" #: src/window.ui:77 msgid "Access Keyboard Shortcuts and Application Information" msgstr "Доступ к комбинациям клавиш и информации о приложении" #: src/window.ui:84 msgid "Save Drum Pattern" msgstr "Сохранить барабанный рисунок" #: src/window.ui:86 msgctxt "accessibility" msgid "Save Drum Pattern" msgstr "Сохранить барабанный рисунок" #: src/window.ui:87 msgid "Save Current Drum Pattern as a Preset File" msgstr "Сохранить текущий барабанный рисунок как файл" #: src/window.ui:131 msgid "BPM" msgstr "BPM" #: src/window.ui:136 src/window.ui:140 msgid "Adjust Tempo In Beats per Minute (BPM)" msgstr "Настройка темпа в ударах в минуту (BPM)" #: src/window.ui:139 msgid "Tempo" msgstr "Темп" #: src/window.ui:181 msgid "Adjust Volume" msgstr "Изменить громкость" #: src/window.ui:204 msgid "Reset" msgstr "Сбросить" #: src/window.ui:205 msgid "Reset the Drum Sequence" msgstr "Сбросить барабанный ритм" #: src/window.ui:218 msgid "_Keyboard Shortcuts" msgstr "_Комбинации клавиш" #: src/window.ui:222 msgid "_About Drum Machine" msgstr "_О приложении" #: src/gtk/help-overlay.ui:11 msgctxt "shortcut window" msgid "General" msgstr "Общие" #: src/gtk/help-overlay.ui:14 msgctxt "shortcut window" msgid "Show Shortcuts" msgstr "Показать комбинации клавиш" #: src/gtk/help-overlay.ui:20 msgctxt "shortcut window" msgid "Quit" msgstr "Выйти" #: src/gtk/help-overlay.ui:29 msgctxt "shortcut window" msgid "Playback Controls" msgstr "Управление воспроизведением" #: src/gtk/help-overlay.ui:32 msgctxt "shortcut window" msgid "Play/Pause" msgstr "Воспроизведение/Пауза" #: src/gtk/help-overlay.ui:39 msgctxt "shortcut window" msgid "Clear All" msgstr "Очистить всё" #: src/gtk/help-overlay.ui:48 msgctxt "shortcut window" msgid "BPM & Volume Controls" msgstr "Управление темпом и громкостью" #: src/gtk/help-overlay.ui:51 msgctxt "shortcut window" msgid "Increase BPM" msgstr "Увеличить BPM" #: src/gtk/help-overlay.ui:58 msgctxt "shortcut window" msgid "Decrease BPM" msgstr "Уменьшить BPM" #: src/gtk/help-overlay.ui:65 msgctxt "shortcut window" msgid "Increase Volume" msgstr "Увеличить громкость" #: src/gtk/help-overlay.ui:72 msgctxt "shortcut window" msgid "Decrease Volume" msgstr "Уменьшить громкость" #: src/gtk/help-overlay.ui:79 msgctxt "shortcut window" msgid "Mute" msgstr "Отключить звук" #: src/gtk/help-overlay.ui:88 msgctxt "shortcut window" msgid "Preset Management" msgstr "Управление рисунками" #: src/gtk/help-overlay.ui:91 msgctxt "shortcut window" msgid "Load Preset" msgstr "Загрузить рисунок" #: src/gtk/help-overlay.ui:98 msgctxt "shortcut window" msgid "Save Preset" msgstr "Сохранить рисунок" #: src/gtk/help-overlay.ui:107 msgctxt "shortcut window" msgid "Navigation" msgstr "Навигация" #: src/gtk/help-overlay.ui:110 msgctxt "shortcut window" msgid "Go to Instrument" msgstr "Перейти к инструменту" #: src/gtk/help-overlay.ui:117 msgctxt "shortcut window" msgid "Previous Page" msgstr "Предыдущая страница" #: src/gtk/help-overlay.ui:124 msgctxt "shortcut window" msgid "Next Page" msgstr "Следующая страница" #: src/gtk/save_changes_dialog.ui:6 msgid "Save Changes?" msgstr "Сохранить изменения?" #: src/gtk/save_changes_dialog.ui:7 msgid "" "Current preset contains unsaved changes. Changes which are not saved will be " "permanently lost." msgstr "" "Текущий рисунок содержит несохраненные изменения. Изменения, которые не были " "сохранены, будут безвозвратно потеряны." #. Cancel the operation #: src/gtk/save_changes_dialog.ui:14 msgid "_Cancel" msgstr "_Отменить" #. Discard all changes #: src/gtk/save_changes_dialog.ui:15 msgid "_Discard" msgstr "_Не сохранять" #. Save current changes #: src/gtk/save_changes_dialog.ui:16 msgid "_Save" msgstr "_Сохранить" #: src/handlers/file_dialog_handler.py:48 msgid "Default Presets" msgstr "Рисунок по умолчанию" #: src/handlers/file_dialog_handler.py:76 #: src/handlers/file_dialog_handler.py:142 msgid "MIDI files" msgstr "MIDI-файлы" #: src/handlers/file_dialog_handler.py:82 msgid "Open MIDI File" msgstr "Открыть MIDI-файл" #: src/handlers/file_dialog_handler.py:148 msgid "Save Sequence" msgstr "Сохранить последовательность" drum-machine-2.2.0/po/sl.po000066400000000000000000000530761514070543000154720ustar00rootroot00000000000000# Slovenian translation for drum-machine. # Copyright (C) 2025 drum-machine's COPYRIGHT HOLDER # This file is distributed under the same license as the drum-machine package. # Martin , 2025. # msgid "" msgstr "" "Project-Id-Version: drum-machine master\n" "Report-Msgid-Bugs-To: https://github.com/revisto/drum-machine/issues\n" "POT-Creation-Date: 2025-12-13 03:26+0000\n" "PO-Revision-Date: 2025-12-13 12:48+0100\n" "Last-Translator: Martin Srebotnjak \n" "Language-Team: Slovenian GNOME Translation Team \n" "Language: sl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=(n%100==1 ? 1 : n%100==2 ? 2 : n%100==3 || n%100==4 ? " "3 : 0);\n" "X-Generator: Poedit 3.8\n" #: data/io.github.revisto.drum-machine.desktop.in:2 #: data/io.github.revisto.drum-machine.metainfo.xml.in:6 src/application.py:67 #: src/window.ui:69 msgid "Drum Machine" msgstr "Bobnarski stroj" #. Translators: Search terms to find this application. Do NOT translate or localise the semicolons! The list MUST also end with a semicolon! #: data/io.github.revisto.drum-machine.desktop.in:9 msgid "drum;drums;sequencer;rhythm;music;pattern;beats;percussion;loop;groove;" msgstr "boben;bobni;sekvenčnik;ritem;glasba;vzorec;udarci;tolkala;zanke;zankanje;groove;" #: data/io.github.revisto.drum-machine.metainfo.xml.in:7 msgid "Create and play drum beats" msgstr "Ustvarjajte in igrajte bobnarske ritme" #: data/io.github.revisto.drum-machine.metainfo.xml.in:9 msgid "" "Drum Machine is a modern and intuitive application for creating, playing, and managing " "drum patterns. Perfect for musicians, producers, and anyone interested in rhythm " "creation, this application provides a simple interface for drum pattern programming. " "Have fun!" msgstr "" "To je sodoben in intuitiven program za ustvarjanje, igranje in upravljanje vzorcev " "bobnov. Kot nalašč za glasbenike, producente in vse, ki jih zanima ustvarjanje ritma. " "Ta program ponuja preprost vmesnik za programiranje vzorcev bobnov. Zabavajte se!" #: data/io.github.revisto.drum-machine.metainfo.xml.in:15 msgid "Features:" msgstr "Funkcionalnosti:" #: data/io.github.revisto.drum-machine.metainfo.xml.in:17 msgid "Intuitive grid-based pattern editor with infinite pages" msgstr "Intuitiven urejevalnik vzorcev, ki temelji na mreži, z neskončnimi stranmi" #: data/io.github.revisto.drum-machine.metainfo.xml.in:18 msgid "Custom samples: Add your own drum sounds with MIDI note mapping" msgstr "Vzorci po meri: dodajte svoje lastne bobnarske zvoke z MIDI-preslikavo not" #: data/io.github.revisto.drum-machine.metainfo.xml.in:19 msgid "Adjustable BPM control" msgstr "Nastavljiv nadzor BPM" #: data/io.github.revisto.drum-machine.metainfo.xml.in:20 msgid "Volume control for overall mix" msgstr "Nadzor glasnosti za celoten miks" #: data/io.github.revisto.drum-machine.metainfo.xml.in:21 msgid "Save and load patterns" msgstr "Shranite in naložite vzorce" #: data/io.github.revisto.drum-machine.metainfo.xml.in:22 msgid "Multiple drum sounds including kick, snare, hi-hat, and more" msgstr "Več zvokov bobnov, vključno z udarcem, zanko, činelo in še več" #: data/io.github.revisto.drum-machine.metainfo.xml.in:23 msgid "Audio and MIDI export with support for WAV, FLAC, Ogg, MP3, and MIDI formats" msgstr "Funkcija izvoza zvoka in MIDI s podporo za zapise WAV, FLAC, Ogg, MP3 in MIDI" #: data/io.github.revisto.drum-machine.metainfo.xml.in:24 msgid "Metadata support for embedding artist name, song title, and cover art" msgstr "Podpora za metapodatke za vdelavo imen izvajalcev, naslova pesmi in naslovnice" #: data/io.github.revisto.drum-machine.metainfo.xml.in:25 msgid "Keyboard shortcuts for quick access to all functions" msgstr "Tipkovne bližnjice za hiter dostop do vseh funkcij" #: data/io.github.revisto.drum-machine.metainfo.xml.in:34 msgid "Drum Pattern Loaded in Light Mode" msgstr "Vzorec bobna naložen v svetlem načinu" #: data/io.github.revisto.drum-machine.metainfo.xml.in:38 msgid "Drum Pattern Loaded in Dark Mode" msgstr "Vzorec bobna naložen v temnem načinu" #: src/application.py:74 msgid "" "Drum Machine is a modern and intuitive application for creating, playing, and managing " "drum patterns." msgstr "" "To je sodoben in intuitiven program za ustvarjanje, igranje in upravljanje vzorcev " "bobnov." #: src/application.py:79 msgid "translator-credits" msgstr "Martin Srebotnjak " #: src/application.py:84 msgid "Special thanks" msgstr "Posebna zahvala" #: src/application.py:87 msgid "Sounds" msgstr "Zvoki" #: src/application.py:88 #, python-brace-format msgid "The drum samples used in this application are from {link}." msgstr "Vzorci bobnov, uporabljeni v tem programu, izhajajo iz {link}." #: src/config/export_formats.py:44 msgid "MP3 files" msgstr "Datoteke MP3" #: src/config/export_formats.py:45 msgid "MP3" msgstr "MP3" #: src/config/export_formats.py:51 msgid "FLAC files" msgstr "Datoteke FLAC" #: src/config/export_formats.py:52 msgid "FLAC (Lossless)" msgstr "FLAC (brez izgub)" #: src/config/export_formats.py:58 msgid "Ogg files" msgstr "Datoteke Ogg" #: src/config/export_formats.py:59 msgid "Ogg Vorbis" msgstr "Ogg Vorbis" #: src/config/export_formats.py:65 msgid "WAV files" msgstr "Datoteke WAV" #: src/config/export_formats.py:66 msgid "WAV (Uncompressed)" msgstr "WAV (nestisnjeno)" #: src/dialogs/audio_export_dialog.py:119 msgid "Save Audio File" msgstr "Shrani zvočno datoteko" #: src/dialogs/audio_export_dialog.py:148 msgid "Part “{}” is Silent" msgstr "Del »{}« je nem" #: src/dialogs/audio_export_dialog.py:150 msgid "Parts “{}” and “{}” are Silent" msgstr "Dela »{}« in »{}« sta nema" #: src/dialogs/audio_export_dialog.py:154 msgid "{} Parts are Silent" msgstr "{} delov je nemih" #: src/dialogs/audio_export_dialog.py:179 msgid "Image files" msgstr "Slikovne datoteke" #: src/dialogs/audio_export_dialog.py:185 msgid "Select Cover Art" msgstr "Izberi naslovnico" #: src/dialogs/audio_export_dialog.py:245 msgid "Audio exported to {}" msgstr "Zvok, izvožen v {}" #: src/dialogs/audio_export_dialog.py:251 msgid "Export failed" msgstr "Izvoz ni uspel" #: src/dialogs/audio_export_dialog.py:258 msgid "Export cancelled successfully" msgstr "Izvoz je bil uspešno preklican" #: src/dialogs/midi_mapping_dialog.py:22 msgid "Acoustic Bass Drum" msgstr "Akustični pedalni bas boben" #: src/dialogs/midi_mapping_dialog.py:23 msgid "Bass Drum 1" msgstr "Predalni bas boben 1" #: src/dialogs/midi_mapping_dialog.py:24 msgid "Side Stick" msgstr "S prečno položeno palico" #: src/dialogs/midi_mapping_dialog.py:25 msgid "Acoustic Snare" msgstr "Akustični mali boben" #: src/dialogs/midi_mapping_dialog.py:26 msgid "Hand Clap" msgstr "Plosk z rokama" #: src/dialogs/midi_mapping_dialog.py:27 msgid "Electric Snare" msgstr "Električni mali boben" #: src/dialogs/midi_mapping_dialog.py:28 msgid "Low Floor Tom" msgstr "Nizki stoječi tom-tom" #: src/dialogs/midi_mapping_dialog.py:29 msgid "Closed Hi Hat" msgstr "Zaprti pedalni čineli" #: src/dialogs/midi_mapping_dialog.py:30 msgid "High Floor Tom" msgstr "Visoki stoječi tom-tom" #: src/dialogs/midi_mapping_dialog.py:31 msgid "Pedal Hi Hat" msgstr "Pedalni čineli" #: src/dialogs/midi_mapping_dialog.py:32 msgid "Low Tom" msgstr "Nizki manjši prehodni boben" #: src/dialogs/midi_mapping_dialog.py:33 msgid "Open Hi Hat" msgstr "Odprti pedalni čineli" #: src/dialogs/midi_mapping_dialog.py:34 msgid "Low-Mid Tom" msgstr "Nizko-srednji manjši prehodni boben" #: src/dialogs/midi_mapping_dialog.py:35 msgid "Hi-Mid Tom" msgstr "Visoko-srednji manjši prehodni boben" #: src/dialogs/midi_mapping_dialog.py:36 msgid "Crash Cymbal 1" msgstr "Viseča činela 1" #: src/dialogs/midi_mapping_dialog.py:37 msgid "High Tom" msgstr "Visoki manjši prehodni boben" #: src/dialogs/midi_mapping_dialog.py:38 msgid "Ride Cymbal 1" msgstr "Ritem činela 1" #: src/dialogs/midi_mapping_dialog.py:39 msgid "Chinese Cymbal" msgstr "Kitajska činela" #: src/dialogs/midi_mapping_dialog.py:40 msgid "Ride Bell" msgstr "Zvonasta ritem činela" #: src/dialogs/midi_mapping_dialog.py:41 msgid "Tambourine" msgstr "Tamburin" #: src/dialogs/midi_mapping_dialog.py:42 msgid "Splash Cymbal" msgstr "Spleš činele" #: src/dialogs/midi_mapping_dialog.py:43 msgid "Cowbell" msgstr "Kravji zvonec" #: src/dialogs/midi_mapping_dialog.py:44 msgid "Crash Cymbal 2" msgstr "Viseča činela 2" #: src/dialogs/midi_mapping_dialog.py:45 msgid "Vibraslap" msgstr "Vibraslap" #: src/dialogs/midi_mapping_dialog.py:46 msgid "Ride Cymbal 2" msgstr "Ritem činela 2" #: src/dialogs/midi_mapping_dialog.py:47 msgid "Hi Bongo" msgstr "Visoki bongi" #: src/dialogs/midi_mapping_dialog.py:48 msgid "Low Bongo" msgstr "Nizki bongi" #: src/dialogs/midi_mapping_dialog.py:49 msgid "Mute Hi Conga" msgstr "Utišaj visoko kongo" #: src/dialogs/midi_mapping_dialog.py:50 msgid "Open Hi Conga" msgstr "Odpri visoko kongo" #: src/dialogs/midi_mapping_dialog.py:51 msgid "Low Conga" msgstr "Nizka konga" #: src/dialogs/midi_mapping_dialog.py:52 msgid "High Timbale" msgstr "Visoki timbali" #: src/dialogs/midi_mapping_dialog.py:53 msgid "Low Timbale" msgstr "Nizki timbali" #: src/dialogs/midi_mapping_dialog.py:54 msgid "High Agogo" msgstr "Visoki agogo zvonci" #: src/dialogs/midi_mapping_dialog.py:55 msgid "Low Agogo" msgstr "Nizki agogo zvonci" #: src/dialogs/midi_mapping_dialog.py:56 msgid "Cabasa" msgstr "Kabasa" #: src/dialogs/midi_mapping_dialog.py:57 msgid "Maracas" msgstr "Marakas" #: src/dialogs/midi_mapping_dialog.py:58 msgid "Short Whistle" msgstr "Kratka piščalka" #: src/dialogs/midi_mapping_dialog.py:59 msgid "Long Whistle" msgstr "Dolga piščalka" #: src/dialogs/midi_mapping_dialog.py:60 msgid "Short Guiro" msgstr "Kratki guiro" #: src/dialogs/midi_mapping_dialog.py:61 msgid "Long Guiro" msgstr "Dolgi guiro" #: src/dialogs/midi_mapping_dialog.py:62 msgid "Claves" msgstr "Klaves" #: src/dialogs/midi_mapping_dialog.py:63 msgid "Hi Wood Block" msgstr "Visoki leseni blok" #: src/dialogs/midi_mapping_dialog.py:64 msgid "Low Wood Block" msgstr "Nizki leseni blok" #: src/dialogs/midi_mapping_dialog.py:65 msgid "Mute Cuica" msgstr "Utišaj kuiko" #: src/dialogs/midi_mapping_dialog.py:66 msgid "Open Cuica" msgstr "Odpri kuiko" #: src/dialogs/midi_mapping_dialog.py:67 msgid "Mute Triangle" msgstr "Utišaj triangel" #: src/dialogs/midi_mapping_dialog.py:68 msgid "Open Triangle" msgstr "Odpri triangel" #: src/dialogs/midi_mapping_dialog.py:78 src/ui/drum_grid_builder.py:338 msgid "MIDI Mapping" msgstr "Preslikava MIDI" #. Group 1: Note Assignment #: src/dialogs/midi_mapping_dialog.py:108 msgid "Note Assignment" msgstr "Dodelitev not" #: src/dialogs/midi_mapping_dialog.py:111 msgid "Assign a MIDI note for '{}'. This ensures correct playback when exporting." msgstr "Za »{}« dodelite noto MIDI. To zagotavlja pravilno predvajanje pri izvozu." #. Action Row for Note #: src/dialogs/midi_mapping_dialog.py:118 msgid "MIDI Note" msgstr "Nota MIDI" #: src/dialogs/midi_mapping_dialog.py:119 msgid "The note number to trigger" msgstr "Številka note za proženje" #. Group 2: Standard Instruments #: src/dialogs/midi_mapping_dialog.py:137 msgid "Standard Instruments" msgstr "Standardni inštrumenti" #: src/dialogs/midi_mapping_dialog.py:139 msgid "Select a General MIDI instrument to automatically set the note." msgstr "Izberite splošni inštrument MIDI, da samodejno nastavite noto." #: src/dialogs/midi_mapping_dialog.py:143 msgid "Instrument Preset" msgstr "Prednastavitev inštrumenta" #: src/dialogs/midi_mapping_dialog.py:186 msgid "Save" msgstr "Shrani" #: src/dialogs/midi_mapping_dialog.py:229 msgid "Custom Note" msgstr "Nota po meri" #: src/handlers/drag_drop_handler.py:113 msgid "Sound replaced" msgstr "Zvok zamenjan" #: src/handlers/drag_drop_handler.py:116 msgid "Failed to replace sound" msgstr "Zamenjava zvoka ni uspela" #: src/handlers/drag_drop_handler.py:126 msgid "Not a supported audio file" msgstr "Ni podprta zvočna datoteka" #: src/handlers/drag_drop_handler.py:134 msgid "File not found" msgstr "Datoteke ni mogoče najti" #: src/handlers/drag_drop_handler.py:139 msgid "Selected item is not a file" msgstr "Izbrani element ni datoteka" #: src/handlers/drag_drop_handler.py:146 msgid "File too large: {:.1f}MB (max 50MB)" msgstr "Prevelika datoteka: {:.1f} MB (največ 50 MB)" #: src/handlers/drag_drop_handler.py:174 msgid "No valid audio files found" msgstr "Ni mogoče najti veljavnih zvočnih datotek" #: src/handlers/drag_drop_handler.py:209 msgid "Error processing file: {}" msgstr "Datoteka pri obdelavi datoteke: {}" #: src/handlers/drag_drop_handler.py:237 msgid "Added {} drum part, {} files skipped" msgstr "Dodan {} bobnarski del, {} datotek preskočenih" #: src/handlers/drag_drop_handler.py:243 msgid "Added {} drum parts, {} files skipped" msgstr "Dodanih {} bobnarskih delov, {} datotek preskočenih" #: src/handlers/drag_drop_handler.py:248 msgid "Added {} drum parts" msgstr "Dodanih {} bobnarskih delov" #. Only show skipped message if no replacement happened #: src/handlers/drag_drop_handler.py:251 msgid "{} files skipped" msgstr "{} preskočenih datotek" #: src/handlers/file_dialog_handler.py:52 msgid "Default Patterns" msgstr "Privzeti vzorci" #: src/handlers/file_dialog_handler.py:92 src/handlers/file_dialog_handler.py:171 msgid "MIDI files" msgstr "Datoteke MIDI" #: src/handlers/file_dialog_handler.py:98 msgid "Open MIDI File" msgstr "Odpri datoteko MIDI" #: src/handlers/file_dialog_handler.py:127 msgid "Failed to open file" msgstr "Ni mogoče odpreti datoteke" #: src/handlers/file_dialog_handler.py:165 msgid "Failed to load pattern" msgstr "Nalaganje vzorca ni uspelo" #: src/handlers/file_dialog_handler.py:179 msgid "Save Sequence" msgstr "Shrani zaporedje" #: src/handlers/file_dialog_handler.py:205 msgid "Add Audio Samples" msgstr "Dodaj zvočne vzorce" #: src/handlers/file_dialog_handler.py:227 msgid "Audio files" msgstr "Zvočne datoteke" #: src/utils/export_progress.py:76 msgid "Preparing…" msgstr "Poteka priprava …" #: src/utils/export_progress.py:77 msgid "Initializing…" msgstr "Inicializacija ..." #: src/utils/export_progress.py:79 msgid "Rendering audio…" msgstr "Izdelovanje zvoka …" #: src/utils/export_progress.py:80 msgid "Processing beats…" msgstr "Obdelovanje ritmičnega vzorca ..." #: src/utils/export_progress.py:82 msgid "Saving file…" msgstr "Shranjevanje datoteke ..." #: src/utils/export_progress.py:83 msgid "Writing to disk…" msgstr "Pisanje na disk ..." #: src/utils/export_progress.py:85 msgid "Exporting…" msgstr "Poteka izvažanje …" #: src/utils/export_progress.py:86 msgid "Processing…" msgstr "Obdelovanje ..." #: src/utils/name_utils.py:36 msgid "Custom Sound" msgstr "Zvok po meri" #: src/ui/drum_grid_builder.py:323 msgid "Preview" msgstr "Predogled" #: src/ui/drum_grid_builder.py:325 msgid "Replace…" msgstr "Zamenjaj …" #: src/ui/drum_grid_builder.py:328 msgid "Replace with new sound" msgstr "Zamenjajte z novim zvokom" #: src/ui/drum_grid_builder.py:331 msgid "Remove" msgstr "Odstrani" #: src/ui/drum_grid_builder.py:334 msgid "At least one drum part must remain" msgstr "Vsaj en bobnarski del mora ostati" #: src/ui/drum_grid_builder.py:341 msgid "Configure MIDI note for export" msgstr "Prilagodi noto MIDI za izvoz" #: src/ui/drum_grid_builder.py:398 msgid "MIDI note updated" msgstr "NNota MIDI posodobljena" #: src/ui/drum_grid_builder.py:406 msgid "Select New Sound" msgstr "Izberite nov zvok" #: src/ui/drum_grid_builder.py:420 msgid "Removed drum part: {}" msgstr "Odstranjen bobnarski del: {}" #: src/ui/drum_grid_builder.py:425 msgid "Failed to remove drum part" msgstr "Ni uspelo odstraniti bobnarskega dela" #. Update tooltip and accessibility with current BPM #: src/window.py:225 msgid "{} Beats per Minute (BPM)" msgstr "{} udarcev na minuto (BPM)" #. Update button tooltip to show current volume level #: src/window.py:234 msgid "{:.0f}% Volume" msgstr "Glasnost {:.0f} %" #: src/window.py:251 src/window.ui:173 msgid "Play" msgstr "Predvajaj" #: src/window.py:255 msgid "Pause" msgstr "Premor" #: src/window.py:302 msgid "Open" msgstr "Odpri" #: src/window.py:320 msgid "Added: {}" msgstr "Dodano: {}" #: src/window.py:335 msgid "Failed to add custom sound" msgstr "Dodajanje zvoka po meri ni uspelo" #: src/window.py:342 msgid "Replaced drum with: {}" msgstr "Boben zamenjan z: {}" #: src/window.py:350 msgid "Failed to replace drum sound" msgstr "Zamenjava zvoka bobnov ni uspela" #: src/window.ui:52 msgid "Open…" msgstr "Odpri …" #: src/window.ui:54 msgid "Open Pattern" msgstr "Odpri vzorec" #: src/window.ui:57 msgctxt "accessibility" msgid "Open Pattern" msgstr "Odpri vzorec" #: src/window.ui:58 msgid "Open Saved Drum Pattern" msgstr "Odpri shranjeni vzorec bobna" #: src/window.ui:76 msgid "Main Menu" msgstr "Glavni meni" #: src/window.ui:78 msgctxt "accessibility" msgid "Main Menu" msgstr "Glavni meni" #: src/window.ui:79 msgid "Access Keyboard Shortcuts and Application Information" msgstr "Dostop do tipkovnih bližnjic in informacij o programih" #: src/window.ui:86 msgid "Export Audio…" msgstr "Izvozi zvok …" #: src/window.ui:91 msgctxt "accessibility" msgid "Export Audio…" msgstr "Izvozi zvok …" #: src/window.ui:92 msgid "Export Current Drum Pattern as Audio File" msgstr "Shrani trenutni vzorec bobna kot zvočno datoteko" #: src/window.ui:137 msgid "BPM" msgstr "UNM (BPM)" #: src/window.ui:142 src/window.ui:146 msgid "Adjust Tempo In Beats per Minute (BPM)" msgstr "Prilagodi tempo v udarcih na minuto (BPM)" #: src/window.ui:145 msgid "Tempo" msgstr "Tempo" #: src/window.ui:187 msgid "Adjust Volume" msgstr "Prilagodi glasnost" #: src/window.ui:210 msgid "Reset" msgstr "Ponastavi" #: src/window.ui:211 msgid "Reset the Drum Sequence" msgstr "Ponastavi zaporedje bobna" #: src/window.ui:226 msgid "_Add Samples…" msgstr "_Dodaj vzorce …" #: src/window.ui:230 msgid "_Save Pattern…" msgstr "_Shrani vzorec …" #: src/window.ui:236 msgid "_Keyboard Shortcuts" msgstr "_Tipkovne bližnjice" #: src/window.ui:240 msgid "_About Drum Machine" msgstr "_O programu Bobnarski stroj" #: src/gtk/help-overlay.blp:11 msgctxt "shortcut window" msgid "General" msgstr "Splošno" #: src/gtk/help-overlay.blp:14 msgctxt "shortcut window" msgid "Show Shortcuts" msgstr "Pokaži tipkovne bližnjice‫" #: src/gtk/help-overlay.blp:19 msgctxt "shortcut window" msgid "Quit" msgstr "Izhod" #: src/gtk/help-overlay.blp:26 msgctxt "shortcut window" msgid "Playback Controls" msgstr "Kontrolniki predvajanja" #: src/gtk/help-overlay.blp:29 msgctxt "shortcut window" msgid "Play/Pause" msgstr "Predvajaj / premor" #: src/gtk/help-overlay.blp:35 msgctxt "shortcut window" msgid "Clear All" msgstr "Počisti vse" #: src/gtk/help-overlay.blp:42 msgctxt "shortcut window" msgid "BPM & Volume Controls" msgstr "BPM in nadzor glasnosti" #: src/gtk/help-overlay.blp:45 msgctxt "shortcut window" msgid "Increase BPM" msgstr "Povečajte BPM" #: src/gtk/help-overlay.blp:51 msgctxt "shortcut window" msgid "Decrease BPM" msgstr "Zmanjšanje BPM" #: src/gtk/help-overlay.blp:57 msgctxt "shortcut window" msgid "Increase Volume" msgstr "Povečaj glasnost" #: src/gtk/help-overlay.blp:63 msgctxt "shortcut window" msgid "Decrease Volume" msgstr "Zmanjšaj glasnost" #: src/gtk/help-overlay.blp:69 msgctxt "shortcut window" msgid "Mute" msgstr "Utišaj" #: src/gtk/help-overlay.blp:76 msgctxt "shortcut window" msgid "Pattern Management" msgstr "Upravljanje vzorcev" #: src/gtk/help-overlay.blp:79 msgctxt "shortcut window" msgid "Load Pattern" msgstr "Naloži vzorec" #: src/gtk/help-overlay.blp:85 msgctxt "shortcut window" msgid "Save Pattern" msgstr "Shrani vzorec" #: src/gtk/help-overlay.blp:91 msgctxt "shortcut window" msgid "Export Audio" msgstr "Izvozi zvok" #: src/gtk/help-overlay.blp:98 msgctxt "shortcut window" msgid "Navigation" msgstr "Krmarjenje" #: src/gtk/help-overlay.blp:101 msgctxt "shortcut window" msgid "Go to Instrument" msgstr "Pojdi na inštrument" #: src/gtk/help-overlay.blp:107 msgctxt "shortcut window" msgid "Previous Page" msgstr "Skoči na predhodno stran" #: src/gtk/help-overlay.blp:113 msgctxt "shortcut window" msgid "Next Page" msgstr "Skoči na naslednjo stran" #: src/gtk/save-changes-dialog.blp:5 msgid "Save Changes?" msgstr "Ali želite shraniti spremembe?" #: src/gtk/save-changes-dialog.blp:6 msgid "" "Current pattern contains unsaved changes. Changes which are not saved will be " "permanently lost." msgstr "" "Trenutni vzorec vsebuje neshranjene spremembe. Spremembe, ki niso shranjene, bodo " "trajno izgubljene." #. Translators: Cancel the operation #: src/gtk/save-changes-dialog.blp:14 msgid "_Cancel" msgstr "Pre_kliči" #. Translators: Discard all changes #: src/gtk/save-changes-dialog.blp:15 msgid "_Discard" msgstr "_Zavrzi" #. Translators: Save current changes #: src/gtk/save-changes-dialog.blp:16 msgid "_Save" msgstr "_Shrani" #: src/gtk/audio-export-dialog.blp:6 src/gtk/audio-export-dialog.blp:101 msgid "Export Audio" msgstr "Izvozi zvok" #: src/gtk/audio-export-dialog.blp:44 msgid "Audio Format" msgstr "Zvočni zapis" #: src/gtk/audio-export-dialog.blp:50 msgid "Repeat Count" msgstr "Število ponovitev" #: src/gtk/audio-export-dialog.blp:51 msgid "How many times to repeat the pattern" msgstr "Kolikokrat želite ponoviti vzorec" #: src/gtk/audio-export-dialog.blp:64 msgid "Metadata" msgstr "Metapodatki" #: src/gtk/audio-export-dialog.blp:67 msgid "Artist Name" msgstr "Ime izvajalca" #: src/gtk/audio-export-dialog.blp:72 msgid "Song Name" msgstr "Ime pesmi" #: src/gtk/audio-export-dialog.blp:77 msgid "Cover Art" msgstr "Naslovnica" #: src/gtk/audio-export-dialog.blp:81 msgid "Choose File…" msgstr "Izberi datoteko ..." #: src/gtk/audio-export-dialog.blp:110 msgid "Cancel Export" msgstr "Prekliči izvoz" drum-machine-2.2.0/po/sv.po000066400000000000000000000176321514070543000155020ustar00rootroot00000000000000# Swedish translation for drum-machine. # Copyright © 2025 drum-machine's COPYRIGHT HOLDER # This file is distributed under the same license as the drum-machine package. # Anders Jonsson , 2025. # msgid "" msgstr "" "Project-Id-Version: drum-machine master\n" "Report-Msgid-Bugs-To: https://github.com/revisto/drum-machine/issues\n" "POT-Creation-Date: 2025-08-12 15:25+0000\n" "PO-Revision-Date: 2025-08-26 01:20+0200\n" "Last-Translator: Anders Jonsson \n" "Language-Team: Swedish \n" "Language: sv\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Poedit 3.7\n" #: data/io.github.revisto.drum-machine.desktop.in:2 #: data/io.github.revisto.drum-machine.metainfo.xml.in:6 src/window.ui:67 msgid "Drum Machine" msgstr "Drum Machine" #: data/io.github.revisto.drum-machine.metainfo.xml.in:7 msgid "Create and play drum beats" msgstr "Skapa och spela trumslag" #: data/io.github.revisto.drum-machine.metainfo.xml.in:9 msgid "" "Drum Machine is a modern and intuitive application for creating, playing, " "and managing drum patterns. Perfect for musicians, producers, and anyone " "interested in rhythm creation, this application provides a simple interface " "for drum pattern programming. Have fun!" msgstr "" "Drum Machine är ett modernt och intuitivt program för att skapa, spela och " "hantera trumslingor. Perfekt för musiker, producenter och alla som är " "intresserade av att skapa rytmer. Detta program tillhandahåller ett enkelt " "gränssnitt för trumslingeprogrammering. Ha så kul!" #: data/io.github.revisto.drum-machine.metainfo.xml.in:15 msgid "Features:" msgstr "Funktioner:" #: data/io.github.revisto.drum-machine.metainfo.xml.in:17 msgid "Intuitive grid-based pattern editor" msgstr "Intuitiv rutnätsbaserad slingredigerare" #: data/io.github.revisto.drum-machine.metainfo.xml.in:18 msgid "Adjustable BPM control" msgstr "Justerbar BPM-kontroll" #: data/io.github.revisto.drum-machine.metainfo.xml.in:19 msgid "Volume control for overall mix" msgstr "Volymkontroll för generell mix" #: data/io.github.revisto.drum-machine.metainfo.xml.in:20 msgid "Save and load preset patterns" msgstr "Spara och läs in förinställda slingor" #: data/io.github.revisto.drum-machine.metainfo.xml.in:21 msgid "Multiple drum sounds including kick, snare, hi-hat, and more" msgstr "Flera trumljud inkluderande bastrumma, virveltrumma, hi-hat med mera" #: data/io.github.revisto.drum-machine.metainfo.xml.in:22 msgid "Keyboard shortcuts for quick access to all functions" msgstr "Tangentbordsgenvägar för snabb åtkomst till alla funktioner" #: data/io.github.revisto.drum-machine.metainfo.xml.in:31 msgid "Drum Pattern Loaded in Light Mode" msgstr "Trumslinga inläst i ljust läge" #: data/io.github.revisto.drum-machine.metainfo.xml.in:35 msgid "Drum Pattern Loaded in Dark Mode" msgstr "Trumslinga inläst i mörkt läge" #: src/application.py:69 msgid "translator-credits" msgstr "Anders Jonsson " #. Update tooltip and accessibility with current BPM #: src/window.py:190 msgid "{} Beats per Minute (BPM)" msgstr "{} slag per minut (BPM)" #. Update button tooltip to show current volume level #: src/window.py:199 msgid "{:.0f}% Volume" msgstr "{:.0f}% volym" #: src/window.py:214 src/window.ui:167 msgid "Play" msgstr "Spela" #: src/window.py:218 msgid "Pause" msgstr "Pausa" #: src/window.ui:50 msgid "Open" msgstr "Öppna" #: src/window.ui:52 msgid "Open Preset" msgstr "Öppna förinställning" #: src/window.ui:55 msgctxt "accessibility" msgid "Open Preset" msgstr "Öppna förinställning" #: src/window.ui:56 msgid "Open Saved Drum Pattern Preset" msgstr "Öppna sparad trumslingeförinställning" #: src/window.ui:74 msgid "Main Menu" msgstr "Huvudmeny" #: src/window.ui:76 msgctxt "accessibility" msgid "Main Menu" msgstr "Huvudmeny" #: src/window.ui:77 msgid "Access Keyboard Shortcuts and Application Information" msgstr "Kom åt tangentbordsgenvägar och programinformation" #: src/window.ui:84 msgid "Save Drum Pattern" msgstr "Spara trumslinga" #: src/window.ui:86 msgctxt "accessibility" msgid "Save Drum Pattern" msgstr "Spara trumslinga" #: src/window.ui:87 msgid "Save Current Drum Pattern as a Preset File" msgstr "Spara aktuell trumslinga som en förinställningsfil" #: src/window.ui:131 msgid "BPM" msgstr "BPM" #: src/window.ui:136 src/window.ui:140 msgid "Adjust Tempo In Beats per Minute (BPM)" msgstr "Justera tempo i slag per minut (BPM)" #: src/window.ui:139 msgid "Tempo" msgstr "Tempo" #: src/window.ui:181 msgid "Adjust Volume" msgstr "Justera volym" #: src/window.ui:204 msgid "Reset" msgstr "Återställ" #: src/window.ui:205 msgid "Reset the Drum Sequence" msgstr "Återställ trumsekvensen" #: src/window.ui:218 msgid "_Keyboard Shortcuts" msgstr "_Tangentbordsgenvägar" #: src/window.ui:222 msgid "_About Drum Machine" msgstr "_Om Drum Machine" #: src/gtk/help-overlay.ui:11 msgctxt "shortcut window" msgid "General" msgstr "Allmänt" #: src/gtk/help-overlay.ui:14 msgctxt "shortcut window" msgid "Show Shortcuts" msgstr "Visa kortkommandon" #: src/gtk/help-overlay.ui:20 msgctxt "shortcut window" msgid "Quit" msgstr "Avsluta" #: src/gtk/help-overlay.ui:29 msgctxt "shortcut window" msgid "Playback Controls" msgstr "Uppspelningskontroller" #: src/gtk/help-overlay.ui:32 msgctxt "shortcut window" msgid "Play/Pause" msgstr "Spela/pausa" #: src/gtk/help-overlay.ui:39 msgctxt "shortcut window" msgid "Clear All" msgstr "Töm alla" #: src/gtk/help-overlay.ui:48 msgctxt "shortcut window" msgid "BPM & Volume Controls" msgstr "BPM- och volymkontroller" #: src/gtk/help-overlay.ui:51 msgctxt "shortcut window" msgid "Increase BPM" msgstr "Öka slag/minut" #: src/gtk/help-overlay.ui:58 msgctxt "shortcut window" msgid "Decrease BPM" msgstr "Minska slag/minut" #: src/gtk/help-overlay.ui:65 msgctxt "shortcut window" msgid "Increase Volume" msgstr "Öka volymen" #: src/gtk/help-overlay.ui:72 msgctxt "shortcut window" msgid "Decrease Volume" msgstr "Sänk volymen" #: src/gtk/help-overlay.ui:79 msgctxt "shortcut window" msgid "Mute" msgstr "Tysta" #: src/gtk/help-overlay.ui:88 msgctxt "shortcut window" msgid "Preset Management" msgstr "Förinställningshantering" #: src/gtk/help-overlay.ui:91 msgctxt "shortcut window" msgid "Load Preset" msgstr "Läs in förinställning" #: src/gtk/help-overlay.ui:98 msgctxt "shortcut window" msgid "Save Preset" msgstr "Spara förinställning" #: src/gtk/help-overlay.ui:107 msgctxt "shortcut window" msgid "Navigation" msgstr "Navigering" #: src/gtk/help-overlay.ui:110 msgctxt "shortcut window" msgid "Go to Instrument" msgstr "Gå till instrument" #: src/gtk/help-overlay.ui:117 msgctxt "shortcut window" msgid "Previous Page" msgstr "Föregående sida" #: src/gtk/help-overlay.ui:124 msgctxt "shortcut window" msgid "Next Page" msgstr "Nästa sida" #: src/gtk/save_changes_dialog.ui:6 msgid "Save Changes?" msgstr "Spara ändringar?" #: src/gtk/save_changes_dialog.ui:7 msgid "" "Current preset contains unsaved changes. Changes which are not saved will be " "permanently lost." msgstr "" "Aktuell förinställning innehåller osparade ändringar. Ändringar som inte " "sparas kommer gå permanent förlorade." #. Cancel the operation #: src/gtk/save_changes_dialog.ui:14 msgid "_Cancel" msgstr "A_vbryt" #. Discard all changes #: src/gtk/save_changes_dialog.ui:15 msgid "_Discard" msgstr "_Förkasta" #. Save current changes #: src/gtk/save_changes_dialog.ui:16 msgid "_Save" msgstr "_Spara" #: src/handlers/file_dialog_handler.py:48 msgid "Default Presets" msgstr "Standardförinställningar" #: src/handlers/file_dialog_handler.py:76 #: src/handlers/file_dialog_handler.py:142 msgid "MIDI files" msgstr "MIDI-filer" #: src/handlers/file_dialog_handler.py:82 msgid "Open MIDI File" msgstr "Öppna MIDI-fil" #: src/handlers/file_dialog_handler.py:148 msgid "Save Sequence" msgstr "Spara sekvens" drum-machine-2.2.0/po/tr.po000066400000000000000000000303301514070543000154650ustar00rootroot00000000000000# Turkish translation for drum-machine. # Copyright (C) 2025 drum-machine's COPYRIGHT HOLDER # This file is distributed under the same license as the drum-machine package. # # Sabri Ünal , 2025. # Emin Tufan Çetin , 2025. # msgid "" msgstr "" "Project-Id-Version: drum-machine master\n" "Report-Msgid-Bugs-To: https://github.com/revisto/drum-machine/issues\n" "POT-Creation-Date: 2025-09-23 15:25+0000\n" "PO-Revision-Date: 2025-09-23 21:03+0300\n" "Last-Translator: Sabri Ünal \n" "Language-Team: Turkish \n" "Language: tr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: Poedit 3.7\n" #: data/io.github.revisto.drum-machine.desktop.in:2 #: data/io.github.revisto.drum-machine.metainfo.xml.in:6 src/window.ui:69 msgid "Drum Machine" msgstr "Davul Makinesi" #. Translators: Search terms to find this application. Do NOT translate or localise the semicolons! The list MUST also end with a semicolon! #: data/io.github.revisto.drum-machine.desktop.in:9 msgid "drum;drums;sequencer;rhythm;music;pattern;beats;percussion;loop;groove;" msgstr "drum;drums;sequencer;rhythm;music;pattern;beats;percussion;loop;groove;davul;davullar;sıralayıcı;rizim;müzik;örüntü;desen;perküsyon;döngü;" #: data/io.github.revisto.drum-machine.metainfo.xml.in:7 msgid "Create and play drum beats" msgstr "Davul ritimleri oluştur ve çal" #: data/io.github.revisto.drum-machine.metainfo.xml.in:9 msgid "" "Drum Machine is a modern and intuitive application for creating, playing, " "and managing drum patterns. Perfect for musicians, producers, and anyone " "interested in rhythm creation, this application provides a simple interface " "for drum pattern programming. Have fun!" msgstr "" "Davul Makinesi; davul örüntülerini oluşturmak, oynatmak ve yönetmek için " "çağdaş ve sezgisel uygulamadır. Müzisyenler, yapımcılar ve ritim " "oluşturmayla ilgilenenler için dört dörtlüktür, bu uygulama davul örüntüsü " "programlama için basit arayüz sağlar. İyi eğlenceler!" #: data/io.github.revisto.drum-machine.metainfo.xml.in:15 msgid "Features:" msgstr "Özellikler:" #: data/io.github.revisto.drum-machine.metainfo.xml.in:17 msgid "Intuitive grid-based pattern editor" msgstr "Sezgisel ızgara tabanlı örüntü düzenleyici" #: data/io.github.revisto.drum-machine.metainfo.xml.in:18 msgid "Adjustable BPM control" msgstr "Ayarlanabilir BPM denetimi" #: data/io.github.revisto.drum-machine.metainfo.xml.in:19 msgid "Volume control for overall mix" msgstr "Genel karışım için ses denetimi" #: data/io.github.revisto.drum-machine.metainfo.xml.in:20 msgid "Save and load preset patterns" msgstr "Ön ayar örüntülerini kaydet ve yükle" #: data/io.github.revisto.drum-machine.metainfo.xml.in:21 msgid "Multiple drum sounds including kick, snare, hi-hat, and more" msgstr "Bas davulu, trampet, hi-hat ve daha çoğunu içeren çoklu davul sesleri" #: data/io.github.revisto.drum-machine.metainfo.xml.in:22 msgid "Audio export feature with support for WAV, FLAC, Ogg, and MP3 formats" msgstr "" "WAV, FLAC, Ogg ve MP3 biçimlerini destekleyen ses dışa aktarma özelliği" #: data/io.github.revisto.drum-machine.metainfo.xml.in:23 msgid "Metadata support for embedding artist name, song title, and cover art" msgstr "Sanatçı adı, şarkı adı ve kapak resmi gömmek için üst veri desteği" #: data/io.github.revisto.drum-machine.metainfo.xml.in:24 msgid "Keyboard shortcuts for quick access to all functions" msgstr "Tüm işlevlere hızlı erişim için klavye kısayolları" #: data/io.github.revisto.drum-machine.metainfo.xml.in:33 msgid "Drum Pattern Loaded in Light Mode" msgstr "Açık Kipte Yüklenen Davul Örüntüsü" #: data/io.github.revisto.drum-machine.metainfo.xml.in:37 msgid "Drum Pattern Loaded in Dark Mode" msgstr "Koyu Kipte Yüklenen Davul Örüntüsü" #: src/application.py:69 msgid "translator-credits" msgstr "" "Sabri Ünal \n" "Emin Tufan Çetin " #: src/config/export_formats.py:43 msgid "MP3 files" msgstr "MP3 dosyaları" #: src/config/export_formats.py:44 msgid "MP3" msgstr "MP3" #: src/config/export_formats.py:50 msgid "FLAC files" msgstr "FLAC dosyaları" #: src/config/export_formats.py:51 msgid "FLAC (Lossless)" msgstr "FLAC (Kayıpsız)" #: src/config/export_formats.py:57 msgid "Ogg files" msgstr "Ogg dosyaları" #: src/config/export_formats.py:58 msgid "Ogg Vorbis" msgstr "Ogg Vorbis" #: src/config/export_formats.py:64 msgid "WAV files" msgstr "WAV dosyaları" #: src/config/export_formats.py:65 msgid "WAV (Uncompressed)" msgstr "WAV (Sıkıştırılmamış)" #: src/dialogs/audio_export_dialog.py:115 msgid "Save Audio File" msgstr "Ses Dosyasını Kaydet" #: src/dialogs/audio_export_dialog.py:139 msgid "Image files" msgstr "Görüntü dosyaları" #: src/dialogs/audio_export_dialog.py:145 msgid "Select Cover Art" msgstr "Kapak Resmi Seç" #: src/dialogs/audio_export_dialog.py:202 msgid "Audio exported to {}" msgstr "Ses {} konumuna dışa aktarıldı" #: src/dialogs/audio_export_dialog.py:207 msgid "Export failed" msgstr "Dışa aktarılamadı" #: src/dialogs/audio_export_dialog.py:214 msgid "Export cancelled successfully" msgstr "Dışa aktarma iptal edildi" #: src/handlers/file_dialog_handler.py:51 msgid "Default Presets" msgstr "Ön Tanımlı Ön Ayarlar" #: src/handlers/file_dialog_handler.py:83 msgid "No Pattern" msgstr "Örüntü Yok" #: src/handlers/file_dialog_handler.py:84 msgid "Please create a drum pattern before exporting audio." msgstr "Sesi dışa aktarmadan önce davul örüntüsü oluşturun." #: src/handlers/file_dialog_handler.py:86 msgid "_OK" msgstr "_Tamam" #: src/handlers/file_dialog_handler.py:109 #: src/handlers/file_dialog_handler.py:177 msgid "MIDI files" msgstr "MIDI dosyaları" #: src/handlers/file_dialog_handler.py:115 msgid "Open MIDI File" msgstr "MIDI Dosyası Aç" #: src/handlers/file_dialog_handler.py:185 msgid "Save Sequence" msgstr "Sırayı Kaydet" #: src/utils/export_progress.py:68 msgid "Preparing..." msgstr "Hazırlanıyor..." #: src/utils/export_progress.py:69 msgid "Initializing..." msgstr "Başlatılıyor..." #: src/utils/export_progress.py:71 msgid "Rendering audio..." msgstr "Ses oluşturuluyor..." #: src/utils/export_progress.py:72 msgid "Processing beats..." msgstr "Ritimler işleniyor..." #: src/utils/export_progress.py:74 msgid "Saving file..." msgstr "Dosya kaydediliyor..." #: src/utils/export_progress.py:75 msgid "Writing to disk..." msgstr "Diske yazılıyor..." #: src/utils/export_progress.py:77 msgid "Exporting..." msgstr "Dışa aktarılıyor..." #: src/utils/export_progress.py:78 msgid "Processing..." msgstr "İşleniyor..." #. Update tooltip and accessibility with current BPM #: src/window.py:198 msgid "{} Beats per Minute (BPM)" msgstr "{} Dakika Başına Vuruş (BPM)" #. Update button tooltip to show current volume level #: src/window.py:207 msgid "{:.0f}% Volume" msgstr "%{:.0f} Ses" #: src/window.py:222 src/window.ui:170 msgid "Play" msgstr "Oynat" #: src/window.py:226 msgid "Pause" msgstr "Duraklat" #: src/window.py:264 src/window.ui:52 msgid "Open" msgstr "Aç" #: src/window.ui:54 msgid "Open Preset" msgstr "Ön Ayar Aç" #: src/window.ui:57 msgctxt "accessibility" msgid "Open Preset" msgstr "Ön Ayar Aç" #: src/window.ui:58 msgid "Open Saved Drum Pattern Preset" msgstr "Kaydedilmiş Davul Örüntüsü Ön Ayarını Aç" #: src/window.ui:76 msgid "Main Menu" msgstr "Ana Menü" #: src/window.ui:78 msgctxt "accessibility" msgid "Main Menu" msgstr "Ana Menü" #: src/window.ui:79 msgid "Access Keyboard Shortcuts and Application Information" msgstr "Klavye Kısayollarına ve Uygulama Bilgilerine Eriş" #: src/window.ui:86 src/gtk/audio-export-dialog.blp:6 #: src/gtk/audio-export-dialog.blp:96 msgid "Export Audio" msgstr "Sesi Dışa Aktar" #: src/window.ui:88 msgctxt "accessibility" msgid "Export Audio" msgstr "Sesi Dışa Aktar" #: src/window.ui:89 msgid "Export Current Drum Pattern as Audio File" msgstr "Geçerli Davul Örüntüsünü Ses Dosyası Olarak Dışa Aktar" #: src/window.ui:134 msgid "BPM" msgstr "BPM" #: src/window.ui:139 src/window.ui:143 msgid "Adjust Tempo In Beats per Minute (BPM)" msgstr "Tempoyu Dakika Başına Vuruş (BPM) Olarak Ayarla" #: src/window.ui:142 msgid "Tempo" msgstr "Tempo" #: src/window.ui:184 msgid "Adjust Volume" msgstr "Sesi Ayarla" #: src/window.ui:207 msgid "Reset" msgstr "Sıfırla" #: src/window.ui:208 msgid "Reset the Drum Sequence" msgstr "Davul Sırasını Sıfırla" #: src/window.ui:223 msgid "_Save Pattern" msgstr "Örüntüsüyü _Kaydet" #: src/window.ui:229 msgid "_Keyboard Shortcuts" msgstr "_Klavye Kısayolları" #: src/window.ui:233 msgid "_About Drum Machine" msgstr "Davul Makinesi _Hakkında" #: src/gtk/help-overlay.blp:11 msgctxt "shortcut window" msgid "General" msgstr "Genel" #: src/gtk/help-overlay.blp:14 msgctxt "shortcut window" msgid "Show Shortcuts" msgstr "Kısayolları Göster" #: src/gtk/help-overlay.blp:19 msgctxt "shortcut window" msgid "Quit" msgstr "Çık" #: src/gtk/help-overlay.blp:26 msgctxt "shortcut window" msgid "Playback Controls" msgstr "Oynatma Denetimleri" #: src/gtk/help-overlay.blp:29 msgctxt "shortcut window" msgid "Play/Pause" msgstr "Oynat/Duraklat" #: src/gtk/help-overlay.blp:35 msgctxt "shortcut window" msgid "Clear All" msgstr "Tümünü Temizle" #: src/gtk/help-overlay.blp:42 msgctxt "shortcut window" msgid "BPM & Volume Controls" msgstr "BPM ve Ses Denetimleri" #: src/gtk/help-overlay.blp:45 msgctxt "shortcut window" msgid "Increase BPM" msgstr "BPM Artır" #: src/gtk/help-overlay.blp:51 msgctxt "shortcut window" msgid "Decrease BPM" msgstr "BPM Azalt" #: src/gtk/help-overlay.blp:57 msgctxt "shortcut window" msgid "Increase Volume" msgstr "Sesi Artır" #: src/gtk/help-overlay.blp:63 msgctxt "shortcut window" msgid "Decrease Volume" msgstr "Sesi Azalt" #: src/gtk/help-overlay.blp:69 msgctxt "shortcut window" msgid "Mute" msgstr "Sesi Kapat" #: src/gtk/help-overlay.blp:76 msgctxt "shortcut window" msgid "Preset Management" msgstr "Ön Ayar Yönetimi" #: src/gtk/help-overlay.blp:79 msgctxt "shortcut window" msgid "Load Preset" msgstr "Ön Ayarı Yükle" #: src/gtk/help-overlay.blp:85 msgctxt "shortcut window" msgid "Save Preset" msgstr "Ön Ayarı Kaydet" #: src/gtk/help-overlay.blp:91 msgctxt "shortcut window" msgid "Export Audio" msgstr "Sesi Dışa Aktar" #: src/gtk/help-overlay.blp:98 msgctxt "shortcut window" msgid "Navigation" msgstr "Gezinti" #: src/gtk/help-overlay.blp:101 msgctxt "shortcut window" msgid "Go to Instrument" msgstr "Enstrümana Git" #: src/gtk/help-overlay.blp:107 msgctxt "shortcut window" msgid "Previous Page" msgstr "Önceki Sayfa" #: src/gtk/help-overlay.blp:113 msgctxt "shortcut window" msgid "Next Page" msgstr "Sonraki Sayfa" #: src/gtk/save-changes-dialog.blp:5 msgid "Save Changes?" msgstr "Değişiklikler Kaydedilsin Mi?" #: src/gtk/save-changes-dialog.blp:6 msgid "" "Current preset contains unsaved changes. Changes which are not saved will be " "permanently lost." msgstr "" "Şimdiki ön ayar kaydedilmemiş değişiklikler içeriyor. Kaydedilmemiş " "değişiklikler kalıcı olarak yitecek." #. Translators: Cancel the operation #: src/gtk/save-changes-dialog.blp:14 msgid "_Cancel" msgstr "İ_ptal" #. Translators: Discard all changes #: src/gtk/save-changes-dialog.blp:15 msgid "_Discard" msgstr "_Gözden Çıkar" #. Translators: Save current changes #: src/gtk/save-changes-dialog.blp:16 msgid "_Save" msgstr "_Kaydet" #: src/gtk/audio-export-dialog.blp:39 msgid "Audio Format" msgstr "Ses Biçimi" #: src/gtk/audio-export-dialog.blp:45 msgid "Repeat Count" msgstr "Yineleme Sayısı" #: src/gtk/audio-export-dialog.blp:46 msgid "How many times to repeat the pattern" msgstr "Örüntünün yinelenme sayısı" #: src/gtk/audio-export-dialog.blp:59 msgid "Metadata" msgstr "Üst Veri" #: src/gtk/audio-export-dialog.blp:62 msgid "Artist Name" msgstr "Sanatçı Adı" #: src/gtk/audio-export-dialog.blp:67 msgid "Song Name" msgstr "Şarkı Adı" #: src/gtk/audio-export-dialog.blp:72 msgid "Cover Art" msgstr "Kapak Resmi" #: src/gtk/audio-export-dialog.blp:76 msgid "Choose File" msgstr "Dosya Seç" #: src/gtk/audio-export-dialog.blp:105 msgid "Cancel Export" msgstr "Dışa Aktarmayı İptal Et" drum-machine-2.2.0/po/uk.po000066400000000000000000000666661514070543000155040ustar00rootroot00000000000000# Ukrainian translation for drum-machine. # Copyright (C) 2025 drum-machine's COPYRIGHT HOLDER # This file is distributed under the same license as the drum-machine package. # # Yuri Chornoivan , 2025. msgid "" msgstr "" "Project-Id-Version: drum-machine master\n" "Report-Msgid-Bugs-To: https://github.com/revisto/drum-machine/issues\n" "POT-Creation-Date: 2025-12-13 15:25+0000\n" "PO-Revision-Date: 2025-12-13 20:29+0200\n" "Last-Translator: Yuri Chornoivan \n" "Language-Team: Ukrainian \n" "Language: uk\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n" "%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" "X-Generator: Lokalize 23.04.3\n" #: data/io.github.revisto.drum-machine.desktop.in:2 #: data/io.github.revisto.drum-machine.metainfo.xml.in:6 src/application.py:67 #: src/window.ui:69 msgid "Drum Machine" msgstr "Драм-машина" #. Translators: Search terms to find this application. Do NOT translate or localise the semicolons! The list MUST also end with a semicolon! #: data/io.github.revisto.drum-machine.desktop.in:9 msgid "drum;drums;sequencer;rhythm;music;pattern;beats;percussion;loop;groove;" msgstr "" "drum;drums;sequencer;rhythm;music;pattern;beats;percussion;loop;groove;ударні;" "барабани;секвенсер;ритм;музика;партитура;такти;перкусія;цикл;грув;" #: data/io.github.revisto.drum-machine.metainfo.xml.in:7 msgid "Create and play drum beats" msgstr "Створення та виконання партій ударних" #: data/io.github.revisto.drum-machine.metainfo.xml.in:9 msgid "" "Drum Machine is a modern and intuitive application for creating, playing, " "and managing drum patterns. Perfect for musicians, producers, and anyone " "interested in rhythm creation, this application provides a simple interface " "for drum pattern programming. Have fun!" msgstr "" "«Драм-машина» — це сучасна та інтуїтивно зрозуміла програма для створення, " "відтворення та керування барабанними партитурами. Ідеально підходить для " "музикантів, продюсерів і всіх, хто цікавиться створенням ритму, ця програма " "має простий інтерфейс для програмування барабанних партитур. Приємного " "користування!" #: data/io.github.revisto.drum-machine.metainfo.xml.in:15 msgid "Features:" msgstr "Можливості:" #: data/io.github.revisto.drum-machine.metainfo.xml.in:17 #| msgid "Intuitive grid-based pattern editor" msgid "Intuitive grid-based pattern editor with infinite pages" msgstr "" "Зручний редактор партитур на основі сітки із нескінченною кількістю сторінок" #: data/io.github.revisto.drum-machine.metainfo.xml.in:18 msgid "Custom samples: Add your own drum sounds with MIDI note mapping" msgstr "" "Нетипові семпли: додайте ваші власні перкусійні звуки з прив'язкою до нот MIDI" #: data/io.github.revisto.drum-machine.metainfo.xml.in:19 msgid "Adjustable BPM control" msgstr "Гнучке керування частотою ударів" #: data/io.github.revisto.drum-machine.metainfo.xml.in:20 msgid "Volume control for overall mix" msgstr "Керування гучністю для загального мікшування" #: data/io.github.revisto.drum-machine.metainfo.xml.in:21 msgid "Save and load patterns" msgstr "Зберігання та завантаження партитур" #: data/io.github.revisto.drum-machine.metainfo.xml.in:22 msgid "Multiple drum sounds including kick, snare, hi-hat, and more" msgstr "Кілька звуків барабанів, зокрема удар, малий барабан, хай-хет тощо" #: data/io.github.revisto.drum-machine.metainfo.xml.in:23 #| msgid "" #| "Audio export feature with support for WAV, FLAC, Ogg, and MP3 formats" msgid "" "Audio and MIDI export with support for WAV, FLAC, Ogg, MP3, and MIDI formats" msgstr "" "Експортування звукових даних та MIDI з підтримкою форматів WAV, FLAC, Ogg," " MP3 і MIDI" #: data/io.github.revisto.drum-machine.metainfo.xml.in:24 msgid "Metadata support for embedding artist name, song title, and cover art" msgstr "" "Підтримка метаданих для вбудовування імені виконавця, назви композиції та " "зображення обкладинки" #: data/io.github.revisto.drum-machine.metainfo.xml.in:25 msgid "Keyboard shortcuts for quick access to all functions" msgstr "Клавіатурні скорочення для доступу до усіх можливостей" #: data/io.github.revisto.drum-machine.metainfo.xml.in:34 msgid "Drum Pattern Loaded in Light Mode" msgstr "Партитуру ударних завантажено у світлому режимі" #: data/io.github.revisto.drum-machine.metainfo.xml.in:38 msgid "Drum Pattern Loaded in Dark Mode" msgstr "Партитуру ударних завантажено у темному режимі" #: src/application.py:74 msgid "" "Drum Machine is a modern and intuitive application for creating, playing, " "and managing drum patterns." msgstr "" "«Драм-машина» — це сучасна та інтуїтивно зрозуміла програма для створення, " "відтворення та керування барабанними партитурами." #: src/application.py:79 msgid "translator-credits" msgstr "Юрій Чорноіван , 2025" #: src/application.py:84 msgid "Special thanks" msgstr "Особливі подяки" #: src/application.py:87 msgid "Sounds" msgstr "Звуки" #: src/application.py:88 #, python-brace-format msgid "The drum samples used in this application are from {link}." msgstr "" "Перкусійні семпли, які використано у цій програмі, запозичено з {link}." #: src/config/export_formats.py:44 msgid "MP3 files" msgstr "файли MP3" #: src/config/export_formats.py:45 msgid "MP3" msgstr "MP3" #: src/config/export_formats.py:51 msgid "FLAC files" msgstr "файли FLAC" #: src/config/export_formats.py:52 msgid "FLAC (Lossless)" msgstr "FLAC (без втрат)" #: src/config/export_formats.py:58 msgid "Ogg files" msgstr "файли Ogg" #: src/config/export_formats.py:59 msgid "Ogg Vorbis" msgstr "Ogg Vorbis" #: src/config/export_formats.py:65 msgid "WAV files" msgstr "файли WAV" #: src/config/export_formats.py:66 msgid "WAV (Uncompressed)" msgstr "WAV (без стискання)" #: src/dialogs/audio_export_dialog.py:119 msgid "Save Audio File" msgstr "Зберегти звуковий файл" #: src/dialogs/audio_export_dialog.py:148 msgid "Part “{}” is Silent" msgstr "На партії «{}» вимкнено звук" #: src/dialogs/audio_export_dialog.py:150 msgid "Parts “{}” and “{}” are Silent" msgstr "На партіях «{}» і «{}» вимкнено звук" #: src/dialogs/audio_export_dialog.py:154 msgid "{} Parts are Silent" msgstr "На партіях {} вимкнено звук" #: src/dialogs/audio_export_dialog.py:179 msgid "Image files" msgstr "файли зображень" #: src/dialogs/audio_export_dialog.py:185 msgid "Select Cover Art" msgstr "Виберіть обкладинку" #: src/dialogs/audio_export_dialog.py:245 msgid "Audio exported to {}" msgstr "Звукові дані експортовано до {}" #: src/dialogs/audio_export_dialog.py:251 msgid "Export failed" msgstr "Не вдалося експортувати" #: src/dialogs/audio_export_dialog.py:258 msgid "Export cancelled successfully" msgstr "Експортування успішно скасовано" #: src/dialogs/midi_mapping_dialog.py:22 msgid "Acoustic Bass Drum" msgstr "Акустичний великий барабан" #: src/dialogs/midi_mapping_dialog.py:23 msgid "Bass Drum 1" msgstr "Великий барабан 1" #: src/dialogs/midi_mapping_dialog.py:24 msgid "Side Stick" msgstr "удар по ободу" #: src/dialogs/midi_mapping_dialog.py:25 msgid "Acoustic Snare" msgstr "Акустичний малий барабан" #: src/dialogs/midi_mapping_dialog.py:26 msgid "Hand Clap" msgstr "Плескіт долонь" #: src/dialogs/midi_mapping_dialog.py:27 msgid "Electric Snare" msgstr "Малий електробарабан" #: src/dialogs/midi_mapping_dialog.py:28 msgid "Low Floor Tom" msgstr "Низький підлоговий томтом" #: src/dialogs/midi_mapping_dialog.py:29 msgid "Closed Hi Hat" msgstr "Закритий хет" #: src/dialogs/midi_mapping_dialog.py:30 msgid "High Floor Tom" msgstr "Високий напольний томтом" #: src/dialogs/midi_mapping_dialog.py:31 msgid "Pedal Hi Hat" msgstr "Хет (педаллю)" #: src/dialogs/midi_mapping_dialog.py:32 msgid "Low Tom" msgstr "Низький томтом" #: src/dialogs/midi_mapping_dialog.py:33 msgid "Open Hi Hat" msgstr "Відкритий високий хет" #: src/dialogs/midi_mapping_dialog.py:34 msgid "Low-Mid Tom" msgstr "Низький середній томтом" #: src/dialogs/midi_mapping_dialog.py:35 msgid "Hi-Mid Tom" msgstr "Високий середній томтом" #: src/dialogs/midi_mapping_dialog.py:36 msgid "Crash Cymbal 1" msgstr "Креш-тарілка 1" #: src/dialogs/midi_mapping_dialog.py:37 msgid "High Tom" msgstr "Високий томтом" #: src/dialogs/midi_mapping_dialog.py:38 msgid "Ride Cymbal 1" msgstr "Райд-тарілка 1" #: src/dialogs/midi_mapping_dialog.py:39 msgid "Chinese Cymbal" msgstr "Китайська тарілка" #: src/dialogs/midi_mapping_dialog.py:40 msgid "Ride Bell" msgstr "Райд-тарілка" #: src/dialogs/midi_mapping_dialog.py:41 msgid "Tambourine" msgstr "Тамбурин" #: src/dialogs/midi_mapping_dialog.py:42 msgid "Splash Cymbal" msgstr "Сплеш-тарілка" #: src/dialogs/midi_mapping_dialog.py:43 msgid "Cowbell" msgstr "Дзвіночок" #: src/dialogs/midi_mapping_dialog.py:44 msgid "Crash Cymbal 2" msgstr "Креш-тарілка 2" #: src/dialogs/midi_mapping_dialog.py:45 msgid "Vibraslap" msgstr "Вібруючий слеп" #: src/dialogs/midi_mapping_dialog.py:46 msgid "Ride Cymbal 2" msgstr "Райд-тарілка 2" #: src/dialogs/midi_mapping_dialog.py:47 msgid "Hi Bongo" msgstr "Високий Бонґо" #: src/dialogs/midi_mapping_dialog.py:48 msgid "Low Bongo" msgstr "Низьке Бонґо" #: src/dialogs/midi_mapping_dialog.py:49 msgid "Mute Hi Conga" msgstr "Закрита висока конга" #: src/dialogs/midi_mapping_dialog.py:50 msgid "Open Hi Conga" msgstr "Відкрита висока Конґа" #: src/dialogs/midi_mapping_dialog.py:51 msgid "Low Conga" msgstr "Низька Конґа" #: src/dialogs/midi_mapping_dialog.py:52 msgid "High Timbale" msgstr "Високі литаври" #: src/dialogs/midi_mapping_dialog.py:53 msgid "Low Timbale" msgstr "Низькі литаври" #: src/dialogs/midi_mapping_dialog.py:54 msgid "High Agogo" msgstr "Високий Аґоґо" #: src/dialogs/midi_mapping_dialog.py:55 msgid "Low Agogo" msgstr "Низький Аґоґо" #: src/dialogs/midi_mapping_dialog.py:56 msgid "Cabasa" msgstr "Кабаса" #: src/dialogs/midi_mapping_dialog.py:57 msgid "Maracas" msgstr "Маракаси" #: src/dialogs/midi_mapping_dialog.py:58 msgid "Short Whistle" msgstr "Короткий свист" #: src/dialogs/midi_mapping_dialog.py:59 msgid "Long Whistle" msgstr "Довгий свист" #: src/dialogs/midi_mapping_dialog.py:60 msgid "Short Guiro" msgstr "Коротке ґуїро" #: src/dialogs/midi_mapping_dialog.py:61 msgid "Long Guiro" msgstr "Довге ґуїро" #: src/dialogs/midi_mapping_dialog.py:62 msgid "Claves" msgstr "Клавес" #: src/dialogs/midi_mapping_dialog.py:63 msgid "Hi Wood Block" msgstr "Висока коробочка" #: src/dialogs/midi_mapping_dialog.py:64 msgid "Low Wood Block" msgstr "Низький дерев'яний блок" #: src/dialogs/midi_mapping_dialog.py:65 msgid "Mute Cuica" msgstr "Закрита куїка" #: src/dialogs/midi_mapping_dialog.py:66 msgid "Open Cuica" msgstr "Відкрита куїка" #: src/dialogs/midi_mapping_dialog.py:67 msgid "Mute Triangle" msgstr "Закритий трикутник" #: src/dialogs/midi_mapping_dialog.py:68 msgid "Open Triangle" msgstr "Відкритий трикутник" #: src/dialogs/midi_mapping_dialog.py:78 src/ui/drum_grid_builder.py:338 msgid "MIDI Mapping" msgstr "Прив'язка MIDI" #. Group 1: Note Assignment #: src/dialogs/midi_mapping_dialog.py:108 msgid "Note Assignment" msgstr "Прив'язка нот" #: src/dialogs/midi_mapping_dialog.py:111 msgid "" "Assign a MIDI note for '{}'. This ensures correct playback when exporting." msgstr "" "Призначити ноту MIDI для «{}». Це забезпечує належне відтворення при " "експортуванні." #. Action Row for Note #: src/dialogs/midi_mapping_dialog.py:118 msgid "MIDI Note" msgstr "Нота MIDI" #: src/dialogs/midi_mapping_dialog.py:119 msgid "The note number to trigger" msgstr "Номер ноти для відтворення" #. Group 2: Standard Instruments #: src/dialogs/midi_mapping_dialog.py:137 msgid "Standard Instruments" msgstr "Стандартні інструменти" #: src/dialogs/midi_mapping_dialog.py:139 msgid "Select a General MIDI instrument to automatically set the note." msgstr "" "Виберіть загальний інструмент MIDI для автоматичного встановлення ноти." #: src/dialogs/midi_mapping_dialog.py:143 msgid "Instrument Preset" msgstr "Шаблон інструментів" #: src/dialogs/midi_mapping_dialog.py:186 msgid "Save" msgstr "Зберегти" #: src/dialogs/midi_mapping_dialog.py:229 msgid "Custom Note" msgstr "Нетипова нота" #: src/handlers/drag_drop_handler.py:113 msgid "Sound replaced" msgstr "Звук замінено" #: src/handlers/drag_drop_handler.py:116 msgid "Failed to replace sound" msgstr "Не вдалося замінити звук" #: src/handlers/drag_drop_handler.py:126 msgid "Not a supported audio file" msgstr "Не є підтримуваним звуковим файлом" #: src/handlers/drag_drop_handler.py:134 msgid "File not found" msgstr "Файл не знайдено" #: src/handlers/drag_drop_handler.py:139 msgid "Selected item is not a file" msgstr "Вибраний запис не є файлом" #: src/handlers/drag_drop_handler.py:146 msgid "File too large: {:.1f}MB (max 50MB)" msgstr "Файл є надто великим: {:.1f}МБ (макс. 50МБ)" #: src/handlers/drag_drop_handler.py:174 msgid "No valid audio files found" msgstr "Не знайдено коректних файлів звукових даних" #: src/handlers/drag_drop_handler.py:209 msgid "Error processing file: {}" msgstr "Помилка при обробці файла: {}" #: src/handlers/drag_drop_handler.py:237 msgid "Added {} drum part, {} files skipped" msgstr "Додано партитуру ударних {}, {} файлів пропущено" #: src/handlers/drag_drop_handler.py:243 msgid "Added {} drum parts, {} files skipped" msgstr "Додано партитури ударних {}, {} файлів пропущено" #: src/handlers/drag_drop_handler.py:248 msgid "Added {} drum parts" msgstr "Додано партитури ударних {}" #. Only show skipped message if no replacement happened #: src/handlers/drag_drop_handler.py:251 msgid "{} files skipped" msgstr "{} файлів пропущено" #: src/handlers/file_dialog_handler.py:52 msgid "Default Patterns" msgstr "Типові партитури" #: src/handlers/file_dialog_handler.py:92 #: src/handlers/file_dialog_handler.py:171 msgid "MIDI files" msgstr "файли MIDI" #: src/handlers/file_dialog_handler.py:98 msgid "Open MIDI File" msgstr "Відкрити файл MIDI" #: src/handlers/file_dialog_handler.py:127 msgid "Failed to open file" msgstr "Не вдалося відкрити файл" #: src/handlers/file_dialog_handler.py:165 msgid "Failed to load pattern" msgstr "Не вдалося завантажити партитуру" #: src/handlers/file_dialog_handler.py:179 msgid "Save Sequence" msgstr "Зберегти послідовність" #: src/handlers/file_dialog_handler.py:205 msgid "Add Audio Samples" msgstr "Додати звукові семпли" #: src/handlers/file_dialog_handler.py:227 msgid "Audio files" msgstr "файли звукових даних" #: src/utils/export_progress.py:76 msgid "Preparing…" msgstr "Приготування…" #: src/utils/export_progress.py:77 msgid "Initializing…" msgstr "Ініціалізація…" #: src/utils/export_progress.py:79 msgid "Rendering audio…" msgstr "Обробка звукових даних…" #: src/utils/export_progress.py:80 msgid "Processing beats…" msgstr "Обробка тактів…" #: src/utils/export_progress.py:82 msgid "Saving file…" msgstr "Збереження файла…" #: src/utils/export_progress.py:83 msgid "Writing to disk…" msgstr "Запис на диск…" #: src/utils/export_progress.py:85 msgid "Exporting…" msgstr "Експортування…" #: src/utils/export_progress.py:86 msgid "Processing…" msgstr "Обробка…" #: src/utils/name_utils.py:36 msgid "Custom Sound" msgstr "Нетиповий звук" #: src/ui/drum_grid_builder.py:323 msgid "Preview" msgstr "Перегляд" #: src/ui/drum_grid_builder.py:325 msgid "Replace…" msgstr "Замінити…" #: src/ui/drum_grid_builder.py:328 msgid "Replace with new sound" msgstr "Замінити новим звуком" #: src/ui/drum_grid_builder.py:331 msgid "Remove" msgstr "Вилучити" #: src/ui/drum_grid_builder.py:334 msgid "At least one drum part must remain" msgstr "Має лишитися хоча б одна партитура ударних" #: src/ui/drum_grid_builder.py:341 msgid "Configure MIDI note for export" msgstr "Налаштувати ноту MIDI для експортування" #: src/ui/drum_grid_builder.py:398 msgid "MIDI note updated" msgstr "Оновлено ноту MIDI" #: src/ui/drum_grid_builder.py:406 msgid "Select New Sound" msgstr "Вибрати новий звук" #: src/ui/drum_grid_builder.py:420 msgid "Removed drum part: {}" msgstr "Вилучено партитуру ударних: {}" #: src/ui/drum_grid_builder.py:425 msgid "Failed to remove drum part" msgstr "Не вдалося вилучити партитуру ударних" #. Update tooltip and accessibility with current BPM #: src/window.py:225 msgid "{} Beats per Minute (BPM)" msgstr "{} тактів на хвилину (BPM)" #. Update button tooltip to show current volume level #: src/window.py:234 msgid "{:.0f}% Volume" msgstr "{:.0f}% гучності" #: src/window.py:251 src/window.ui:173 msgid "Play" msgstr "Пуск" #: src/window.py:255 msgid "Pause" msgstr "Пауза" #: src/window.py:302 msgid "Open" msgstr "Відкрити" #: src/window.py:320 msgid "Added: {}" msgstr "Додано: {}" #: src/window.py:335 msgid "Failed to add custom sound" msgstr "Не вдалося додати нетиповий звук" #: src/window.py:342 msgid "Replaced drum with: {}" msgstr "Замінено ударні на: {}" #: src/window.py:350 msgid "Failed to replace drum sound" msgstr "Не вдалося замінити звук ударних" #: src/window.ui:52 msgid "Open…" msgstr "Відкрити…" #: src/window.ui:54 msgid "Open Pattern" msgstr "Відкрити партитуру" #: src/window.ui:57 msgctxt "accessibility" msgid "Open Pattern" msgstr "Відкрити партитуру" #: src/window.ui:58 msgid "Open Saved Drum Pattern" msgstr "Відкрити збережену партитуру ударних" #: src/window.ui:76 msgid "Main Menu" msgstr "Головне меню" #: src/window.ui:78 msgctxt "accessibility" msgid "Main Menu" msgstr "Головне меню" #: src/window.ui:79 msgid "Access Keyboard Shortcuts and Application Information" msgstr "Доступ до клавіатурних скорочень та відомостей про програму" #: src/window.ui:86 msgid "Export Audio…" msgstr "Експортувати звукові дані…" #: src/window.ui:91 msgctxt "accessibility" msgid "Export Audio…" msgstr "Експортувати звукові дані…" #: src/window.ui:92 msgid "Export Current Drum Pattern as Audio File" msgstr "Експортувати поточну партитуру ударних як файл звукових даних" #: src/window.ui:137 msgid "BPM" msgstr "Музичний розмір" #: src/window.ui:142 src/window.ui:146 msgid "Adjust Tempo In Beats per Minute (BPM)" msgstr "Скоригувати темп у тактах на хвилину (BPM)" #: src/window.ui:145 msgid "Tempo" msgstr "Темп" #: src/window.ui:187 msgid "Adjust Volume" msgstr "Регулювання гучності" #: src/window.ui:210 msgid "Reset" msgstr "Скинути" #: src/window.ui:211 msgid "Reset the Drum Sequence" msgstr "Скинути послідовністю ударних" #: src/window.ui:226 msgid "_Add Samples…" msgstr "_Додати семпли…" #: src/window.ui:230 msgid "_Save Pattern…" msgstr "_Зберегти партитуру…" #: src/window.ui:236 msgid "_Keyboard Shortcuts" msgstr "_Клавіатурні скорочення" #: src/window.ui:240 msgid "_About Drum Machine" msgstr "_Про «Драм-машину»" #: src/gtk/help-overlay.blp:11 msgctxt "shortcut window" msgid "General" msgstr "Загальне" #: src/gtk/help-overlay.blp:14 msgctxt "shortcut window" msgid "Show Shortcuts" msgstr "Показати клавіатурні скорочення" #: src/gtk/help-overlay.blp:19 msgctxt "shortcut window" msgid "Quit" msgstr "Вийти" #: src/gtk/help-overlay.blp:26 msgctxt "shortcut window" msgid "Playback Controls" msgstr "Керування відтворенням" #: src/gtk/help-overlay.blp:29 msgctxt "shortcut window" msgid "Play/Pause" msgstr "Пуск/Пауза" #: src/gtk/help-overlay.blp:35 msgctxt "shortcut window" msgid "Clear All" msgstr "Очистити все" #: src/gtk/help-overlay.blp:42 msgctxt "shortcut window" msgid "BPM & Volume Controls" msgstr "Керування темпом і гучністю" #: src/gtk/help-overlay.blp:45 msgctxt "shortcut window" msgid "Increase BPM" msgstr "Зменшити темп" #: src/gtk/help-overlay.blp:51 msgctxt "shortcut window" msgid "Decrease BPM" msgstr "Збільшити темп" #: src/gtk/help-overlay.blp:57 msgctxt "shortcut window" msgid "Increase Volume" msgstr "Збільшити гучність" #: src/gtk/help-overlay.blp:63 msgctxt "shortcut window" msgid "Decrease Volume" msgstr "Зменшити гучність" #: src/gtk/help-overlay.blp:69 msgctxt "shortcut window" msgid "Mute" msgstr "Вимкнути звук" #: src/gtk/help-overlay.blp:76 msgctxt "shortcut window" msgid "Pattern Management" msgstr "Керування партитурами" #: src/gtk/help-overlay.blp:79 msgctxt "shortcut window" msgid "Load Pattern" msgstr "Завантажити партитуру" #: src/gtk/help-overlay.blp:85 msgctxt "shortcut window" msgid "Save Pattern" msgstr "Зберегти партитуру" #: src/gtk/help-overlay.blp:91 msgctxt "shortcut window" msgid "Export Audio" msgstr "Експорт звукових даних" #: src/gtk/help-overlay.blp:98 msgctxt "shortcut window" msgid "Navigation" msgstr "Навігація" #: src/gtk/help-overlay.blp:101 msgctxt "shortcut window" msgid "Go to Instrument" msgstr "Перейти до інструмента" #: src/gtk/help-overlay.blp:107 msgctxt "shortcut window" msgid "Previous Page" msgstr "Попередня сторінка" #: src/gtk/help-overlay.blp:113 msgctxt "shortcut window" msgid "Next Page" msgstr "Наступна сторінка" #: src/gtk/save-changes-dialog.blp:5 msgid "Save Changes?" msgstr "Зберегти зміни?" #: src/gtk/save-changes-dialog.blp:6 msgid "" "Current pattern contains unsaved changes. Changes which are not saved will " "be permanently lost." msgstr "" "До поточної партитури внесено незбережені зміни. Зміни, які не було " "збережено, буде назавжди втрачено." #. Translators: Cancel the operation #: src/gtk/save-changes-dialog.blp:14 msgid "_Cancel" msgstr "_Скасувати" #. Translators: Discard all changes #: src/gtk/save-changes-dialog.blp:15 msgid "_Discard" msgstr "_Відкинути" #. Translators: Save current changes #: src/gtk/save-changes-dialog.blp:16 msgid "_Save" msgstr "З_берегти" #: src/gtk/audio-export-dialog.blp:6 src/gtk/audio-export-dialog.blp:101 msgid "Export Audio" msgstr "Експорт звукових даних" #: src/gtk/audio-export-dialog.blp:44 msgid "Audio Format" msgstr "Формат звукових даних" #: src/gtk/audio-export-dialog.blp:50 msgid "Repeat Count" msgstr "Кількість повторів" #: src/gtk/audio-export-dialog.blp:51 msgid "How many times to repeat the pattern" msgstr "Кількість разів повторення партитури" #: src/gtk/audio-export-dialog.blp:64 msgid "Metadata" msgstr "Метадані" #: src/gtk/audio-export-dialog.blp:67 msgid "Artist Name" msgstr "Ім'я виконавця" #: src/gtk/audio-export-dialog.blp:72 msgid "Song Name" msgstr "Назва композиції" #: src/gtk/audio-export-dialog.blp:77 msgid "Cover Art" msgstr "Обкладинка" #: src/gtk/audio-export-dialog.blp:81 msgid "Choose File…" msgstr "Вибрати файл…" #: src/gtk/audio-export-dialog.blp:110 msgid "Cancel Export" msgstr "Скасувати експортування" #~ msgid "No Pattern" #~ msgstr "Без партитури" #~ msgid "Please create a drum pattern before exporting audio." #~ msgstr "" #~ "Будь ласка, створіть партитуру уданих, перш ніж експортувати звукові дані." #~ msgid "_OK" #~ msgstr "_Гаразд" #~ msgid "Open Preset" #~ msgstr "Відкрити шаблон" #~ msgctxt "accessibility" #~ msgid "Open Preset" #~ msgstr "Відкрити шаблон" #~ msgctxt "shortcut window" #~ msgid "Load Preset" #~ msgstr "Завантажити шаблон" #~ msgctxt "shortcut window" #~ msgid "Save Preset" #~ msgstr "Зберегти шаблон" #~ msgctxt "accessibility" #~ msgid "Export Audio" #~ msgstr "Експорт звукових даних" #~ msgid "Export Settings" #~ msgstr "Параметри експортування" #~ msgid "Select the output audio format" #~ msgstr "Виберіть формат виведення звукових даних" #~ msgid "Add metadata to your exported audio" #~ msgstr "Додайте метадані до експортованих вами звукових даних" #~ msgid "Select an image file for the cover art" #~ msgstr "Виберіть файл зображення для обкладинки" #~ msgctxt "accessibility" #~ msgid "Save Drum Pattern" #~ msgstr "Зберегти партитуру ударних" drum-machine-2.2.0/po/uz.po000066400000000000000000000306521514070543000155050ustar00rootroot00000000000000# Uzbek (Latin) translation for drum-machine. # Copyright (C) 2025 drum-machine's COPYRIGHT HOLDER # This file is distributed under the same license as the drum-machine package. # let rec , 2025. # msgid "" msgstr "" "Project-Id-Version: drum-machine master\n" "Report-Msgid-Bugs-To: https://github.com/revisto/drum-machine/issues\n" "POT-Creation-Date: 2025-10-11 15:26+0000\n" "PO-Revision-Date: 2025-10-13 12:05+0500\n" "Last-Translator: Baxrom Raxmatov \n" "Language-Team: Uzbek (Latin) \n" "Language: uz\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 3.5\n" #: data/io.github.revisto.drum-machine.desktop.in:2 #: data/io.github.revisto.drum-machine.metainfo.xml.in:6 src/window.ui:69 msgid "Drum Machine" msgstr "Baraban mashinasi" # sekvenator rostan ham sequenser ekanmi? #. Translators: Search terms to find this application. Do NOT translate or localise the semicolons! The list MUST also end with a semicolon! #: data/io.github.revisto.drum-machine.desktop.in:9 msgid "drum;drums;sequencer;rhythm;music;pattern;beats;percussion;loop;groove;" msgstr "baraban;barabanlar;sequencer;ritm;musiqa;naqsh;zarblar;zarb;halqa;o‘yiq;" #: data/io.github.revisto.drum-machine.metainfo.xml.in:7 msgid "Create and play drum beats" msgstr "Baraban zarblarini yaratish va ijro etish" #: data/io.github.revisto.drum-machine.metainfo.xml.in:9 msgid "" "Drum Machine is a modern and intuitive application for creating, playing, and " "managing drum patterns. Perfect for musicians, producers, and anyone interested " "in rhythm creation, this application provides a simple interface for drum " "pattern programming. Have fun!" msgstr "" "Baraban mashinasi - ritm naqshlarini yaratish, chalish va boshqarish uchun " "mo‘ljallangan zamonaviy va qulay dastur. Musiqachilar, prodyuserlar va ritm " "yaratishga qiziquvchilar uchun aynan moslashtirilgan bu dastur baraban " "naqshlarini dasturlash uchun sodda interfeysni taqdim etadi. Maroqli vaqt " "o‘tkazing!" #: data/io.github.revisto.drum-machine.metainfo.xml.in:15 msgid "Features:" msgstr "Xususiyatlar:" #: data/io.github.revisto.drum-machine.metainfo.xml.in:17 msgid "Intuitive grid-based pattern editor" msgstr "Gridga asoslangan intuitiv naqsh muharriri" #: data/io.github.revisto.drum-machine.metainfo.xml.in:18 msgid "Adjustable BPM control" msgstr "Sozlanadigan DZ boshqaruvi" #: data/io.github.revisto.drum-machine.metainfo.xml.in:19 msgid "Volume control for overall mix" msgstr "Umumiy miks uchun tovush balandligini boshqarish" #: data/io.github.revisto.drum-machine.metainfo.xml.in:20 msgid "Save and load preset patterns" msgstr "Oldindan sozlangan andozalarni saqlash va yuklash" #: data/io.github.revisto.drum-machine.metainfo.xml.in:21 msgid "Multiple drum sounds including kick, snare, hi-hat, and more" msgstr "Bir nechta baraban tovushlari, jumladan, kik, snare, hi-hat va boshqalar" #: data/io.github.revisto.drum-machine.metainfo.xml.in:22 msgid "Audio export feature with support for WAV, FLAC, Ogg, and MP3 formats" msgstr "" "WAV, FLAC, Ogg va MP3 formatlarini qo‘llab-quvvatlaydigan audio eksporti " "funksiyasi" #: data/io.github.revisto.drum-machine.metainfo.xml.in:23 msgid "Metadata support for embedding artist name, song title, and cover art" msgstr "" "Ijrochi nomi, qo‘shiq sarlavhasi va muqova rasmini joylashtirish uchun meta-" "ma’lumotlarni qo‘llab-quvvatlash" #: data/io.github.revisto.drum-machine.metainfo.xml.in:24 msgid "Keyboard shortcuts for quick access to all functions" msgstr "Barcha funksiyalarga tezkor kirish uchun klaviatura yorliqlari" #: data/io.github.revisto.drum-machine.metainfo.xml.in:33 msgid "Drum Pattern Loaded in Light Mode" msgstr "Yorug‘lik rejimida baraban naqshi yuklandi" #: data/io.github.revisto.drum-machine.metainfo.xml.in:37 msgid "Drum Pattern Loaded in Dark Mode" msgstr "Qorong‘i rejimda baraban naqshi yuklandi" #: src/application.py:69 msgid "translator-credits" msgstr "Hamidulloh To'xtayev " #: src/config/export_formats.py:43 msgid "MP3 files" msgstr "MP3 fayllar" #: src/config/export_formats.py:44 msgid "MP3" msgstr "MP3" #: src/config/export_formats.py:50 msgid "FLAC files" msgstr "FLAC fayllar" #: src/config/export_formats.py:51 msgid "FLAC (Lossless)" msgstr "FLAC (Yo‘qotishsiz)" #: src/config/export_formats.py:57 msgid "Ogg files" msgstr "Ogg fayllar" #: src/config/export_formats.py:58 msgid "Ogg Vorbis" msgstr "Ogg Vorbis" #: src/config/export_formats.py:64 msgid "WAV files" msgstr "WAV fayllar" #: src/config/export_formats.py:65 msgid "WAV (Uncompressed)" msgstr "WAV (zichlanmagan audio fayl formati)" #: src/dialogs/audio_export_dialog.py:115 msgid "Save Audio File" msgstr "Audio faylni saqlash" #: src/dialogs/audio_export_dialog.py:139 msgid "Image files" msgstr "Rasm fayllar" #: src/dialogs/audio_export_dialog.py:145 msgid "Select Cover Art" msgstr "Muqova san’atini tanlang" #: src/dialogs/audio_export_dialog.py:202 msgid "Audio exported to {}" msgstr "Audio {} jildiga eksport qilindi" #: src/dialogs/audio_export_dialog.py:207 msgid "Export failed" msgstr "Eksport amalga oshmadi" #: src/dialogs/audio_export_dialog.py:214 msgid "Export cancelled successfully" msgstr "Eksport muvaffaqiyatli bekor qilindi" #: src/handlers/file_dialog_handler.py:51 msgid "Default Presets" msgstr "Birlamchi sozlamalar" #: src/handlers/file_dialog_handler.py:83 msgid "No Pattern" msgstr "Naqshsiz" #: src/handlers/file_dialog_handler.py:84 msgid "Please create a drum pattern before exporting audio." msgstr "Audioni eksport qilishdan oldin baraban naqshini yarating." #: src/handlers/file_dialog_handler.py:86 msgid "_OK" msgstr "Hop" #: src/handlers/file_dialog_handler.py:109 src/handlers/file_dialog_handler.py:177 msgid "MIDI files" msgstr "MIDI fayllar" #: src/handlers/file_dialog_handler.py:115 msgid "Open MIDI File" msgstr "MIDI faylni ochish" #: src/handlers/file_dialog_handler.py:185 msgid "Save Sequence" msgstr "Ketma-ketlikni saqlash" #: src/utils/export_progress.py:68 msgid "Preparing..." msgstr "Tayyorlanmoqda…" #: src/utils/export_progress.py:69 msgid "Initializing..." msgstr "Ishga tushirilmoqda..." #: src/utils/export_progress.py:71 msgid "Rendering audio..." msgstr "Audio tayyorlanmoqda..." #: src/utils/export_progress.py:72 msgid "Processing beats..." msgstr "Ritmlar ishlanmoqda..." #: src/utils/export_progress.py:74 msgid "Saving file..." msgstr "Fayl saqlanmoqda..." #: src/utils/export_progress.py:75 msgid "Writing to disk..." msgstr "Diskka yozilmoqda..." #: src/utils/export_progress.py:77 msgid "Exporting..." msgstr "Eksport qilinmoqda…" #: src/utils/export_progress.py:78 msgid "Processing..." msgstr "Qayta ishlanmoqda..." #. Update tooltip and accessibility with current BPM #: src/window.py:198 msgid "{} Beats per Minute (BPM)" msgstr "Daqiqasiga {} ta zarba (DZ)" #. Update button tooltip to show current volume level #: src/window.py:207 msgid "{:.0f}% Volume" msgstr "{:.0f}% ovoz balandligi" #: src/window.py:222 src/window.ui:170 msgid "Play" msgstr "Ijro" #: src/window.py:226 msgid "Pause" msgstr "To‘xtatish" #: src/window.py:264 src/window.ui:52 msgid "Open" msgstr "Ochish" #: src/window.ui:54 msgid "Open Preset" msgstr "Tayyor sozlamani ochish" #: src/window.ui:57 msgctxt "accessibility" msgid "Open Preset" msgstr "Tayyor sozlamani ochish" #: src/window.ui:58 msgid "Open Saved Drum Pattern Preset" msgstr "Saqlangan baraban naqsh sozlamasini ochish" #: src/window.ui:76 msgid "Main Menu" msgstr "Asosiy menyu" #: src/window.ui:78 msgctxt "accessibility" msgid "Main Menu" msgstr "Asosiy menyu" #: src/window.ui:79 msgid "Access Keyboard Shortcuts and Application Information" msgstr "Klaviatura yorliqlari va ilova haqidagi axborotga kirish" #: src/window.ui:86 src/gtk/audio-export-dialog.blp:6 #: src/gtk/audio-export-dialog.blp:96 msgid "Export Audio" msgstr "Audioni eksport qilish" #: src/window.ui:88 msgctxt "accessibility" msgid "Export Audio" msgstr "Audioni eksport qilish" #: src/window.ui:89 msgid "Export Current Drum Pattern as Audio File" msgstr "Joriy baraban naqshini audio fayl sifatida eksport qilish" #: src/window.ui:134 msgid "BPM" msgstr "DZ" #: src/window.ui:139 src/window.ui:143 msgid "Adjust Tempo In Beats per Minute (BPM)" msgstr "Bir daqiqadagi zarbalar tezligini sozlash (DZ)" #: src/window.ui:142 msgid "Tempo" msgstr "Tezlik" #: src/window.ui:184 msgid "Adjust Volume" msgstr "Ovoz balandligini sozlash" #: src/window.ui:207 msgid "Reset" msgstr "Qayta tiklash" #: src/window.ui:208 msgid "Reset the Drum Sequence" msgstr "Baraban ketma-ketligini asliga qaytarish" # andaza soʻzi togʻri keladimi bu yerga? #: src/window.ui:223 #, fuzzy msgid "_Save Pattern" msgstr "Naqshni saqlash" #: src/window.ui:229 msgid "_Keyboard Shortcuts" msgstr "Klaviatura yorliqlari" #: src/window.ui:233 msgid "_About Drum Machine" msgstr "Barabanli mashina haqida" #: src/gtk/help-overlay.blp:11 msgctxt "shortcut window" msgid "General" msgstr "Umumiy" #: src/gtk/help-overlay.blp:14 msgctxt "shortcut window" msgid "Show Shortcuts" msgstr "Yorliqlarni koʼrsatish" #: src/gtk/help-overlay.blp:19 msgctxt "shortcut window" msgid "Quit" msgstr "Chiqish" #: src/gtk/help-overlay.blp:26 msgctxt "shortcut window" msgid "Playback Controls" msgstr "Ijro boshqaruvi" #: src/gtk/help-overlay.blp:29 msgctxt "shortcut window" msgid "Play/Pause" msgstr "Tinglash/Toʻxtatish" #: src/gtk/help-overlay.blp:35 msgctxt "shortcut window" msgid "Clear All" msgstr "Hammasini tozalash" #: src/gtk/help-overlay.blp:42 msgctxt "shortcut window" msgid "BPM & Volume Controls" msgstr "DZ va tovush balandligini boshqarish" #: src/gtk/help-overlay.blp:45 msgctxt "shortcut window" msgid "Increase BPM" msgstr "DZ darajasini oshirish" #: src/gtk/help-overlay.blp:51 msgctxt "shortcut window" msgid "Decrease BPM" msgstr "DZ darajasini kamaytirish" #: src/gtk/help-overlay.blp:57 msgctxt "shortcut window" msgid "Increase Volume" msgstr "Ovoz balandligini oshirish" #: src/gtk/help-overlay.blp:63 msgctxt "shortcut window" msgid "Decrease Volume" msgstr "Ovoz balandligini pasaytirish" #: src/gtk/help-overlay.blp:69 msgctxt "shortcut window" msgid "Mute" msgstr "Ovozsiz" #: src/gtk/help-overlay.blp:76 msgctxt "shortcut window" msgid "Preset Management" msgstr "Oldindan sozlash boshqaruvi" #: src/gtk/help-overlay.blp:79 msgctxt "shortcut window" msgid "Load Preset" msgstr "Tayyor sozlamani yuklash" #: src/gtk/help-overlay.blp:85 msgctxt "shortcut window" msgid "Save Preset" msgstr "Tayyor sozlamani saqlash" #: src/gtk/help-overlay.blp:91 msgctxt "shortcut window" msgid "Export Audio" msgstr "Audioni eksport qilish" #: src/gtk/help-overlay.blp:98 msgctxt "shortcut window" msgid "Navigation" msgstr "Navigatsiya" #: src/gtk/help-overlay.blp:101 msgctxt "shortcut window" msgid "Go to Instrument" msgstr "Uskunani ochish" #: src/gtk/help-overlay.blp:107 msgctxt "shortcut window" msgid "Previous Page" msgstr "Oldingi sahifa" #: src/gtk/help-overlay.blp:113 msgctxt "shortcut window" msgid "Next Page" msgstr "Keyingi sahifa" #: src/gtk/save-changes-dialog.blp:5 msgid "Save Changes?" msgstr "Oʻzgarishlar saqlansinmi?" #: src/gtk/save-changes-dialog.blp:6 msgid "" "Current preset contains unsaved changes. Changes which are not saved will be " "permanently lost." msgstr "" "Joriy sozlamada saqlanmagan o‘zgarishlar mavjud. Saqlanmagan o‘zgarishlar " "butunlay yo‘qoladi." #. Translators: Cancel the operation #: src/gtk/save-changes-dialog.blp:14 msgid "_Cancel" msgstr "Bekor qilish" #. Translators: Discard all changes #: src/gtk/save-changes-dialog.blp:15 msgid "_Discard" msgstr "Bekor qilish" #. Translators: Save current changes #: src/gtk/save-changes-dialog.blp:16 msgid "_Save" msgstr "Saqlash" #: src/gtk/audio-export-dialog.blp:39 msgid "Audio Format" msgstr "Audio formati" #: src/gtk/audio-export-dialog.blp:45 msgid "Repeat Count" msgstr "Takrorlashlar soni" #: src/gtk/audio-export-dialog.blp:46 msgid "How many times to repeat the pattern" msgstr "Naqshni necha marta takrorlash kerak" #: src/gtk/audio-export-dialog.blp:59 msgid "Metadata" msgstr "Meta maʼlumotlar" #: src/gtk/audio-export-dialog.blp:62 msgid "Artist Name" msgstr "Ijrochi nomi" #: src/gtk/audio-export-dialog.blp:67 msgid "Song Name" msgstr "Tarona nomi" #: src/gtk/audio-export-dialog.blp:72 msgid "Cover Art" msgstr "Muqova san’ati" #: src/gtk/audio-export-dialog.blp:76 msgid "Choose File" msgstr "Faylni tanlash" #: src/gtk/audio-export-dialog.blp:105 msgid "Cancel Export" msgstr "Eksportni bekor qilish" drum-machine-2.2.0/po/zh_CN.po000066400000000000000000000535031514070543000160500ustar00rootroot00000000000000# Chinese (China) translation for drum-machine. # Copyright (C) 2025 drum-machine's COPYRIGHT HOLDER # This file is distributed under the same license as the drum-machine package. # lumingzh , 2025. # msgid "" msgstr "" "Project-Id-Version: drum-machine master\n" "Report-Msgid-Bugs-To: https://github.com/revisto/drum-machine/issues\n" "POT-Creation-Date: 2025-12-13 03:26+0000\n" "PO-Revision-Date: 2025-12-13 11:47+0800\n" "Last-Translator: lumingzh \n" "Language-Team: Chinese (China) \n" "Language: zh_CN\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: Gtranslator 49.0\n" #: data/io.github.revisto.drum-machine.desktop.in:2 #: data/io.github.revisto.drum-machine.metainfo.xml.in:6 src/application.py:67 #: src/window.ui:69 msgid "Drum Machine" msgstr "击鼓器" #. Translators: Search terms to find this application. Do NOT translate or localise the semicolons! The list MUST also end with a semicolon! #: data/io.github.revisto.drum-machine.desktop.in:9 msgid "drum;drums;sequencer;rhythm;music;pattern;beats;percussion;loop;groove;" msgstr "" "drum;drums;sequencer;rhythm;music;pattern;beats;percussion;loop;groove;击鼓;" "敲鼓;序列器;节奏;音乐;模式;方案;节拍;拍子;打击乐器;循环;律动;" #: data/io.github.revisto.drum-machine.metainfo.xml.in:7 msgid "Create and play drum beats" msgstr "创建和播放击鼓节奏" #: data/io.github.revisto.drum-machine.metainfo.xml.in:9 msgid "" "Drum Machine is a modern and intuitive application for creating, playing, " "and managing drum patterns. Perfect for musicians, producers, and anyone " "interested in rhythm creation, this application provides a simple interface " "for drum pattern programming. Have fun!" msgstr "" "击鼓器是一个创建、播放和管理击鼓模式的现代且直观的应用程序。完美适用于音乐" "家、创作者和对韵律创作感兴趣的任何人,此应用程序提供了一个用于击鼓模式编程的" "简单界面。玩的开心!" #: data/io.github.revisto.drum-machine.metainfo.xml.in:15 msgid "Features:" msgstr "特性:" #: data/io.github.revisto.drum-machine.metainfo.xml.in:17 msgid "Intuitive grid-based pattern editor with infinite pages" msgstr "直观的基于网格具有无限页面的模式编辑器" #: data/io.github.revisto.drum-machine.metainfo.xml.in:18 msgid "Custom samples: Add your own drum sounds with MIDI note mapping" msgstr "自定义采样:使用 MIDI 音符映射添加您自己的击鼓音色" #: data/io.github.revisto.drum-machine.metainfo.xml.in:19 msgid "Adjustable BPM control" msgstr "可调节的 BPM 控制" #: data/io.github.revisto.drum-machine.metainfo.xml.in:20 msgid "Volume control for overall mix" msgstr "整体混音的音量控制" #: data/io.github.revisto.drum-machine.metainfo.xml.in:21 msgid "Save and load patterns" msgstr "保存和加载模式" #: data/io.github.revisto.drum-machine.metainfo.xml.in:22 msgid "Multiple drum sounds including kick, snare, hi-hat, and more" msgstr "多种击鼓音色,包括底鼓、军鼓、踩镲和其它更多音色" #: data/io.github.revisto.drum-machine.metainfo.xml.in:23 msgid "" "Audio and MIDI export with support for WAV, FLAC, Ogg, MP3, and MIDI formats" msgstr "音频和 MIDI 导出功能支持 WAV、FLAC、Ogg、MP3 和 MIDI 格式" #: data/io.github.revisto.drum-machine.metainfo.xml.in:24 msgid "Metadata support for embedding artist name, song title, and cover art" msgstr "支持嵌入艺人姓名、曲目标题和封面的元数据" #: data/io.github.revisto.drum-machine.metainfo.xml.in:25 msgid "Keyboard shortcuts for quick access to all functions" msgstr "用于快速访问所有功能的键盘快捷键" #: data/io.github.revisto.drum-machine.metainfo.xml.in:34 msgid "Drum Pattern Loaded in Light Mode" msgstr "以亮色模式加载击鼓模式" #: data/io.github.revisto.drum-machine.metainfo.xml.in:38 msgid "Drum Pattern Loaded in Dark Mode" msgstr "以暗色模式加载击鼓模式" #: src/application.py:74 msgid "" "Drum Machine is a modern and intuitive application for creating, playing, " "and managing drum patterns." msgstr "击鼓器是一款用于创建、播放和管理击鼓模式现代且直观的应用程序。" #: src/application.py:79 msgid "translator-credits" msgstr "lumingzh , 2025." #: src/application.py:84 msgid "Special thanks" msgstr "特别感谢" #: src/application.py:87 msgid "Sounds" msgstr "声音" #: src/application.py:88 #, python-brace-format msgid "The drum samples used in this application are from {link}." msgstr "此应用程序中使用的击鼓采样来自于 {link}。" #: src/config/export_formats.py:44 msgid "MP3 files" msgstr "MP3 文件" #: src/config/export_formats.py:45 msgid "MP3" msgstr "MP3" #: src/config/export_formats.py:51 msgid "FLAC files" msgstr "FLAC 文件" #: src/config/export_formats.py:52 msgid "FLAC (Lossless)" msgstr "FLAC(无损)" #: src/config/export_formats.py:58 msgid "Ogg files" msgstr "Ogg 文件" #: src/config/export_formats.py:59 msgid "Ogg Vorbis" msgstr "Ogg Vorbis" #: src/config/export_formats.py:65 msgid "WAV files" msgstr "WAV 文件" #: src/config/export_formats.py:66 msgid "WAV (Uncompressed)" msgstr "WAV(未压缩)" #: src/dialogs/audio_export_dialog.py:119 msgid "Save Audio File" msgstr "保存音频文件" #: src/dialogs/audio_export_dialog.py:148 msgid "Part “{}” is Silent" msgstr "“{}”部分是无声的" #: src/dialogs/audio_export_dialog.py:150 msgid "Parts “{}” and “{}” are Silent" msgstr "“{}”和“{}”部分是无声的" #: src/dialogs/audio_export_dialog.py:154 msgid "{} Parts are Silent" msgstr "{} 个部分是无声的" #: src/dialogs/audio_export_dialog.py:179 msgid "Image files" msgstr "图像文件" #: src/dialogs/audio_export_dialog.py:185 msgid "Select Cover Art" msgstr "选择封面" #: src/dialogs/audio_export_dialog.py:245 msgid "Audio exported to {}" msgstr "音频已导出至 {}" #: src/dialogs/audio_export_dialog.py:251 msgid "Export failed" msgstr "导出失败" #: src/dialogs/audio_export_dialog.py:258 msgid "Export cancelled successfully" msgstr "导出已成功取消" #: src/dialogs/midi_mapping_dialog.py:22 msgid "Acoustic Bass Drum" msgstr "原声底鼓" #: src/dialogs/midi_mapping_dialog.py:23 msgid "Bass Drum 1" msgstr "底鼓 1" #: src/dialogs/midi_mapping_dialog.py:24 msgid "Side Stick" msgstr "边击" #: src/dialogs/midi_mapping_dialog.py:25 msgid "Acoustic Snare" msgstr "原声军鼓" #: src/dialogs/midi_mapping_dialog.py:26 msgid "Hand Clap" msgstr "拍手" #: src/dialogs/midi_mapping_dialog.py:27 msgid "Electric Snare" msgstr "电子军鼓" #: src/dialogs/midi_mapping_dialog.py:28 msgid "Low Floor Tom" msgstr "低音落地桶鼓" #: src/dialogs/midi_mapping_dialog.py:29 msgid "Closed Hi Hat" msgstr "闭合踩镲" #: src/dialogs/midi_mapping_dialog.py:30 msgid "High Floor Tom" msgstr "高音落地桶鼓" #: src/dialogs/midi_mapping_dialog.py:31 msgid "Pedal Hi Hat" msgstr "脚踩踩镲" #: src/dialogs/midi_mapping_dialog.py:32 msgid "Low Tom" msgstr "低音桶鼓" #: src/dialogs/midi_mapping_dialog.py:33 msgid "Open Hi Hat" msgstr "开放踩镲" #: src/dialogs/midi_mapping_dialog.py:34 msgid "Low-Mid Tom" msgstr "中低音桶鼓" #: src/dialogs/midi_mapping_dialog.py:35 msgid "Hi-Mid Tom" msgstr "中高音桶鼓" #: src/dialogs/midi_mapping_dialog.py:36 msgid "Crash Cymbal 1" msgstr "碎音钹 1" #: src/dialogs/midi_mapping_dialog.py:37 msgid "High Tom" msgstr "高音桶鼓" #: src/dialogs/midi_mapping_dialog.py:38 msgid "Ride Cymbal 1" msgstr "节奏钹 1" #: src/dialogs/midi_mapping_dialog.py:39 msgid "Chinese Cymbal" msgstr "中国钹" #: src/dialogs/midi_mapping_dialog.py:40 msgid "Ride Bell" msgstr "钹帽" #: src/dialogs/midi_mapping_dialog.py:41 msgid "Tambourine" msgstr "铃鼓" #: src/dialogs/midi_mapping_dialog.py:42 msgid "Splash Cymbal" msgstr "水钹" #: src/dialogs/midi_mapping_dialog.py:43 msgid "Cowbell" msgstr "牛铃" #: src/dialogs/midi_mapping_dialog.py:44 msgid "Crash Cymbal 2" msgstr "碎音钹 2" #: src/dialogs/midi_mapping_dialog.py:45 msgid "Vibraslap" msgstr "颤音叉" #: src/dialogs/midi_mapping_dialog.py:46 msgid "Ride Cymbal 2" msgstr "节奏钹 2" #: src/dialogs/midi_mapping_dialog.py:47 msgid "Hi Bongo" msgstr "高音邦戈鼓" #: src/dialogs/midi_mapping_dialog.py:48 msgid "Low Bongo" msgstr "低音邦戈鼓" #: src/dialogs/midi_mapping_dialog.py:49 msgid "Mute Hi Conga" msgstr "闷音高音康加鼓" #: src/dialogs/midi_mapping_dialog.py:50 msgid "Open Hi Conga" msgstr "开放音高音康加鼓" #: src/dialogs/midi_mapping_dialog.py:51 msgid "Low Conga" msgstr "低音康加鼓" #: src/dialogs/midi_mapping_dialog.py:52 msgid "High Timbale" msgstr "高音天巴鼓" #: src/dialogs/midi_mapping_dialog.py:53 msgid "Low Timbale" msgstr "低音天巴鼓" #: src/dialogs/midi_mapping_dialog.py:54 msgid "High Agogo" msgstr "高音阿哥哥铃" #: src/dialogs/midi_mapping_dialog.py:55 msgid "Low Agogo" msgstr "低音阿哥哥铃" #: src/dialogs/midi_mapping_dialog.py:56 msgid "Cabasa" msgstr "卡巴萨" #: src/dialogs/midi_mapping_dialog.py:57 msgid "Maracas" msgstr "沙槌" #: src/dialogs/midi_mapping_dialog.py:58 msgid "Short Whistle" msgstr "短哨" #: src/dialogs/midi_mapping_dialog.py:59 msgid "Long Whistle" msgstr "长哨" #: src/dialogs/midi_mapping_dialog.py:60 msgid "Short Guiro" msgstr "短刮鱼" #: src/dialogs/midi_mapping_dialog.py:61 msgid "Long Guiro" msgstr "长刮鱼" #: src/dialogs/midi_mapping_dialog.py:62 msgid "Claves" msgstr "响木" #: src/dialogs/midi_mapping_dialog.py:63 msgid "Hi Wood Block" msgstr "高音木鱼" #: src/dialogs/midi_mapping_dialog.py:64 msgid "Low Wood Block" msgstr "低音木鱼" #: src/dialogs/midi_mapping_dialog.py:65 msgid "Mute Cuica" msgstr "闷音桂嘎鼓" #: src/dialogs/midi_mapping_dialog.py:66 msgid "Open Cuica" msgstr "开放音桂嘎鼓" #: src/dialogs/midi_mapping_dialog.py:67 msgid "Mute Triangle" msgstr "闷音三角铁" #: src/dialogs/midi_mapping_dialog.py:68 msgid "Open Triangle" msgstr "开放音三角铁" #: src/dialogs/midi_mapping_dialog.py:78 src/ui/drum_grid_builder.py:338 msgid "MIDI Mapping" msgstr "MIDI 映射" #. Group 1: Note Assignment #: src/dialogs/midi_mapping_dialog.py:108 msgid "Note Assignment" msgstr "音符分配" #: src/dialogs/midi_mapping_dialog.py:111 msgid "" "Assign a MIDI note for '{}'. This ensures correct playback when exporting." msgstr "为“{}”分配 MIDI 音符。这确保了导出时可以正确播放。" #. Action Row for Note #: src/dialogs/midi_mapping_dialog.py:118 msgid "MIDI Note" msgstr "MIDI 音符" #: src/dialogs/midi_mapping_dialog.py:119 msgid "The note number to trigger" msgstr "要触发的音符编号" #. Group 2: Standard Instruments #: src/dialogs/midi_mapping_dialog.py:137 msgid "Standard Instruments" msgstr "标准乐器" #: src/dialogs/midi_mapping_dialog.py:139 msgid "Select a General MIDI instrument to automatically set the note." msgstr "选择常规 MIDI 乐器以自动设定音符。" #: src/dialogs/midi_mapping_dialog.py:143 msgid "Instrument Preset" msgstr "乐器预设" #: src/dialogs/midi_mapping_dialog.py:186 msgid "Save" msgstr "保存" #: src/dialogs/midi_mapping_dialog.py:229 msgid "Custom Note" msgstr "自定义音符" #: src/handlers/drag_drop_handler.py:113 msgid "Sound replaced" msgstr "声音已替换" #: src/handlers/drag_drop_handler.py:116 msgid "Failed to replace sound" msgstr "替换声音失败" #: src/handlers/drag_drop_handler.py:126 msgid "Not a supported audio file" msgstr "不受支持的音频文件" #: src/handlers/drag_drop_handler.py:134 msgid "File not found" msgstr "文件未找到" #: src/handlers/drag_drop_handler.py:139 msgid "Selected item is not a file" msgstr "选中项目不是文件" #: src/handlers/drag_drop_handler.py:146 msgid "File too large: {:.1f}MB (max 50MB)" msgstr "文件太大了:{:.1f}MB(最大 50MB)" #: src/handlers/drag_drop_handler.py:174 msgid "No valid audio files found" msgstr "未找到有效音频文件" #: src/handlers/drag_drop_handler.py:209 msgid "Error processing file: {}" msgstr "处理文件时出错:{}" #: src/handlers/drag_drop_handler.py:237 msgid "Added {} drum part, {} files skipped" msgstr "添加了 {} 个击鼓部分,跳过了 {} 个文件" #: src/handlers/drag_drop_handler.py:243 msgid "Added {} drum parts, {} files skipped" msgstr "添加了 {} 个击鼓部分,跳过了 {} 个文件" #: src/handlers/drag_drop_handler.py:248 msgid "Added {} drum parts" msgstr "添加了 {} 个击鼓部分" #. Only show skipped message if no replacement happened #: src/handlers/drag_drop_handler.py:251 msgid "{} files skipped" msgstr "跳过了 {} 个文件" #: src/handlers/file_dialog_handler.py:52 msgid "Default Patterns" msgstr "默认模式" #: src/handlers/file_dialog_handler.py:92 #: src/handlers/file_dialog_handler.py:171 msgid "MIDI files" msgstr "MIDI 文件" #: src/handlers/file_dialog_handler.py:98 msgid "Open MIDI File" msgstr "打开 MIDI 文件" #: src/handlers/file_dialog_handler.py:127 msgid "Failed to open file" msgstr "打开文件失败" #: src/handlers/file_dialog_handler.py:165 msgid "Failed to load pattern" msgstr "加载模式失败" #: src/handlers/file_dialog_handler.py:179 msgid "Save Sequence" msgstr "保存序列" #: src/handlers/file_dialog_handler.py:205 msgid "Add Audio Samples" msgstr "添加音频采样" #: src/handlers/file_dialog_handler.py:227 msgid "Audio files" msgstr "音频文件" #: src/utils/export_progress.py:76 msgid "Preparing…" msgstr "正在准备…" #: src/utils/export_progress.py:77 msgid "Initializing…" msgstr "正在初始化…" #: src/utils/export_progress.py:79 msgid "Rendering audio…" msgstr "正在渲染音频…" #: src/utils/export_progress.py:80 msgid "Processing beats…" msgstr "正在处理节拍…" #: src/utils/export_progress.py:82 msgid "Saving file…" msgstr "正在保存文件…" #: src/utils/export_progress.py:83 msgid "Writing to disk…" msgstr "正在写入磁盘…" #: src/utils/export_progress.py:85 msgid "Exporting…" msgstr "正在导出…" #: src/utils/export_progress.py:86 msgid "Processing…" msgstr "正在处理…" #: src/utils/name_utils.py:36 msgid "Custom Sound" msgstr "自定义声音" #: src/ui/drum_grid_builder.py:323 msgid "Preview" msgstr "预览" #: src/ui/drum_grid_builder.py:325 msgid "Replace…" msgstr "替换…" #: src/ui/drum_grid_builder.py:328 msgid "Replace with new sound" msgstr "使用新声音替换" #: src/ui/drum_grid_builder.py:331 msgid "Remove" msgstr "移除" #: src/ui/drum_grid_builder.py:334 msgid "At least one drum part must remain" msgstr "必须保留至少一个击鼓部分" #: src/ui/drum_grid_builder.py:341 msgid "Configure MIDI note for export" msgstr "配置 MIDI 音符导出选项" #: src/ui/drum_grid_builder.py:398 msgid "MIDI note updated" msgstr "MIDI 音符已更新" #: src/ui/drum_grid_builder.py:406 msgid "Select New Sound" msgstr "选择新声音" #: src/ui/drum_grid_builder.py:420 msgid "Removed drum part: {}" msgstr "已移除击鼓部分:{}" #: src/ui/drum_grid_builder.py:425 msgid "Failed to remove drum part" msgstr "移除击鼓部分失败" #. Update tooltip and accessibility with current BPM #: src/window.py:225 msgid "{} Beats per Minute (BPM)" msgstr "每分钟 {} 节拍(BPM)" #. Update button tooltip to show current volume level #: src/window.py:234 msgid "{:.0f}% Volume" msgstr "{:.0f}% 音量" #: src/window.py:251 src/window.ui:173 msgid "Play" msgstr "播放" #: src/window.py:255 msgid "Pause" msgstr "暂停" #: src/window.py:302 msgid "Open" msgstr "打开" #: src/window.py:320 msgid "Added: {}" msgstr "已添加:{}" #: src/window.py:335 msgid "Failed to add custom sound" msgstr "添加自定义声音失败" #: src/window.py:342 msgid "Replaced drum with: {}" msgstr "已替换击鼓为:{}" #: src/window.py:350 msgid "Failed to replace drum sound" msgstr "替换击鼓声音失败" #: src/window.ui:52 msgid "Open…" msgstr "打开…" #: src/window.ui:54 msgid "Open Pattern" msgstr "打开模式" #: src/window.ui:57 msgctxt "accessibility" msgid "Open Pattern" msgstr "打开模式" #: src/window.ui:58 msgid "Open Saved Drum Pattern" msgstr "打开已保存的击鼓模式" #: src/window.ui:76 msgid "Main Menu" msgstr "主菜单" #: src/window.ui:78 msgctxt "accessibility" msgid "Main Menu" msgstr "主菜单" #: src/window.ui:79 msgid "Access Keyboard Shortcuts and Application Information" msgstr "访问键盘快捷键和应用程序信息" #: src/window.ui:86 msgid "Export Audio…" msgstr "导出音频…" #: src/window.ui:91 msgctxt "accessibility" msgid "Export Audio…" msgstr "导出音频…" #: src/window.ui:92 msgid "Export Current Drum Pattern as Audio File" msgstr "将当前击鼓模式导出为音频文件" #: src/window.ui:137 msgid "BPM" msgstr "BPM" #: src/window.ui:142 src/window.ui:146 msgid "Adjust Tempo In Beats per Minute (BPM)" msgstr "以每分钟节拍为单位调节拍子(BPM)" #: src/window.ui:145 msgid "Tempo" msgstr "拍子" #: src/window.ui:187 msgid "Adjust Volume" msgstr "调整音量" #: src/window.ui:210 msgid "Reset" msgstr "重置" #: src/window.ui:211 msgid "Reset the Drum Sequence" msgstr "重置击鼓序列" #: src/window.ui:226 msgid "_Add Samples…" msgstr "添加采样(_A)…" #: src/window.ui:230 msgid "_Save Pattern…" msgstr "保存模式(_S)…" #: src/window.ui:236 msgid "_Keyboard Shortcuts" msgstr "键盘快捷键(_K)" #: src/window.ui:240 msgid "_About Drum Machine" msgstr "关于击鼓器(_A)" #: src/gtk/help-overlay.blp:11 msgctxt "shortcut window" msgid "General" msgstr "常规" #: src/gtk/help-overlay.blp:14 msgctxt "shortcut window" msgid "Show Shortcuts" msgstr "显示快捷键" #: src/gtk/help-overlay.blp:19 msgctxt "shortcut window" msgid "Quit" msgstr "退出" #: src/gtk/help-overlay.blp:26 msgctxt "shortcut window" msgid "Playback Controls" msgstr "播放控制" #: src/gtk/help-overlay.blp:29 msgctxt "shortcut window" msgid "Play/Pause" msgstr "播放/暂停" #: src/gtk/help-overlay.blp:35 msgctxt "shortcut window" msgid "Clear All" msgstr "全部清除" #: src/gtk/help-overlay.blp:42 msgctxt "shortcut window" msgid "BPM & Volume Controls" msgstr "BPM 和音量控制" #: src/gtk/help-overlay.blp:45 msgctxt "shortcut window" msgid "Increase BPM" msgstr "增加 BPM" #: src/gtk/help-overlay.blp:51 msgctxt "shortcut window" msgid "Decrease BPM" msgstr "减少 BPM" #: src/gtk/help-overlay.blp:57 msgctxt "shortcut window" msgid "Increase Volume" msgstr "增大音量" #: src/gtk/help-overlay.blp:63 msgctxt "shortcut window" msgid "Decrease Volume" msgstr "减小音量" #: src/gtk/help-overlay.blp:69 msgctxt "shortcut window" msgid "Mute" msgstr "静音" #: src/gtk/help-overlay.blp:76 msgctxt "shortcut window" msgid "Pattern Management" msgstr "模式管理" #: src/gtk/help-overlay.blp:79 msgctxt "shortcut window" msgid "Load Pattern" msgstr "加载模式" #: src/gtk/help-overlay.blp:85 msgctxt "shortcut window" msgid "Save Pattern" msgstr "保存模式" #: src/gtk/help-overlay.blp:91 msgctxt "shortcut window" msgid "Export Audio" msgstr "导出音频" #: src/gtk/help-overlay.blp:98 msgctxt "shortcut window" msgid "Navigation" msgstr "导航" #: src/gtk/help-overlay.blp:101 msgctxt "shortcut window" msgid "Go to Instrument" msgstr "前往乐器" #: src/gtk/help-overlay.blp:107 msgctxt "shortcut window" msgid "Previous Page" msgstr "上一页" #: src/gtk/help-overlay.blp:113 msgctxt "shortcut window" msgid "Next Page" msgstr "下一页" #: src/gtk/save-changes-dialog.blp:5 msgid "Save Changes?" msgstr "保存更改吗?" #: src/gtk/save-changes-dialog.blp:6 msgid "" "Current pattern contains unsaved changes. Changes which are not saved will " "be permanently lost." msgstr "当前模式包含未保存更改。未保存的更改将会永久丢失。" #. Translators: Cancel the operation #: src/gtk/save-changes-dialog.blp:14 msgid "_Cancel" msgstr "取消(_C)" #. Translators: Discard all changes #: src/gtk/save-changes-dialog.blp:15 msgid "_Discard" msgstr "丢弃(_D)" #. Translators: Save current changes #: src/gtk/save-changes-dialog.blp:16 msgid "_Save" msgstr "保存(_S)" #: src/gtk/audio-export-dialog.blp:6 src/gtk/audio-export-dialog.blp:101 msgid "Export Audio" msgstr "导出音频" #: src/gtk/audio-export-dialog.blp:44 msgid "Audio Format" msgstr "音频格式" #: src/gtk/audio-export-dialog.blp:50 msgid "Repeat Count" msgstr "重复计数" #: src/gtk/audio-export-dialog.blp:51 msgid "How many times to repeat the pattern" msgstr "重复击鼓模式的次数" #: src/gtk/audio-export-dialog.blp:64 msgid "Metadata" msgstr "元数据" #: src/gtk/audio-export-dialog.blp:67 msgid "Artist Name" msgstr "艺人姓名" #: src/gtk/audio-export-dialog.blp:72 msgid "Song Name" msgstr "曲目名称" #: src/gtk/audio-export-dialog.blp:77 msgid "Cover Art" msgstr "封面" #: src/gtk/audio-export-dialog.blp:81 msgid "Choose File…" msgstr "选择文件…" #: src/gtk/audio-export-dialog.blp:110 msgid "Cancel Export" msgstr "取消导出" #~ msgid "No Pattern" #~ msgstr "无模式" #~ msgid "Please create a drum pattern before exporting audio." #~ msgstr "请在导出音频前创建击鼓模式。" #~ msgid "_OK" #~ msgstr "确定(_O)" #~ msgid "Open Preset" #~ msgstr "打开预设" #~ msgctxt "accessibility" #~ msgid "Open Preset" #~ msgstr "打开预设" #~ msgctxt "shortcut window" #~ msgid "Load Preset" #~ msgstr "加载预设" #~ msgctxt "shortcut window" #~ msgid "Save Preset" #~ msgstr "保存预设" #~ msgctxt "accessibility" #~ msgid "Export Audio" #~ msgstr "导出音频" #~ msgid "Export Settings" #~ msgstr "导出设置" #~ msgid "Select the output audio format" #~ msgstr "选择输出的音频格式" #~ msgid "Add metadata to your exported audio" #~ msgstr "添加元数据至您导出的音频" #~ msgid "Select an image file for the cover art" #~ msgstr "选择用于封面的图像文件" #~ msgctxt "accessibility" #~ msgid "Save Drum Pattern" #~ msgstr "保存击鼓模式" drum-machine-2.2.0/python-dependencies.json000077500000000000000000000113571514070543000207350ustar00rootroot00000000000000{ "name": "python-dependencies", "buildsystem": "simple", "build-commands": [], "modules": [ { "name": "python3-pygame", "buildsystem": "simple", "build-commands": [ "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"pygame\"" ], "sources": [ { "type": "file", "url": "https://files.pythonhosted.org/packages/49/cc/08bba60f00541f62aaa252ce0cfbd60aebd04616c0b9574f755b583e45ae/pygame-2.6.1.tar.gz", "sha256": "56fb02ead529cee00d415c3e007f75e0780c655909aaa8e8bf616ee09c9feb1f" }, { "type": "file", "url": "https://files.pythonhosted.org/packages/a3/dc/17031897dae0efacfea57dfd3a82fdd2a2aeb58e0ff71b77b87e44edc772/setuptools-80.9.0-py3-none-any.whl", "sha256": "062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922" } ] }, { "name": "python3-mido", "buildsystem": "simple", "build-commands": [ "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"mido\"" ], "sources": [ { "type": "file", "url": "https://files.pythonhosted.org/packages/fd/28/45deb15c11859d2f10702b32e71de9328a9fa494f989626916db39a9617f/mido-1.3.3-py3-none-any.whl", "sha256": "01033c9b10b049e4436fca2762194ca839b09a4334091dd3c34e7f4ae674fd8a" }, { "type": "file", "url": "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", "sha256": "29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484" } ] }, { "name": "python3-setuptools-scm", "buildsystem": "simple", "build-commands": [ "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"setuptools-scm\"" ], "sources": [ { "type": "file", "url": "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", "sha256": "29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484" }, { "type": "file", "url": "https://files.pythonhosted.org/packages/f7/14/dd3a6053325e882fe191fb4b42289bbdfabf5f44307c302903a8a3236a0a/setuptools_scm-9.2.0-py3-none-any.whl", "sha256": "c551ef54e2270727ee17067881c9687ca2aedf179fa5b8f3fab9e8d73bdc421f" } ] }, { "name": "python3-packaging", "buildsystem": "simple", "build-commands": [ "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"packaging\"" ], "sources": [ { "type": "file", "url": "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", "sha256": "29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484" } ] }, { "name": "python3-numpy", "buildsystem": "simple", "build-commands": [ "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"numpy\"" ], "sources": [ { "type": "file", "url": "https://files.pythonhosted.org/packages/59/ef/f96536f1df42c668cbacb727a8c6da7afc9c05ece6d558927fb1722693e1/numpy-2.3.2-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", "sha256": "8145dd6d10df13c559d1e4314df29695613575183fa2e2d11fac4c208c8a1f73" }, { "type": "file", "url": "https://files.pythonhosted.org/packages/91/ba/f4ebf257f08affa464fe6036e13f2bf9d4642a40228781dc1235da81be9f/numpy-2.3.2-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", "sha256": "572d5512df5470f50ada8d1972c5f1082d9a0b7aa5944db8084077570cf98370" } ] } ] }drum-machine-2.2.0/requirements.txt000066400000000000000000000000661514070543000173510ustar00rootroot00000000000000pygame mido setuptools setuptools-scm packaging numpy drum-machine-2.2.0/snap/000077500000000000000000000000001514070543000150245ustar00rootroot00000000000000drum-machine-2.2.0/snap/snapcraft.yaml000066400000000000000000000072061514070543000176760ustar00rootroot00000000000000name: drum-machine title: Drum Machine base: core24 license: GPL-3.0-or-later grade: stable confinement: strict compression: lzo adopt-info: drum-machine contact: - therevisto@gmail.com issues: - https://github.com/Revisto/drum-machine/issues donation: - https://patreon.com/Revisto source-code: - https://github.com/Revisto/drum-machine website: - https://apps.gnome.org/DrumMachine/ platforms: amd64: arm64: armhf: plugs: ffmpeg-2404: interface: content target: ffmpeg-platform default-provider: ffmpeg-2404 slots: drum-machine-mpris: interface: mpris name: drum-machine drum-machine: interface: dbus bus: session name: io.github.revisto.drum-machine parts: python-deps: plugin: python source: https://github.com/revisto/drum-machine.git source-tag: 'v2.0.0' source-depth: 1 python-packages: - pygame - mido - numpy organize: bin: usr/bin lib/python3.12/site-packages: usr/lib/python3/dist-packages prime: - -usr/bin/activate* - -usr/bin/Activate.ps1 - -usr/bin/python* - -usr/bin/pip* - -pyvenv.cfg - -share - -include - -lib - -lib64 - -usr/lib/*/dist-packages/pip* - -usr/lib/*/dist-packages/setuptools* - -usr/lib/*/dist-packages/pkg_resources* drum-machine: after: [python-deps] plugin: meson source: https://github.com/revisto/drum-machine.git source-tag: 'v2.0.0' source-depth: 1 meson-parameters: - --prefix=/snap/drum-machine/current/usr - --buildtype=release build-environment: - PYTHONPATH: $CRAFT_STAGE/usr/lib/python3/dist-packages:$PYTHONPATH build-snaps: - blueprint-compiler/latest/edge parse-info: [usr/share/metainfo/io.github.revisto.drum-machine.metainfo.xml] override-build: | craftctl default sed -e '1c#!/usr/bin/env python3' -i ${CRAFT_PART_INSTALL}/snap/drum-machine/current/usr/bin/drum-machine mkdir -p $CRAFT_PART_INSTALL/meta/gui cp -r $CRAFT_PART_INSTALL/snap/drum-machine/current/usr/share/icons $CRAFT_PART_INSTALL/meta/gui/ for i in `find $CRAFT_PART_INSTALL/meta/gui/icons -name "*.svg" -o -name "*.png"`; do mv $i "`dirname $i`/snap.$CRAFT_PROJECT_NAME.`basename $i`" done for i in `find $CRAFT_PART_INSTALL/snap/drum-machine/current/usr/share/icons -name "io.github.revisto.drum-machine*.svg" -o -name "io.github.revisto.drum-machine*.png"`; do mv $i "`dirname $i`/snap.$CRAFT_PROJECT_NAME.`basename $i`" done sed -i 's/Icon=io.github.revisto.drum-machine/Icon=snap.drum-machine.io.github.revisto.drum-machine/' $CRAFT_PART_INSTALL/snap/drum-machine/current/usr/share/applications/io.github.revisto.drum-machine.desktop organize: snap/drum-machine/current: . gpu-2404: after: [drum-machine] plugin: dump source: https://github.com/canonical/gpu-snap.git override-prime: | craftctl default ${CRAFT_PART_SRC}/bin/gpu-2404-cleanup mesa-2404 prime: - -* cleanup: after: - drum-machine - gpu-2404 plugin: nil build-snaps: - gtk-common-themes - gnome-46-2404 - core24 - blueprint-compiler apps: drum-machine: command: usr/bin/drum-machine desktop: usr/share/applications/io.github.revisto.drum-machine.desktop extensions: [gnome] common-id: io.github.revisto.drum-machine environment: PYTHONPATH: $SNAP/usr/lib/python3/dist-packages:$PYTHONPATH PATH: $SNAP/ffmpeg-platform/usr/bin:$PATH LD_LIBRARY_PATH: $SNAP/ffmpeg-platform/usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR:$LD_LIBRARY_PATH plugs: - audio-playback drum-machine-2.2.0/src/000077500000000000000000000000001514070543000146525ustar00rootroot00000000000000drum-machine-2.2.0/src/__init__.py000066400000000000000000000013241514070543000167630ustar00rootroot00000000000000# __init__.py # # Copyright 2025 revisto # # 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, 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 . # # SPDX-License-Identifier: GPL-3.0-or-later drum-machine-2.2.0/src/application.py000066400000000000000000000077561514070543000175460ustar00rootroot00000000000000# application.py # # Copyright 2025 revisto # # 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, 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 . # # SPDX-License-Identifier: GPL-3.0-or-later import platform import logging from typing import Optional, Callable, List import gi from gettext import gettext as _ gi.require_version("Gtk", "4.0") gi.require_version("Adw", "1") from gi.repository import Adw, Gio, Gtk from .window import DrumMachineWindow class DrumMachineApplication(Adw.Application): def __init__(self, version: str) -> None: super().__init__( application_id="io.github.revisto.drum-machine", flags=Gio.ApplicationFlags.DEFAULT_FLAGS, ) self.version = version self.create_action("about", self.on_about_action) logging.info(f"Drum Machine {version} initialized") def do_activate(self) -> None: win = self.props.active_window if not win: logging.info("Creating new window") try: win = DrumMachineWindow(application=self) except Exception as e: logging.critical(f"Failed to create window: {e}") raise win.present() def on_about_action(self, *_args) -> None: debug_info = f"Drum Machine {self.version}\n" debug_info += f"System: {platform.system()}\n" if platform.system() == "Linux": debug_info += f"Dist: {platform.freedesktop_os_release()['PRETTY_NAME']}\n" debug_info += f"Python {platform.python_version()}\n" debug_info += ( f"GTK {Gtk.MAJOR_VERSION}.{Gtk.MINOR_VERSION}.{Gtk.MICRO_VERSION}\n" ) debug_info += "PyGObject {}.{}.{}\n".format(*gi.version_info) debug_info += ( f"Adwaita {Adw.MAJOR_VERSION}.{Adw.MINOR_VERSION}.{Adw.MICRO_VERSION}" ) about = Adw.AboutDialog( application_name=_("Drum Machine"), application_icon="io.github.revisto.drum-machine", developer_name="Revisto", version=self.version, developers=["Revisto"], copyright="© 2024–2025 Revisto", comments=_( "Drum Machine is a modern and intuitive application for creating, " "playing, and managing drum patterns." ), debug_info=debug_info, license_type=Gtk.License.GPL_3_0, translator_credits=_("translator-credits"), issue_url="https://github.com/Revisto/drum-machine/issues", website="https://apps.gnome.org/DrumMachine/", ) about.add_acknowledgement_section( _("Special thanks"), ["Sepehr Rasouli", "Tobias Bernard"] ) about.add_legal_section( _("Sounds"), _("The drum samples used in this application are from {link}.").format( link="99Sounds" ), Gtk.License.UNKNOWN, ) about.add_legal_section("Mido", None, Gtk.License.MIT_X11) about.add_legal_section("Pygame", None, Gtk.License.LGPL_2_1) about.present(self.props.active_window) def create_action( self, name: str, callback: Callable, shortcuts: Optional[List[str]] = None ) -> None: action = Gio.SimpleAction.new(name, None) action.connect("activate", callback) self.add_action(action) if shortcuts: self.set_accels_for_action(f"app.{name}", shortcuts) drum-machine-2.2.0/src/config/000077500000000000000000000000001514070543000161175ustar00rootroot00000000000000drum-machine-2.2.0/src/config/constants.py000066400000000000000000000027031514070543000205070ustar00rootroot00000000000000# config/constants.py # # Copyright 2025 revisto # # 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, 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 . # # SPDX-License-Identifier: GPL-3.0-or-later from typing import List, Set, Tuple DEFAULT_DRUM_PARTS: List[str] = [ "kick", "kick-2", "kick-3", "snare", "snare-2", "hihat", "hihat-2", "clap", "tom", "crash", ] DEFAULT_PATTERNS: List[str] = [ "Shoot", "Maybe Rock", "Boom Boom", "Night", "Slow", "Chill", ] NUM_TOGGLES: int = 16 GROUP_TOGGLE_COUNT: int = 4 DEFAULT_BPM: int = 120 DEFAULT_VOLUME: int = 100 # Audio rendering constants DEFAULT_FALLBACK_SAMPLE_SIZE: Tuple[int, int] = (1000, 2) # Progress bar constants PULSE_INTERVAL_SECONDS: float = 1.0 # Audio constants MIXER_CHANNELS: int = 32 # Supported audio file formats for input/import SUPPORTED_INPUT_AUDIO_FORMATS: Set[str] = {".wav", ".mp3", ".ogg", ".flac"} drum-machine-2.2.0/src/config/export_formats.py000066400000000000000000000051061514070543000215470ustar00rootroot00000000000000# config/export_formats.py # # Copyright 2025 revisto # # 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, 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 . # # SPDX-License-Identifier: GPL-3.0-or-later from dataclasses import dataclass from typing import Dict from gettext import gettext as _ @dataclass class ExportFormat: """Configuration for an audio export format""" ext: str pattern: str name: str display: str supports_metadata: bool class ExportFormatRegistry: """Registry for managing available export formats""" def __init__(self) -> None: self._formats = { 0: ExportFormat( ext=".mp3", pattern="*.mp3", name=_("MP3 files"), display=_("MP3"), supports_metadata=True, ), 1: ExportFormat( ext=".flac", pattern="*.flac", name=_("FLAC files"), display=_("FLAC (Lossless)"), supports_metadata=True, ), 2: ExportFormat( ext=".ogg", pattern="*.ogg", name=_("Ogg files"), display=_("Ogg Vorbis"), supports_metadata=True, ), 3: ExportFormat( ext=".wav", pattern="*.wav", name=_("WAV files"), display=_("WAV (Uncompressed)"), supports_metadata=False, ), } def get_format(self, format_id: int) -> ExportFormat: """Get format configuration by ID""" return self._formats.get(format_id, self._formats[0]) def get_all_formats(self) -> Dict[int, ExportFormat]: """Get all available formats""" return self._formats.copy() def get_format_by_extension(self, extension: str) -> ExportFormat: """Get format configuration by file extension""" for fmt in self._formats.values(): if fmt.ext == extension: return fmt return self._formats[0] drum-machine-2.2.0/src/config/meson.build000066400000000000000000000002531514070543000202610ustar00rootroot00000000000000modulesubdir = join_paths(moduledir, 'config') config_sources = [ 'constants.py', 'export_formats.py', ] install_data(config_sources, install_dir: modulesubdir) drum-machine-2.2.0/src/dialogs/000077500000000000000000000000001514070543000162745ustar00rootroot00000000000000drum-machine-2.2.0/src/dialogs/audio_export_dialog.py000066400000000000000000000262201514070543000226710ustar00rootroot00000000000000# dialogs/audio_export_dialog.py # # Copyright 2025 revisto # # 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, 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 . # # SPDX-License-Identifier: GPL-3.0-or-later import os import getpass import logging from gi.repository import Adw, Gtk, GLib, Gio from gettext import gettext as _ from ..utils.export_progress import ExportProgressHandler, ExportTask @Gtk.Template( resource_path="/io/github/revisto/drum-machine/gtk/audio-export-dialog.ui" ) class AudioExportDialog(Adw.Dialog): """Dialog for exporting audio with progress tracking""" __gtype_name__ = "AudioExportDialog" # Template children progress_bar = Gtk.Template.Child() status_overlay = Gtk.Template.Child() status_label = Gtk.Template.Child() detail_label = Gtk.Template.Child() export_button = Gtk.Template.Child() cancel_button = Gtk.Template.Child() format_row = Gtk.Template.Child() format_list = Gtk.Template.Child() repeat_row = Gtk.Template.Child() artist_row = Gtk.Template.Child() song_row = Gtk.Template.Child() cover_row = Gtk.Template.Child() cover_button = Gtk.Template.Child() warning_banner = Gtk.Template.Child() def __init__( self, parent_window, audio_export_service, drum_parts_state, bpm, suggested_filename, ): super().__init__() self.window = parent_window self.audio_export_service = audio_export_service self.drum_parts_state = drum_parts_state self.bpm = bpm self.suggested_filename = ( "new_beat" if suggested_filename is None else suggested_filename ) # Initialize components self.metadata_manager = ExportMetadata( self.artist_row, self.song_row, self.cover_row, self.cover_button ) self.progress_handler = ExportProgressHandler( self.progress_bar, self.status_overlay, self.status_label, self.detail_label ) self.export_task = ExportTask(audio_export_service, self.progress_handler) self._setup_ui() self._connect_signals() def _setup_ui(self): """Initialize the UI components""" self._populate_format_list() self._update_metadata_sensitivity() self._check_temporary_parts() def _populate_format_list(self): """Populate the format dropdown with available formats""" formats = self.audio_export_service.format_registry.get_all_formats() for format_id in sorted(formats.keys()): format_info = formats[format_id] self.format_list.append(format_info.display) def _connect_signals(self): """Connect UI signals""" self.export_button.connect("clicked", self._on_export_clicked) self.cancel_button.connect("clicked", self._on_cancel_clicked) self.cover_button.connect("clicked", self._on_cover_button_clicked) self.format_row.connect("notify::selected", self._on_format_changed) self.connect("closed", self._on_dialog_closed) def _create_file_dialog_with_format(self, selected_format): """Create file dialog with format-specific filter""" info = self.audio_export_service.format_registry.get_format(selected_format) file_filter = Gtk.FileFilter.new() file_filter.add_pattern(info.pattern) file_filter.set_name(info.name) filefilters = Gio.ListStore.new(Gtk.FileFilter) filefilters.append(file_filter) title = self.metadata_manager.get_title() initial_name = (title or self.suggested_filename) + info.ext dialog = Gtk.FileDialog.new() dialog.set_title(_("Save Audio File")) dialog.set_filters(filefilters) dialog.set_initial_name(initial_name) return dialog def _check_temporary_parts(self): """Check for temporary parts with active beats and show warning""" drum_part_manager = self.window.sound_service.drum_part_manager temporary_parts_with_beats = [] for part_id, part_state in self.drum_parts_state.items(): if not part_state: continue # Check if this part has any active beats has_active_beats = any(part_state.values()) if not has_active_beats: continue # Check if this is a temporary part (no file path) part = drum_part_manager.get_part_by_id(part_id) if part and not part.file_path: temporary_parts_with_beats.append(part.name) if temporary_parts_with_beats: # Show warning banner with concise title (HIG) count = len(temporary_parts_with_beats) if count == 1: message = _("Part “{}” is Silent").format(temporary_parts_with_beats[0]) elif count == 2: message = _("Parts “{}” and “{}” are Silent").format( temporary_parts_with_beats[0], temporary_parts_with_beats[1] ) else: message = _("{} Parts are Silent").format(count) self.warning_banner.set_title(message) self.warning_banner.set_revealed(True) else: self.warning_banner.set_revealed(False) def _update_metadata_sensitivity(self): """Update metadata fields sensitivity based on selected format""" selected_format = self.format_row.get_selected() format_info = self.audio_export_service.format_registry.get_format( selected_format ) self.metadata_manager.set_sensitivity(format_info.supports_metadata) def _on_format_changed(self, combo_row, pspec): """Handle format selection change""" self._update_metadata_sensitivity() def _on_cover_button_clicked(self, button): """Handle cover art file selection""" image_filter = Gtk.FileFilter.new() image_filter.add_pattern("*.png") image_filter.add_pattern("*.jpg") image_filter.add_pattern("*.jpeg") image_filter.set_name(_("Image files")) filefilters = Gio.ListStore.new(Gtk.FileFilter) filefilters.append(image_filter) dialog = Gtk.FileDialog.new() dialog.set_title(_("Select Cover Art")) dialog.set_filters(filefilters) dialog.open(parent=self.window, callback=self._on_cover_selected) def _on_cover_selected(self, dialog, result): """Handle cover art file selection result""" try: file = dialog.open_finish(result) if file: self.metadata_manager.set_cover_art(file.get_path()) except GLib.Error as e: logging.error(f"Failed to open cover art file: {e}") pass def _on_export_clicked(self, button): """Handle export button click""" selected_format = self.format_row.get_selected() dialog = self._create_file_dialog_with_format(selected_format) dialog.save(parent=self.window, callback=self._on_file_selected) def _on_file_selected(self, dialog, result): """Handle file selection from save dialog""" try: file = dialog.save_finish(result) if file: self._start_export(file.get_path()) except GLib.Error as e: logging.error(f"Failed to save file dialog: {e}") pass def _start_export(self, filename): """Start the export process""" repeat_count = int(self.repeat_row.get_value()) metadata = self.metadata_manager.get_metadata() self._disable_export_controls() self.export_task.start_export( self.drum_parts_state, self.bpm, filename, repeat_count, metadata, self._on_export_complete, ) def _disable_export_controls(self): """Disable export controls during export""" self.format_row.set_sensitive(False) self.repeat_row.set_sensitive(False) self.metadata_manager.set_sensitivity(False) self.export_button.set_visible(False) self.cancel_button.set_visible(True) def _on_export_complete(self, success, filename): """Handle export completion""" if success: logging.info(f"Audio export completed successfully: {filename}") self.window.show_toast( _("Audio exported to {}").format(os.path.basename(filename)), open_file=True, file_path=filename, ) else: logging.error(f"Audio export failed for: {filename}") self.window.show_toast(_("Export failed")) self.close() def _on_cancel_clicked(self, button): """Handle cancel button click""" self.export_task.cancel_export() self.window.show_toast(_("Export cancelled successfully")) self.close() def _on_dialog_closed(self, dialog): """Handle dialog close - cancel export if still running""" self.export_task.cancel_export() self.progress_handler.stop_progress_tracking() class ExportMetadata: """Manages export metadata fields""" def __init__(self, artist_row, song_row, cover_row, cover_button): self.artist_row = artist_row self.song_row = song_row self.cover_row = cover_row self.cover_button = cover_button self.cover_art_path = None self._setup_defaults() def _setup_defaults(self): """Set up default values for metadata fields""" try: system_username = getpass.getuser() self.artist_row.set_text(system_username) except Exception as e: logging.error(f"Failed to get system username for metadata: {e}") pass def get_metadata(self): """Get the current metadata as a dictionary""" return { "artist": self.artist_row.get_text().strip() or None, "title": self.get_title(), "cover_art": self.cover_art_path, } def get_title(self): """Get the song title""" return self.song_row.get_text().strip() or None def set_cover_art(self, file_path): """Set the cover art path and update UI""" self.cover_art_path = file_path if file_path: filename = os.path.basename(file_path) display_name = filename[:20] + "…" if len(filename) > 20 else filename self.cover_button.set_label(display_name) def set_sensitivity(self, sensitive: bool): """Enable or disable metadata fields""" self.artist_row.set_sensitive(sensitive) self.song_row.set_sensitive(sensitive) self.cover_row.set_sensitive(sensitive) self.cover_button.set_sensitive(sensitive) drum-machine-2.2.0/src/dialogs/meson.build000066400000000000000000000003741514070543000204420ustar00rootroot00000000000000modulesubdir = join_paths(moduledir, 'dialogs') services_sources = [ 'save_changes_dialog.py', 'audio_export_dialog.py', 'midi_mapping_dialog.py', 'reset_defaults_dialog.py', ] install_data(services_sources, install_dir: modulesubdir)drum-machine-2.2.0/src/dialogs/midi_mapping_dialog.py000066400000000000000000000166231514070543000226320ustar00rootroot00000000000000# dialogs/midi_mapping_dialog.py # # Copyright 2025 revisto # # 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, either version 3 of the License, or # (at your option) any later version. # # SPDX-License-Identifier: GPL-3.0-or-later import logging import gi gi.require_version("Gtk", "4.0") gi.require_version("Adw", "1") from gi.repository import Gtk, Adw from gettext import gettext as _ # Common GM Percussion Map (General MIDI Level 1) GM_PERCUSSION_MAP = { 35: _("Acoustic Bass Drum"), 36: _("Bass Drum 1"), 37: _("Side Stick"), 38: _("Acoustic Snare"), 39: _("Hand Clap"), 40: _("Electric Snare"), 41: _("Low Floor Tom"), 42: _("Closed Hi Hat"), 43: _("High Floor Tom"), 44: _("Pedal Hi Hat"), 45: _("Low Tom"), 46: _("Open Hi Hat"), 47: _("Low-Mid Tom"), 48: _("Hi-Mid Tom"), 49: _("Crash Cymbal 1"), 50: _("High Tom"), 51: _("Ride Cymbal 1"), 52: _("Chinese Cymbal"), 53: _("Ride Bell"), 54: _("Tambourine"), 55: _("Splash Cymbal"), 56: _("Cowbell"), 57: _("Crash Cymbal 2"), 58: _("Vibraslap"), 59: _("Ride Cymbal 2"), 60: _("Hi Bongo"), 61: _("Low Bongo"), 62: _("Mute Hi Conga"), 63: _("Open Hi Conga"), 64: _("Low Conga"), 65: _("High Timbale"), 66: _("Low Timbale"), 67: _("High Agogo"), 68: _("Low Agogo"), 69: _("Cabasa"), 70: _("Maracas"), 71: _("Short Whistle"), 72: _("Long Whistle"), 73: _("Short Guiro"), 74: _("Long Guiro"), 75: _("Claves"), 76: _("Hi Wood Block"), 77: _("Low Wood Block"), 78: _("Mute Cuica"), 79: _("Open Cuica"), 80: _("Mute Triangle"), 81: _("Open Triangle"), } class MidiMappingDialog(Adw.Dialog): def __init__(self, parent, drum_part, on_save_callback): super().__init__() self.drum_part = drum_part self.on_save_callback = on_save_callback self.set_title(_("MIDI Mapping")) self.set_content_width(450) # Toolbar View to hold HeaderBar + Content toolbar_view = Adw.ToolbarView() self.set_child(toolbar_view) # Header Bar header_bar = Adw.HeaderBar() header_bar.set_show_title(True) toolbar_view.add_top_bar(header_bar) # Content Area - Match export dialog structure with margins scrolled = Gtk.ScrolledWindow() scrolled.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC) scrolled.set_propagate_natural_height(True) content_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=24) content_box.set_margin_start(24) content_box.set_margin_end(24) scrolled.set_child(content_box) toolbar_view.set_content(scrolled) # Use PreferencesPage for nice grouping page = Adw.PreferencesPage() content_box.append(page) # Group 1: Note Assignment note_group = Adw.PreferencesGroup(title=_("Note Assignment")) note_group.set_description( _( "Assign a MIDI note for '{}'. " "This ensures correct playback when exporting." ).format(drum_part.name) ) page.add(note_group) # Action Row for Note self.note_row = Adw.ActionRow(title=_("MIDI Note")) self.note_row.set_subtitle(_("The note number to trigger")) # Spin Button for Note Number adjustment = Gtk.Adjustment( value=drum_part.midi_note_id or 36, lower=0, upper=127, step_increment=1, page_increment=12, ) self.spin_button = Gtk.SpinButton(adjustment=adjustment) self.spin_button.set_valign(Gtk.Align.CENTER) self.spin_button.connect("value-changed", self._on_value_changed) self.note_row.add_suffix(self.spin_button) note_group.add(self.note_row) # Group 2: Standard Instruments preset_group = Adw.PreferencesGroup(title=_("Standard Instruments")) preset_group.set_description( _("Select a General MIDI instrument to automatically set the note.") ) page.add(preset_group) preset_row = Adw.ActionRow(title=_("Instrument Preset")) # Dropdown for presets model = Gtk.StringList() self.note_map = [] # List of (note, string_item) # Sort by note number sorted_map = sorted(GM_PERCUSSION_MAP.items()) current_note = int(adjustment.get_value()) selected_idx = -1 idx = 0 for note, name in sorted_map: display_str = f"{note} - {name}" model.append(display_str) self.note_map.append(note) if note == current_note: selected_idx = idx idx += 1 self.dropdown = Gtk.DropDown(model=model) self.dropdown.set_enable_search(True) self.dropdown.set_valign(Gtk.Align.CENTER) self.dropdown.connect("notify::selected", self._on_preset_selected) if selected_idx != -1: self.dropdown.set_selected(selected_idx) else: self.dropdown.set_selected(Gtk.INVALID_LIST_POSITION) preset_row.add_suffix(self.dropdown) preset_group.add(preset_row) # Update subtitle of note row to match initial state self._update_gm_subtitle(int(adjustment.get_value())) # Bottom Bar for actions - single pill button (matching export dialog style) button_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=12) button_box.set_halign(Gtk.Align.CENTER) button_box.set_margin_bottom(32) save_btn = Gtk.Button(label=_("Save")) save_btn.add_css_class("pill") save_btn.add_css_class("suggested-action") save_btn.connect("clicked", self._on_save_clicked) button_box.append(save_btn) toolbar_view.add_bottom_bar(button_box) def _on_value_changed(self, button): val = int(button.get_value()) self._update_gm_subtitle(val) # Update dropdown if matches found = False try: if val in self.note_map: idx = self.note_map.index(val) if self.dropdown.get_selected() != idx: self.dropdown.set_selected(idx) found = True except ValueError as e: # ValueError is expected if val is not in self.note_map; # This is normal behavior for custom notes not in GM percussion map logging.debug(f"MIDI note {val} not in GM percussion map: {e}") pass if not found: self.dropdown.set_selected(Gtk.INVALID_LIST_POSITION) def _on_preset_selected(self, dropdown, pspec): selected_idx = dropdown.get_selected() if selected_idx != Gtk.INVALID_LIST_POSITION and selected_idx < len( self.note_map ): note = self.note_map[selected_idx] if int(self.spin_button.get_value()) != note: self.spin_button.set_value(note) def _update_gm_subtitle(self, note): name = GM_PERCUSSION_MAP.get(note) if name: self.note_row.set_subtitle(name) else: self.note_row.set_subtitle(_("Custom Note")) def _on_save_clicked(self, button): note = int(self.spin_button.get_value()) self.on_save_callback(self.drum_part.id, note) self.close() drum-machine-2.2.0/src/dialogs/reset_defaults_dialog.py000066400000000000000000000026021514070543000231760ustar00rootroot00000000000000# dialogs/reset_defaults_dialog.py # # Copyright 2025 revisto # # 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, 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 . # # SPDX-License-Identifier: GPL-3.0-or-later from gi.repository import Adw, Gtk @Gtk.Template( resource_path="/io/github/revisto/drum-machine/gtk/reset-defaults-dialog.ui" ) class ResetDefaultsDialog(Adw.AlertDialog): __gtype_name__ = "ResetDefaultsDialog" def __init__(self, window, on_reset_callback=None): super().__init__() self._on_reset_callback = on_reset_callback self.present(window) @Gtk.Template.Callback() def _on_reset(self, _dialog, _response): if callable(self._on_reset_callback): self._on_reset_callback() self.close() @Gtk.Template.Callback() def _on_cancel(self, _dialog, _response): self.close() drum-machine-2.2.0/src/dialogs/save_changes_dialog.py000066400000000000000000000032001514070543000226060ustar00rootroot00000000000000# dialogs/save_changes_dialog.py # # Copyright 2025 revisto # # 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, 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 . # # SPDX-License-Identifier: GPL-3.0-or-later from gi.repository import Adw, Gtk @Gtk.Template( resource_path="/io/github/revisto/drum-machine/gtk/save-changes-dialog.ui" ) class SaveChangesDialog(Adw.AlertDialog): __gtype_name__ = "SaveChangesDialog" def __init__(self, window, on_save_callback=None, on_discard_callback=None): super().__init__() self._on_save_callback = on_save_callback self._on_discard_callback = on_discard_callback self.present(window) @Gtk.Template.Callback() def _on_save(self, _dialog, _response): if callable(self._on_save_callback): self._on_save_callback() self.close() @Gtk.Template.Callback() def _on_discard(self, _dialog, _response): if callable(self._on_discard_callback): self._on_discard_callback() self.close() @Gtk.Template.Callback() def _on_cancel(self, _dialog, _response): self.close() drum-machine-2.2.0/src/drum-machine.gresource.xml000066400000000000000000000014451514070543000217460ustar00rootroot00000000000000 style.css style-dark.css window.ui gtk/help-overlay.ui gtk/save-changes-dialog.ui gtk/audio-export-dialog.ui gtk/reset-defaults-dialog.ui ../data/icons/hicolor/scalable/actions/share-symbolic.svg drum-machine-2.2.0/src/drum-machine.in000077500000000000000000000024701514070543000175610ustar00rootroot00000000000000#!@PYTHON@ # drum-machine.in # # Copyright 2024 rev # # 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, 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 . # # SPDX-License-Identifier: GPL-3.0-or-later import os import sys import signal import locale import gettext VERSION = '@VERSION@' pkgdatadir = '@pkgdatadir@' localedir = '@localedir@' sys.path.insert(1, pkgdatadir) signal.signal(signal.SIGINT, signal.SIG_DFL) locale.bindtextdomain('drum-machine', localedir) locale.textdomain('drum-machine') gettext.install('drum-machine', localedir) if __name__ == '__main__': import gi from gi.repository import Gio resource = Gio.Resource.load(os.path.join(pkgdatadir, 'drum-machine.gresource')) resource._register() from drum_machine import main sys.exit(main.main(VERSION)) drum-machine-2.2.0/src/gtk/000077500000000000000000000000001514070543000154375ustar00rootroot00000000000000drum-machine-2.2.0/src/gtk/audio-export-dialog.blp000066400000000000000000000056341514070543000220230ustar00rootroot00000000000000using Gtk 4.0; using Adw 1; template $AudioExportDialog: Adw.Dialog { content-width: 450; title: _("Export Audio"); child: Adw.ToolbarView toolbar_view { [top] Adw.HeaderBar header_bar { show-title: true; } [top] Adw.Banner warning_banner { revealed: false; } content: Overlay main_overlay { [overlay] ProgressBar progress_bar { valign: start; visible: false; styles [ "osd", ] } ScrolledWindow { hscrollbar-policy: never; propagate-natural-height: true; Box content_box { orientation: vertical; spacing: 24; margin-top: 24; margin-bottom: 24; margin-start: 24; margin-end: 24; Adw.PreferencesGroup export_group { Adw.ComboRow format_row { title: _("Audio Format"); model: StringList format_list {}; } Adw.SpinRow repeat_row { title: _("Repeat Count"); subtitle: _("How many times to repeat the pattern"); adjustment: Adjustment { lower: 1; upper: 100; value: 5; step-increment: 1; page-increment: 5; }; } } Adw.PreferencesGroup metadata_group { title: _("Metadata"); Adw.EntryRow artist_row { title: _("Artist Name"); show-apply-button: false; } Adw.EntryRow song_row { title: _("Song Name"); show-apply-button: false; } Adw.ActionRow cover_row { title: _("Cover Art"); activatable-widget: cover_button; Button cover_button { label: _("Choose File…"); valign: center; } } } } } }; [bottom] Box button_box { orientation: vertical; halign: center; margin-start: 24; margin-end: 24; margin-top: 16; margin-bottom: 32; spacing: 12; Button export_button { label: _("Export Audio"); styles [ "suggested-action", "pill", ] } Button cancel_button { label: _("Cancel Export"); visible: false; styles [ "destructive-action", "pill", ] } Box status_overlay { orientation: vertical; halign: center; spacing: 6; visible: false; Label status_label { halign: center; label: "Exporting…"; styles [ "heading", ] } Label detail_label { halign: center; label: "Processing…"; styles [ "caption", ] } } } }; } drum-machine-2.2.0/src/gtk/help-overlay.blp000066400000000000000000000056361514070543000205570ustar00rootroot00000000000000using Gtk 4.0; ShortcutsWindow help_overlay { modal: true; ShortcutsSection { section-name: "shortcuts"; max-height: 12; ShortcutsGroup { title: C_("shortcut window", "General"); ShortcutsShortcut { title: C_("shortcut window", "Show Shortcuts"); action-name: "win.show-help-overlay"; } ShortcutsShortcut { title: C_("shortcut window", "Quit"); action-name: "win.quit"; accelerator: "q"; } } ShortcutsGroup { title: C_("shortcut window", "Playback Controls"); ShortcutsShortcut { title: C_("shortcut window", "Play/Pause"); action-name: "win.play_pause"; accelerator: "space"; } ShortcutsShortcut { title: C_("shortcut window", "Clear All"); action-name: "win.clear_toggles"; accelerator: "Delete"; } } ShortcutsGroup { title: C_("shortcut window", "BPM & Volume Controls"); ShortcutsShortcut { title: C_("shortcut window", "Increase BPM"); action-name: "win.increase_bpm"; accelerator: "plus equal"; } ShortcutsShortcut { title: C_("shortcut window", "Decrease BPM"); action-name: "win.decrease_bpm"; accelerator: "minus"; } ShortcutsShortcut { title: C_("shortcut window", "Increase Volume"); action-name: "win.increase_volume"; accelerator: "Up"; } ShortcutsShortcut { title: C_("shortcut window", "Decrease Volume"); action-name: "win.decrease_volume"; accelerator: "Down"; } ShortcutsShortcut { title: C_("shortcut window", "Mute"); action-name: "win.mute"; accelerator: "m"; } } ShortcutsGroup { title: C_("shortcut window", "Pattern Management"); ShortcutsShortcut { title: C_("shortcut window", "Load Pattern"); action-name: "win.load_pattern"; accelerator: "o"; } ShortcutsShortcut { title: C_("shortcut window", "Save Pattern"); action-name: "win.save_pattern"; accelerator: "s"; } ShortcutsShortcut { title: C_("shortcut window", "Export Audio"); action-name: "win.export_audio"; accelerator: "e"; } } ShortcutsGroup { title: C_("shortcut window", "Navigation"); ShortcutsShortcut { title: C_("shortcut window", "Go to Instrument"); action-name: "win.go_to_instrument"; accelerator: "i"; } ShortcutsShortcut { title: C_("shortcut window", "Previous Page"); action-name: "win.previous_page"; accelerator: "Page_Up"; } ShortcutsShortcut { title: C_("shortcut window", "Next Page"); action-name: "win.next_page"; accelerator: "Page_Down"; } } } } drum-machine-2.2.0/src/gtk/reset-defaults-dialog.blp000066400000000000000000000010441514070543000223210ustar00rootroot00000000000000using Gtk 4.0; using Adw 1; template $ResetDefaultsDialog: Adw.AlertDialog { heading: _("Reset to Defaults?"); body: _("This will clear the current pattern and restore all samples, BPM, and volume to their default values. This action cannot be undone."); close-response: "cancel"; default-response: "cancel"; response::reset => $_on_reset(); response::cancel => $_on_cancel(); responses [ /* Translators: Cancel the operation */cancel: _("_Cancel"), /* Translators: Reset to defaults */reset: _("_Reset") destructive, ] } drum-machine-2.2.0/src/gtk/save-changes-dialog.blp000066400000000000000000000011511514070543000217350ustar00rootroot00000000000000using Gtk 4.0; using Adw 1; template $SaveChangesDialog: Adw.AlertDialog { heading: _("Save Changes?"); body: _("Current pattern contains unsaved changes. Changes which are not saved will be permanently lost."); close-response: "cancel"; default-response: "save"; response::save => $_on_save(); response::discard => $_on_discard(); response::cancel => $_on_cancel(); responses [ /* Translators: Cancel the operation */cancel: _("_Cancel"), /* Translators: Discard all changes */discard: _("_Discard") destructive, /* Translators: Save current changes */save: _("_Save") suggested, ] } drum-machine-2.2.0/src/handlers/000077500000000000000000000000001514070543000164525ustar00rootroot00000000000000drum-machine-2.2.0/src/handlers/drag_drop_handler.py000066400000000000000000000405441514070543000224710ustar00rootroot00000000000000# handlers/drag_drop_handler.py # # Copyright 2025 revisto # # 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, 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 . # # SPDX-License-Identifier: GPL-3.0-or-later from pathlib import Path from typing import Optional, List, Tuple import logging from gi.repository import Gtk, Gdk, Gio, GObject from gettext import gettext as _ from ..config.constants import SUPPORTED_INPUT_AUDIO_FORMATS from ..utils.name_utils import extract_name_from_path class DragDropHandler: def __init__(self, window) -> None: self.window = window self.new_drum_placeholder: Optional[Gtk.Widget] = None self._dragged_drum_id: Optional[str] = None def setup_drag_drop( self, target_widget: Optional[Gtk.Widget] = None ) -> Gtk.DropTarget: if target_widget is None: target_widget = self.window # Create drop target for file drops on window (for general drag detection) drop_target = Gtk.DropTarget.new(Gdk.FileList, Gdk.DragAction.COPY) drop_target.connect("drop", self._on_window_drop) drop_target.connect("enter", self._on_drag_enter) drop_target.connect("leave", self._on_drag_leave) target_widget.add_controller(drop_target) return drop_target def setup_button_drop_target( self, button: Gtk.Button, drum_id: Optional[str] = None ) -> None: """Setup drop target on individual drum button for replacement""" drop_target = Gtk.DropTarget.new(Gdk.FileList, Gdk.DragAction.COPY) drop_target.connect("drop", self._on_button_drop, drum_id) drop_target.connect("enter", self._on_button_drag_enter, button) drop_target.connect("leave", self._on_button_drag_leave, button) button.add_controller(drop_target) def setup_button_reorder_drag_source( self, button: Gtk.Button, drum_id: str ) -> None: """Setup drag source on drum button for reordering. Args: button: The drum part button that can be dragged drum_id: The ID of the drum part associated with this button """ drag_source = Gtk.DragSource() drag_source.set_actions(Gdk.DragAction.MOVE) drag_source.connect("prepare", self._on_reorder_drag_prepare, drum_id) drag_source.connect("drag-begin", self._on_reorder_drag_begin, drum_id, button) drag_source.connect("drag-end", self._on_reorder_drag_end, button) button.add_controller(drag_source) def setup_column_reorder_drop_target(self, column_widget: Gtk.Box) -> None: """Setup drop target on the entire drum parts column for reordering""" drop_target = Gtk.DropTarget.new(GObject.TYPE_STRING, Gdk.DragAction.MOVE) drop_target.connect("drop", self._on_column_reorder_drop) drop_target.connect("motion", self._on_column_reorder_motion) drop_target.connect("leave", self._on_column_reorder_leave) column_widget.add_controller(drop_target) def _on_reorder_drag_prepare( self, drag_source: Gtk.DragSource, x: float, y: float, drum_id: str, ) -> Gdk.ContentProvider: """Prepare data for drag""" self._dragged_drum_id = drum_id content = Gdk.ContentProvider.new_for_value(drum_id) return content def _on_reorder_drag_begin( self, drag_source: Gtk.DragSource, drag: Gdk.Drag, drum_id: str, button: Gtk.Button, ) -> None: """Handle drag begin for reordering""" button.add_css_class("drag-source-active") icon = Gtk.DragIcon.get_for_drag(drag) label = Gtk.Label(label=button.get_label()) icon.set_child(label) def _on_reorder_drag_end( self, drag_source: Gtk.DragSource, drag: Gdk.Drag, delete_data: bool, button: Gtk.Button, ) -> None: """Handle drag end""" button.remove_css_class("drag-source-active") self._dragged_drum_id = None self._clear_all_insertion_indicators() def _get_widget_index(self, column: Gtk.Box, widget: Gtk.Widget) -> int: """Get the index of a widget within its parent column""" child = column.get_first_child() index = 0 while child: if child == widget: return index index += 1 child = child.get_next_sibling() return -1 def _get_insertion_index_and_widget( self, column: Gtk.Box, y: float ) -> Tuple[int, Optional[Gtk.Widget]]: """Calculate insertion index based on y position in column. Returns (index, widget_to_show_line_on) or (index, None) for end.""" if not column: return 0, None child = column.get_first_child() index = 0 while child: child_y = child.get_allocation().y child_height = child.get_height() child_center = child_y + child_height / 2 if y < child_center: return index, child index += 1 child = child.get_next_sibling() last_child = column.get_last_child() return index, last_child def _on_column_reorder_motion( self, drop_target: Gtk.DropTarget, x: float, y: float ) -> Gdk.DragAction: """Handle drag motion over column - show insertion line""" if not self._dragged_drum_id: return Gdk.DragAction.MOVE self._clear_all_insertion_indicators() drum_parts_column = self.window.drum_grid_builder.drum_parts_column insert_index, widget = self._get_insertion_index_and_widget( drum_parts_column, y ) if widget: widget_index = self._get_widget_index(drum_parts_column, widget) if insert_index > widget_index: widget.add_css_class("insert-below") else: widget.add_css_class("insert-above") return Gdk.DragAction.MOVE def _on_column_reorder_leave(self, drop_target: Gtk.DropTarget) -> None: """Handle drag leave from column""" self._clear_all_insertion_indicators() def _clear_all_insertion_indicators(self) -> None: """Clear all insertion indicators from drum parts column""" drum_parts_column = self.window.drum_grid_builder.drum_parts_column if not drum_parts_column: return child = drum_parts_column.get_first_child() while child: child.remove_css_class("insert-above") child.remove_css_class("insert-below") child = child.get_next_sibling() def _on_column_reorder_drop( self, drop_target: Gtk.DropTarget, value: str, x: float, y: float ) -> bool: """Handle drop for reordering drum parts""" source_drum_id = value self._clear_all_insertion_indicators() if not source_drum_id: return False drum_part_manager = self.window.sound_service.drum_part_manager source_index = drum_part_manager.get_part_index(source_drum_id) if source_index == -1: return False drum_parts_column = self.window.drum_grid_builder.drum_parts_column target_index, _ = self._get_insertion_index_and_widget(drum_parts_column, y) if source_index < target_index: target_index -= 1 if source_index == target_index: return False if drum_part_manager.reorder_part(source_drum_id, target_index): self.window.drum_grid_builder.rebuild_drum_parts_column() self.window.drum_grid_builder.rebuild_carousel() return True return False def _on_drag_enter( self, drop_target: Gtk.DropTarget, x: float, y: float ) -> Gdk.DragAction: self.window.add_css_class("drag-hover") self.new_drum_placeholder = ( self.window.drum_grid_builder.create_new_drum_placeholder() ) return Gdk.DragAction.COPY def _on_button_drag_enter( self, drop_target: Gtk.DropTarget, x: float, y: float, button: Gtk.Button ) -> Gdk.DragAction: """Handle drag enter on drum button - highlight for replacement""" button.add_css_class("drag-over-replace") return Gdk.DragAction.COPY def _on_button_drag_leave( self, drop_target: Gtk.DropTarget, button: Gtk.Button ) -> None: """Handle drag leave on drum button - remove highlight""" button.remove_css_class("drag-over-replace") def _on_drag_leave(self, drop_target: Gtk.DropTarget) -> None: self._clear_drag_feedback() def _on_window_drop( self, drop_target: Gtk.DropTarget, value: Gdk.FileList, x: float, y: float ) -> bool: """Handle drop on window - add new drum(s)""" self._clear_drag_feedback() files_list = value.get_files() files = list(files_list) return self.handle_multiple_files_drop(files, None) def _on_button_drop( self, drop_target: Gtk.DropTarget, value: Gdk.FileList, x: float, y: float, drum_id: Optional[str], ) -> bool: """Handle drop on drum button - replace drum or add multiple""" files_list = value.get_files() files = list(files_list) return self.handle_multiple_files_drop(files, drum_id) def handle_replacement_file_selected(self, file_path: str, drum_id: str) -> bool: """Handle replacement file selected from file chooser Args: file_path: Path to the selected file drum_id: ID of the drum part to replace """ if not file_path: return False path = Path(file_path) # Validate file if not self._validate_file_format(path): return False if not self._validate_file_access(path): return False # Extract name and replace name = extract_name_from_path(path) result = self.window.replace_drum_part(drum_id, str(path), name) if result: self.window.show_toast(_("Sound replaced")) self.window.save_changes_service.mark_unsaved_changes(True) else: self.window.show_toast(_("Failed to replace sound")) return result def _validate_file_format(self, path: Path) -> bool: """Validate file format is supported""" if path.suffix.lower() not in SUPPORTED_INPUT_AUDIO_FORMATS: logging.warning( f"Unsupported file format attempted: {path.suffix} for {path.name}" ) self.window.show_toast(_("Not a supported audio file")) return False return True def _validate_file_access(self, path: Path) -> bool: """Validate file exists, is accessible, and reasonable size""" if not path.exists(): logging.error(f"Dropped file not found: {path}") self.window.show_toast(_("File not found")) return False if not path.is_file(): logging.warning(f"Dropped item is not a file: {path}") self.window.show_toast(_("Selected item is not a file")) return False file_size_mb = path.stat().st_size / (1024 * 1024) if file_size_mb > 50: logging.warning(f"File too large: {file_size_mb:.1f}MB - {path.name}") self.window.show_toast( _("File too large: {:.1f}MB (max 50MB)").format(file_size_mb) ) return False return True def handle_multiple_files_drop( self, files: List[Gio.File], drum_id_to_replace: Optional[str] ) -> bool: """Handle files dropped at once""" if not files: return False valid_files: List[Path] = [] skipped_count = 0 # Filter and validate all files first for file_obj in files: file_path = file_obj.get_path() if not file_path: skipped_count += 1 continue path = Path(file_path) if self._validate_file_format(path) and self._validate_file_access(path): valid_files.append(path) else: skipped_count += 1 if not valid_files: self.window.show_toast(_("No valid audio files found")) return False return self._handle_files(valid_files, skipped_count, drum_id_to_replace) def _handle_files( self, valid_files: List[Path], skipped_count: int, drum_id_to_replace: Optional[str], ) -> bool: """Handle files - replacement and additions""" success_count = 0 replacement_done = False successful_additions: List[str] = [] # Process all files for i, path in enumerate(valid_files): try: name = extract_name_from_path(path) if i == 0 and drum_id_to_replace: # Replace first file and show replacement toast if self.window.replace_drum_part( drum_id_to_replace, str(path), name ): replacement_done = True success_count += 1 else: # Add files # show individual toast for single file, suppress for multiple show_toast = len(valid_files) == 1 and not drum_id_to_replace if self.window.add_new_drum_part( str(path), name, show_success_toast=show_toast ): success_count += 1 if not show_toast: # Track additions for summary successful_additions.append(name) except Exception as e: skipped_count += 1 self.window.show_toast(_("Error processing file: {}").format(str(e))) if len(valid_files) > 1: self._show_files_notifications( success_count, skipped_count, replacement_done, successful_additions ) return success_count > 0 def _show_files_notifications( self, success_count: int, skipped_count: int, replacement_done: bool, successful_additions: List[str], ) -> None: """Show notifications for file operations""" if replacement_done: # If replacement occurred, don't count it in additions additions = success_count - 1 else: additions = success_count # Show summary for additions only (replacement already showed toast) if additions > 0: if additions == 1 and successful_additions: # Show individual toast for single addition like normal self.window.show_added_toast(successful_additions[0]) elif skipped_count > 0: if additions == 1: self.window.show_toast( _("Added {} drum part, {} files skipped").format( additions, skipped_count ) ) else: self.window.show_toast( _("Added {} drum parts, {} files skipped").format( additions, skipped_count ) ) else: self.window.show_toast(_("Added {} drum parts").format(additions)) elif skipped_count > 0 and not replacement_done: # Only show skipped message if no replacement happened self.window.show_toast(_("{} files skipped").format(skipped_count)) def _clear_drag_feedback(self) -> None: """Clear all drag feedback visuals""" self.window.remove_css_class("drag-hover") # Remove placeholder if self.new_drum_placeholder: self.window.drum_grid_builder.remove_new_drum_placeholder( self.new_drum_placeholder ) self.new_drum_placeholder = None drum-machine-2.2.0/src/handlers/file_dialog_handler.py000066400000000000000000000243601514070543000227640ustar00rootroot00000000000000# handlers/file_dialog_handler.py # # Copyright 2025 revisto # # 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, 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 . # # SPDX-License-Identifier: GPL-3.0-or-later import os import logging import gi gi.require_version("Gtk", "4.0") gi.require_version("Gio", "2.0") gi.require_version("Adw", "1") from gi.repository import Gtk, Gio, GLib from gettext import gettext as _ from ..config.constants import DEFAULT_PATTERNS, SUPPORTED_INPUT_AUDIO_FORMATS from ..dialogs.audio_export_dialog import AudioExportDialog class FileDialogHandler: """Handles file dialogs and pattern management""" def __init__(self, window): self.window = window self.filename = None def setup_pattern_menu(self): """Setup the pattern menu with default patterns""" menu = Gio.Menu.new() section = Gio.Menu.new() for pattern in DEFAULT_PATTERNS: item = Gio.MenuItem.new(pattern, "win.load-pattern") item.set_action_and_target_value( "win.load-pattern", GLib.Variant.new_string(pattern) ) section.append_item(item) menu.append_section(_("Default Patterns"), section) pattern_action = Gio.SimpleAction.new("load-pattern", GLib.VariantType.new("s")) pattern_action.connect("activate", self.on_pattern_selected) self.window.add_action(pattern_action) self.window.file_pattern_button.set_menu_model(menu) def handle_open_file(self): """Handle opening a file with unsaved changes check""" if self.window.save_changes_service.has_unsaved_changes(): self.window.save_changes_service.prompt_save_changes( on_save=self._save_and_open_file, on_discard=self._open_file_directly ) else: self._open_file_directly() def handle_save_pattern(self): """Handle saving a pattern""" self.show_save_dialog() def handle_export_audio(self): """Handle audio export""" # Show export dialog export_dialog = AudioExportDialog( self.window, self.window.audio_export_service, self.window.drum_machine_service.drum_parts_state, self.window.drum_machine_service.bpm, self.filename, ) export_dialog.present(self.window) def _save_and_open_file(self): self.show_save_dialog(self._open_file_directly) def _open_file_directly(self): """Show file open dialog""" filefilter = Gtk.FileFilter.new() filefilter.add_pattern("*.mid") filefilter.set_name(_("MIDI files")) filefilters = Gio.ListStore.new(Gtk.FileFilter) filefilters.append(filefilter) dialog = Gtk.FileDialog.new() dialog.set_title(_("Open MIDI File")) dialog.set_filters(filefilters) dialog.set_modal(True) dialog.open(parent=self.window, callback=self._handle_file_response) def _handle_file_response(self, dialog, response): """Handle file dialog response""" try: file = dialog.open_finish(response) if file: file_path = file.get_path() # Load the pattern data into the service self.window.drum_machine_service.load_pattern(file_path) # Update the UI to reflect the new pattern structure self.window.drum_machine_service.update_total_beats() self.window.drum_grid_builder.reset_carousel_pages() self.window.ui_helper.load_pattern_into_ui( self.window.drum_machine_service.drum_parts_state ) self.filename = self._get_filename_without_extension(file) self.window.update_export_button_sensitivity() self.window.save_changes_service.mark_unsaved_changes(False) except GLib.Error as e: logging.debug(f"File dialog cancelled or failed: {e}") return except Exception as e: logging.error(f"Failed to open pattern file: {e}") self.window.show_toast(_("Failed to open file")) def on_pattern_selected(self, action, parameter): """Handle pattern selection from menu""" if self.window.save_changes_service.has_unsaved_changes(): self.window.save_changes_service.prompt_save_changes( on_save=lambda: self._save_and_open_pattern(parameter), on_discard=lambda: self._open_pattern_directly(parameter), ) else: self._open_pattern_directly(parameter) def _save_and_open_pattern(self, parameter): self.show_save_dialog(lambda: self._open_pattern_directly(parameter)) def _open_pattern_directly(self, parameter): """Load a pattern directly""" pattern_name = parameter.get_string() pattern_dir = os.path.join( os.path.dirname(__file__), "..", "..", "data", "patterns" ) file_path = os.path.join(pattern_dir, f"{pattern_name}.mid") try: # Load the pattern data into the service self.window.drum_machine_service.load_pattern(file_path) # Update the UI to reflect the new pattern structure self.window.drum_machine_service.update_total_beats() self.window.drum_grid_builder.reset_carousel_pages() self.window.ui_helper.load_pattern_into_ui( self.window.drum_machine_service.drum_parts_state ) self.filename = None self.window.update_export_button_sensitivity() self.window.save_changes_service.mark_unsaved_changes(False) except Exception as e: logging.error(f"Failed to load default pattern '{pattern_name}': {e}") self.window.show_toast(_("Failed to load pattern")) def show_save_dialog(self, after_save_callback=None): """Show save file dialog""" filefilter = Gtk.FileFilter.new() filefilter.add_pattern("*.mid") filefilter.set_name(_("MIDI files")) filefilters = Gio.ListStore.new(Gtk.FileFilter) filefilters.append(filefilter) initial_name = f"{self.filename or 'new_sequence'}.mid" dialog = Gtk.FileDialog.new() dialog.set_title(_("Save Sequence")) dialog.set_filters(filefilters) dialog.set_modal(True) dialog.set_initial_name(initial_name) def save_callback(dialog, result): try: file = dialog.save_finish(result) if file: file_path = file.get_path() if not file_path.endswith(".mid"): file_path += ".mid" self.window.drum_machine_service.save_pattern(file_path) self.window.save_changes_service.mark_unsaved_changes(False) self.filename = self._get_filename_without_extension(file) if after_save_callback: after_save_callback() except GLib.Error as e: logging.debug(f"Save dialog cancelled or failed: {e}") return dialog.save(parent=self.window, callback=save_callback) def handle_add_samples(self): """Handle adding multiple audio samples via file dialog""" self.open_audio_file_chooser( _("Add Audio Samples"), self._handle_samples_response_callback, multiple=True, ) def _handle_samples_response_callback(self, files, *args): """Handle multiple audio files selection response""" if files and len(files) > 0: # Use existing multiple files handler self.window.drag_drop_handler.handle_multiple_files_drop(files, None) def open_audio_file_chooser(self, title, callback, *args, multiple=False): """Open a file chooser for audio files Args: title (str): Dialog title callback (callable): Function to call with selected file(s) *args: Additional arguments to pass to callback multiple (bool): Whether to allow multiple file selection """ # Create file filter for supported audio formats audio_filter = Gtk.FileFilter.new() audio_filter.set_name(_("Audio files")) # Add supported formats for fmt in SUPPORTED_INPUT_AUDIO_FORMATS: audio_filter.add_pattern(f"*{fmt}") filefilters = Gio.ListStore.new(Gtk.FileFilter) filefilters.append(audio_filter) dialog = Gtk.FileDialog.new() dialog.set_title(title) dialog.set_filters(filefilters) dialog.set_modal(True) def internal_callback(dialog, result): try: if multiple: files = dialog.open_multiple_finish(result) if files and files.get_n_items() > 0: # Convert to list of Gio.File objects file_list = [ files.get_item(i) for i in range(files.get_n_items()) ] callback(file_list, *args) else: file = dialog.open_finish(result) if file: callback(file.get_path(), *args) except GLib.Error as e: logging.debug(f"File dialog cancelled or failed: {e}") return if multiple: dialog.open_multiple(parent=self.window, callback=internal_callback) else: dialog.open(parent=self.window, callback=internal_callback) def _get_filename_without_extension(self, file): """Extract filename without extension from Gio.File""" base_name = file.get_basename() return os.path.splitext(base_name)[0] drum-machine-2.2.0/src/handlers/meson.build000066400000000000000000000003271514070543000206160ustar00rootroot00000000000000modulesubdir = join_paths(moduledir, 'handlers') handlers_sources = [ 'drag_drop_handler.py', 'file_dialog_handler.py', 'window_actions.py', ] install_data(handlers_sources, install_dir: modulesubdir) drum-machine-2.2.0/src/handlers/window_actions.py000066400000000000000000000207251514070543000220610ustar00rootroot00000000000000# handlers/window_actions.py # # Copyright 2025 revisto # # 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, 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 . # # SPDX-License-Identifier: GPL-3.0-or-later import logging import gi from typing import Optional, List, Callable gi.require_version("Gtk", "4.0") gi.require_version("Gio", "2.0") gi.require_version("Adw", "1") from gi.repository import Gio from ..dialogs.reset_defaults_dialog import ResetDefaultsDialog class WindowActionHandler: """Handles window-level actions and keyboard shortcuts""" def __init__(self, window) -> None: self.window = window def setup_actions(self) -> None: """Setup all window actions and keyboard shortcuts""" actions = [ ("open_menu", self.on_open_menu_action, ["F10"]), ("show-help-overlay", self.on_show_help_overlay, ["question"]), ("play_pause", self.handle_play_pause_action, ["space"]), ("clear_toggles", self.handle_clear_action, ["Delete"]), ("increase_bpm", self.increase_bpm_action, ["plus", "equal"]), ("decrease_bpm", self.decrease_bpm_action, ["minus"]), ("increase_volume", self.increase_volume_action, ["Up"]), ("decrease_volume", self.decrease_volume_action, ["Down"]), ("load_pattern", self.on_open_file_action, ["o"]), ("save_pattern", self.on_save_pattern_action, ["s"]), ("export_audio", self.on_export_audio_action, ["e"]), ("add_samples", self.on_add_samples_action, ["a"]), ("reset_to_defaults", self.on_reset_to_defaults_action, []), ("quit", self.on_quit_action, ["q"]), ("close_window", self.on_quit_action, ["w"]), ("go_to_instrument", self.handle_go_to_instrument_action, ["i"]), ("previous_page", self.handle_previous_page_action, ["Page_Up"]), ("next_page", self.handle_next_page_action, ["Page_Down"]), ("mute", self.handle_mute, ["m"]), ] for action_name, callback, shortcuts in actions: self._create_action(action_name, callback, shortcuts) def _create_action( self, name: str, callback: Callable, shortcuts: Optional[List[str]] = None ) -> None: """Create and register an action with optional keyboard shortcuts""" action = Gio.SimpleAction.new(name, None) action.connect("activate", callback) self.window.add_action(action) if shortcuts: self.window.application.set_accels_for_action(f"win.{name}", shortcuts) # Action handlers def on_open_menu_action( self, action: Gio.SimpleAction, param: Optional[object] ) -> None: self.window.menu_button.activate() def on_show_help_overlay( self, action: Gio.SimpleAction, param: Optional[object] ) -> None: self.window.get_help_overlay().present() def handle_play_pause_action( self, action: Gio.SimpleAction, param: Optional[object] ) -> None: self.window.handle_play_pause(self.window.play_pause_button) def handle_clear_action( self, action: Gio.SimpleAction, param: Optional[object] ) -> None: self.window.handle_clear(self.window.clear_button) def increase_bpm_action( self, action: Gio.SimpleAction, param: Optional[object] ) -> None: current_bpm = self.window.bpm_spin_button.get_value() self.window.bpm_spin_button.set_value(current_bpm + 1) def decrease_bpm_action( self, action: Gio.SimpleAction, param: Optional[object] ) -> None: current_bpm = self.window.bpm_spin_button.get_value() self.window.bpm_spin_button.set_value(current_bpm - 1) def increase_volume_action( self, action: Gio.SimpleAction, param: Optional[object] ) -> None: current_volume = self.window.volume_button.get_value() self.window.volume_button.set_value(min(current_volume + 5, 100)) def decrease_volume_action( self, action: Gio.SimpleAction, param: Optional[object] ) -> None: current_volume = self.window.volume_button.get_value() self.window.volume_button.set_value(max(current_volume - 5, 0)) def on_open_file_action( self, action: Gio.SimpleAction, param: Optional[object] ) -> None: self.window._on_open_file_clicked(self.window.file_pattern_button) def on_save_pattern_action( self, action: Gio.SimpleAction, param: Optional[object] ) -> None: self.window._on_save_pattern_clicked() def on_export_audio_action( self, action: Gio.SimpleAction, param: Optional[object] ) -> None: self.window._on_export_audio_clicked(self.window.export_audio_button) def on_quit_action( self, action: Optional[Gio.SimpleAction], param: Optional[object] ) -> None: if self.window.save_changes_service.has_unsaved_changes(): self.window.save_changes_service.prompt_save_changes( on_save=self.window._save_and_close, on_discard=self.window.cleanup_and_destroy, ) else: self.window.cleanup_and_destroy() def handle_go_to_instrument_action( self, action: Gio.SimpleAction, param: Optional[object] ) -> None: """Go to the currently focused instrument button.""" if hasattr(self.window, "carousel"): # Find which drum part is currently focused focused_widget = self.window.get_focus() if focused_widget: widget_name = focused_widget.get_name() if widget_name and "_toggle_" in widget_name: drum_part = widget_name.split("_toggle_")[0] try: instrument_button = getattr( self.window, f"{drum_part}_instrument_button" ) instrument_button.grab_focus() except AttributeError as e: logging.debug( f"Could not find instrument button for {drum_part}: {e}" ) pass def handle_previous_page_action( self, action: Gio.SimpleAction, param: Optional[object] ) -> None: """Go to the previous page.""" if hasattr(self.window, "carousel"): carousel = self.window.carousel current_page = carousel.get_position() if current_page > 0: carousel.scroll_to(carousel.get_nth_page(current_page - 1), True) def handle_next_page_action( self, action: Gio.SimpleAction, param: Optional[object] ) -> None: """Go to the next page.""" if hasattr(self.window, "carousel"): carousel = self.window.carousel current_page = carousel.get_position() n_pages = carousel.get_n_pages() if current_page < n_pages - 1: carousel.scroll_to(carousel.get_nth_page(current_page + 1), True) def handle_mute(self, action: Gio.SimpleAction, param: Optional[object]) -> None: current_volume = self.window.volume_button.get_value() last_volume = self.window.drum_machine_service.last_volume if current_volume == 0: self.window.volume_button.set_value(last_volume) else: self.window.volume_button.set_value(0) def on_add_samples_action( self, action: Gio.SimpleAction, param: Optional[object] ) -> None: """Open file dialog to select multiple audio samples""" self.window.file_dialog_handler.handle_add_samples() def on_reset_to_defaults_action( self, action: Gio.SimpleAction, param: Optional[object] ) -> None: """Reset drum parts to defaults with confirmation""" ResetDefaultsDialog( window=self.window, on_reset_callback=self.window.reset_to_defaults, ) drum-machine-2.2.0/src/interfaces/000077500000000000000000000000001514070543000167755ustar00rootroot00000000000000drum-machine-2.2.0/src/interfaces/meson.build000066400000000000000000000002521514070543000211360ustar00rootroot00000000000000modulesubdir = join_paths(moduledir, 'interfaces') interfaces_sources = [ 'player.py', 'sound.py', ] install_data(interfaces_sources, install_dir: modulesubdir)drum-machine-2.2.0/src/interfaces/player.py000066400000000000000000000020631514070543000206440ustar00rootroot00000000000000# interfaces/player.py # # Copyright 2025 revisto # # 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, 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 . # # SPDX-License-Identifier: GPL-3.0-or-later from abc import ABC, abstractmethod class IPlayer(ABC): @abstractmethod def play(self) -> None: pass @abstractmethod def stop(self) -> None: pass @abstractmethod def set_bpm(self, bpm: float) -> None: pass @abstractmethod def set_volume(self, volume: float) -> None: pass drum-machine-2.2.0/src/interfaces/sound.py000066400000000000000000000024341514070543000205020ustar00rootroot00000000000000# interfaces/sound.py # # Copyright 2025 revisto # # 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, 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 . # # SPDX-License-Identifier: GPL-3.0-or-later from abc import ABC, abstractmethod class ISoundService(ABC): @abstractmethod def load_sounds(self) -> None: pass @abstractmethod def play_sound(self, sound_name: str) -> None: pass @abstractmethod def set_volume(self, volume: float) -> None: pass @abstractmethod def preview_sound(self, sound_name: str) -> None: """Play a preview of the sound at preview volume level""" pass @abstractmethod def stop_all_sounds(self) -> None: """Stop all currently playing sounds""" pass drum-machine-2.2.0/src/main.py000066400000000000000000000015741514070543000161570ustar00rootroot00000000000000# main.py # # Copyright 2025 revisto # # 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, 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 . # # SPDX-License-Identifier: GPL-3.0-or-later import sys from .application import DrumMachineApplication def main(version: str) -> int: app = DrumMachineApplication(version=version) return app.run(sys.argv) drum-machine-2.2.0/src/meson.build000066400000000000000000000032131514070543000170130ustar00rootroot00000000000000pkgdatadir = get_option('prefix') / get_option('datadir') / meson.project_name() moduledir = pkgdatadir / 'drum_machine' gnome = import('gnome') blueprint_compiler = find_program('blueprint-compiler', required: true) blueprint_files = files( 'gtk/help-overlay.blp', 'gtk/audio-export-dialog.blp', 'gtk/save-changes-dialog.blp', 'gtk/reset-defaults-dialog.blp', ) compiled_ui_dir_name = 'compiled_ui_files' compiled_blueprints = custom_target('compiled_blueprints', input: blueprint_files, output: compiled_ui_dir_name, command: [blueprint_compiler, 'batch-compile', '@OUTPUT@', '@CURRENT_SOURCE_DIR@', '@INPUT@'] ) gnome.compile_resources('drum-machine', 'drum-machine.gresource.xml', gresource_bundle: true, install: true, install_dir: pkgdatadir, dependencies: [compiled_blueprints], source_dir: [meson.current_source_dir(), compiled_blueprints.full_path()], ) python = import('python') conf = configuration_data() conf.set('PYTHON', python.find_installation('python3').full_path()) conf.set('VERSION', meson.project_version()) conf.set('localedir', get_option('prefix') / get_option('localedir')) conf.set('pkgdatadir', pkgdatadir) configure_file( input: 'drum-machine.in', output: 'drum-machine', configuration: conf, install: true, install_dir: get_option('bindir'), install_mode: 'r-xr-xr-x' ) drum_machine_sources = [ '__init__.py', 'main.py', 'window.py', 'application.py', 'style.css', 'style-dark.css', ] subdir('config') subdir('utils') subdir('interfaces') subdir('models') subdir('handlers') subdir('services') subdir('dialogs') subdir('ui') install_data(drum_machine_sources, install_dir: moduledir) drum-machine-2.2.0/src/models/000077500000000000000000000000001514070543000161355ustar00rootroot00000000000000drum-machine-2.2.0/src/models/drum_part.py000066400000000000000000000035401514070543000205060ustar00rootroot00000000000000# models/drum_part.py # # Copyright 2025 revisto # # 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, 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 . # # SPDX-License-Identifier: GPL-3.0-or-later import uuid from dataclasses import dataclass @dataclass class DrumPart: id: str name: str file_path: str is_custom: bool = False midi_note_id: int = None @classmethod def create_default(cls, name: str, file_path: str, midi_note_id: int): return cls( id=f"default_{name}", name=name.replace("-", " ").title(), file_path=file_path, is_custom=False, midi_note_id=midi_note_id, ) @classmethod def create_custom(cls, name: str, file_path: str, midi_note_id: int): return cls( id=str(uuid.uuid4()), name=name, file_path=file_path, is_custom=True, midi_note_id=midi_note_id, ) def to_dict(self): return { "id": self.id, "name": self.name, "file_path": self.file_path, "is_custom": self.is_custom, "midi_note_id": self.midi_note_id, } @classmethod def from_dict(cls, data): if "midi_note_id" not in data: data["midi_note_id"] = None return cls(**data) drum-machine-2.2.0/src/models/meson.build000066400000000000000000000002221514070543000202730ustar00rootroot00000000000000modulesubdir = join_paths(moduledir, 'models') models_sources = [ 'drum_part.py', ] install_data(models_sources, install_dir: modulesubdir) drum-machine-2.2.0/src/services/000077500000000000000000000000001514070543000164755ustar00rootroot00000000000000drum-machine-2.2.0/src/services/audio_export_service.py000066400000000000000000000127231514070543000232760ustar00rootroot00000000000000# services/audio_export_service.py # # Copyright 2025 revisto # # 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, 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 . # # SPDX-License-Identifier: GPL-3.0-or-later import os import numpy as np import subprocess import logging from ..utils.export_progress import ExportPhase from ..config.export_formats import ExportFormatRegistry from ..services.audio_renderer import AudioRenderer from ..services.file_encoder import AudioEncoder class SampleLoader: """Handles loading of drum samples""" def __init__(self, sample_rate=44100): self.sample_rate = sample_rate self.samples = {} def load_samples(self, drum_parts): """Load all drum samples into memory from drum parts""" self.samples = {} for part in drum_parts: if os.path.exists(part.file_path): try: audio_data = self._load_sample(part.file_path) self.samples[part.id] = audio_data except Exception as e: logging.warning(f"Could not load {part.file_path}: {e}") self.samples[part.id] = np.zeros((1000, 2), dtype="float32") def clear_samples(self): """Clear loaded samples from memory""" self.samples = {} def _load_sample(self, sample_path): """Load a single audio sample using ffmpeg""" cmd = [ "ffmpeg", "-i", sample_path, "-f", "f32le", "-ac", "2", # Convert to stereo "-ar", str(self.sample_rate), "-", ] result = subprocess.run(cmd, capture_output=True, check=True) audio_data = np.frombuffer(result.stdout, dtype=np.float32) return audio_data.reshape(-1, 2) def get_samples(self): """Get the loaded samples dictionary""" return self.samples class AudioExportService: """Handles audio export functionality with progress tracking""" def __init__(self, window): self.window = window self.sample_rate = 44100 # Initialize components (samples loaded lazily during export) self.sample_loader = SampleLoader(self.sample_rate) self.audio_renderer = AudioRenderer({}, self.sample_rate) self.format_registry = ExportFormatRegistry() self.audio_encoder = AudioEncoder(self.format_registry) def export_audio( self, drum_parts_state, bpm, file_path, progress_callback, repeat_count=1, metadata=None, export_task=None, ): """ Export drum pattern to audio file Args: drum_parts_state: Current drum pattern state bpm: Beats per minute file_path: Output file path progress_callback: Callback function for progress updates repeat_count: Number of times to repeat the pattern metadata: Dict with artist, title, and cover_art keys """ try: progress_callback(ExportPhase.PREPARING) # Load samples fresh from current drum parts (ensures latest files) drum_parts = self.window.sound_service.drum_part_manager.get_all_parts() self.sample_loader.load_samples(drum_parts) # Update the renderer with the loaded samples self.audio_renderer.update_samples(self.sample_loader.get_samples()) self._validate_pattern(drum_parts_state) progress_callback(ExportPhase.RENDERING) total_beats = self.window.drum_machine_service.total_beats audio_buffer = self.audio_renderer.render_pattern( drum_parts_state, bpm, total_beats, repeat_count ) progress_callback(ExportPhase.SAVING) self.audio_encoder.encode_to_file( audio_buffer.buffer, self.sample_rate, file_path, metadata, export_task ) # Clear samples from memory after export self.sample_loader.clear_samples() self.audio_renderer.clear_samples() logging.info(f"Audio exported successfully to {file_path}") return True except ValueError as e: logging.warning(f"Export validation failed: {e}") # Clear samples even on error self.sample_loader.clear_samples() self.audio_renderer.clear_samples() raise except Exception as e: logging.error(f"Export failed: {e}") # Clear samples even on error self.sample_loader.clear_samples() self.audio_renderer.clear_samples() raise def _validate_pattern(self, drum_parts_state): """Validate that the pattern has active beats""" has_beats = any( any(part_state.values()) for part_state in drum_parts_state.values() ) if not has_beats: raise ValueError("No active beats in pattern") drum-machine-2.2.0/src/services/audio_renderer.py000066400000000000000000000151741514070543000220460ustar00rootroot00000000000000# services/audio_renderer.py # # Copyright 2025 revisto # # 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, 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 . # # SPDX-License-Identifier: GPL-3.0-or-later import logging import numpy as np from ..config.constants import ( GROUP_TOGGLE_COUNT, DEFAULT_FALLBACK_SAMPLE_SIZE, ) class AudioBuffer: """Manages audio buffer operations""" def __init__(self, sample_rate: int = 44100): self.sample_rate = sample_rate self.buffer = None def create_buffer(self, duration_seconds: float): """Create output buffer with calculated duration""" try: total_samples = int(duration_seconds * self.sample_rate) self.buffer = np.zeros((total_samples, 2), dtype="float32") return self.buffer except (MemoryError, ValueError) as e: logging.error( f"Failed to create audio buffer (duration={duration_seconds}s): {e}" ) raise def add_sample(self, sample_data: np.ndarray, start_sample: int): """Add a sample to the buffer at the specified position""" if self.buffer is None: logging.warning("Attempted to add sample to uninitialized buffer") return try: end_sample = min(start_sample + len(sample_data), len(self.buffer)) self.buffer[start_sample:end_sample] += sample_data[ : end_sample - start_sample ] except (ValueError, TypeError) as e: logging.error(f"Failed to add sample at position {start_sample}: {e}") raise def normalize(self): """Normalize the audio buffer""" if self.buffer is None: logging.warning("Attempted to normalize uninitialized buffer") return try: max_amplitude = np.max(np.abs(self.buffer)) if max_amplitude > 0: self.buffer[:] = self.buffer / max_amplitude * 0.95 except (ValueError, RuntimeError) as e: logging.error(f"Failed to normalize audio buffer: {e}") raise class AudioRenderer: """Handles audio rendering operations""" def __init__(self, samples, sample_rate: int = 44100): self.samples = samples self.sample_rate = sample_rate def update_samples(self, samples): """Update the samples dictionary""" self.samples = samples def clear_samples(self): """Clear all samples from memory""" self.samples = {} def calculate_pattern_duration( self, drum_parts_state, bpm: int, repeat_count: int, total_beats: int ) -> float: """Calculate total export duration including repeats""" subdivisions_per_second = (bpm / 60) * GROUP_TOGGLE_COUNT pattern_duration_seconds = total_beats / subdivisions_per_second latest_sample_end_time = self._find_latest_sample_end_time( drum_parts_state, subdivisions_per_second ) extra_time_to_add = ( max(latest_sample_end_time, pattern_duration_seconds) - pattern_duration_seconds ) return (pattern_duration_seconds * repeat_count) + extra_time_to_add def render_pattern( self, drum_parts_state, bpm: int, total_beats: int, repeat_count: int ) -> AudioBuffer: """Render drum pattern into an audio buffer""" duration = self.calculate_pattern_duration( drum_parts_state, bpm, repeat_count, total_beats ) audio_buffer = AudioBuffer(self.sample_rate) audio_buffer.create_buffer(duration) subdivisions_per_second = (bpm / 60) * GROUP_TOGGLE_COUNT samples_per_subdivision = int(self.sample_rate / subdivisions_per_second) pattern_duration_seconds = total_beats / subdivisions_per_second for repeat in range(repeat_count): repeat_offset = repeat * int(pattern_duration_seconds * self.sample_rate) self._render_repeat( drum_parts_state, audio_buffer, repeat_offset, samples_per_subdivision, total_beats, ) audio_buffer.normalize() return audio_buffer def _find_latest_sample_end_time( self, drum_parts_state, subdivisions_per_second: float ) -> float: """Find the latest time any sample will finish playing""" latest_sample_end_time = 0 for part_id, part_state in drum_parts_state.items(): if not part_state: continue active_subdivisions = [sub for sub, active in part_state.items() if active] if not active_subdivisions: continue last_subdivision = max(active_subdivisions) trigger_time = last_subdivision / subdivisions_per_second sample_length_seconds = ( len(self.samples.get(part_id, [])) / self.sample_rate ) end_time = trigger_time + sample_length_seconds latest_sample_end_time = max(latest_sample_end_time, end_time) return latest_sample_end_time def _render_repeat( self, drum_parts_state, audio_buffer: AudioBuffer, repeat_offset: int, samples_per_subdivision: int, total_beats: int, ): """Render a single repeat of the pattern""" for subdivision in range(total_beats): start_sample = repeat_offset + (subdivision * samples_per_subdivision) self._add_subdivision_samples( drum_parts_state, audio_buffer, subdivision, start_sample ) def _add_subdivision_samples( self, drum_parts_state, audio_buffer: AudioBuffer, subdivision: int, start_sample: int, ): """Add samples for all active drum parts at this subdivision""" for part_id, part_state in drum_parts_state.items(): if part_state.get(subdivision, False): sample_data = self.samples.get( part_id, np.zeros(DEFAULT_FALLBACK_SAMPLE_SIZE) ) audio_buffer.add_sample(sample_data, start_sample) drum-machine-2.2.0/src/services/drum_machine_service.py000066400000000000000000000201051514070543000232200ustar00rootroot00000000000000# services/drum_machine_service.py # # Copyright 2025 revisto # # 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, 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 . # # SPDX-License-Identifier: GPL-3.0-or-later import threading import time import logging from typing import Dict, Optional from gi.repository import GLib from ..interfaces.player import IPlayer from ..config.constants import ( NUM_TOGGLES, GROUP_TOGGLE_COUNT, DEFAULT_BPM, DEFAULT_VOLUME, ) from .pattern_service import PatternService from .ui_helper import UIHelper class DrumMachineService(IPlayer): def __init__(self, window, sound_service, ui_helper: UIHelper) -> None: self.window = window self.sound_service = sound_service self.ui_helper = ui_helper self.playing: bool = False self.bpm: float = DEFAULT_BPM self.last_volume: float = DEFAULT_VOLUME self.play_thread: Optional[threading.Thread] = None self.stop_event: threading.Event = threading.Event() self.drum_parts_state: Dict[str, Dict[int, bool]] = ( self.create_empty_drum_parts_state() ) self.pattern_service = PatternService(window) self.total_beats: int = NUM_TOGGLES self.beats_per_page: int = NUM_TOGGLES self.active_pages: int = 1 self.playing_beat: int = -1 def create_empty_drum_parts_state(self) -> Dict[str, Dict[int, bool]]: # Get drum parts from sound service drum_parts = self.sound_service.drum_part_manager.get_all_parts() drum_parts_state = {part.id: dict() for part in drum_parts} return drum_parts_state def play(self) -> None: self.playing = True self.stop_event.clear() self.play_thread = threading.Thread(target=self._play_drum_sequence) self.play_thread.start() def stop(self) -> None: self.playing = False self.stop_event.set() self.sound_service.stop_all_sounds() self.ui_helper.clear_all_playhead_highlights() self.playing_beat = -1 if self.play_thread: self.play_thread.join() self.play_thread = None def update_total_beats(self) -> None: """ Calculates the total number of beats and active pages based on the highest active toggle. """ max_beat = 0 for part_state in self.drum_parts_state.values(): if part_state: # Check if the instrument has any active toggles max_beat = max(max_beat, *part_state.keys()) # If the pattern is completely empty, default to one page. if max_beat == 0 and not any(self.drum_parts_state.values()): num_pages = 1 else: # Calculate pages needed for the highest beat. num_pages = (max_beat // self.beats_per_page) + 1 self.active_pages = num_pages self.total_beats = self.active_pages * self.beats_per_page def set_bpm(self, bpm: float) -> None: self.bpm = bpm def set_volume(self, volume: float) -> None: self.sound_service.set_volume(volume) if volume != 0: self.last_volume = volume def clear_all_toggles(self) -> None: self.drum_parts_state = self.create_empty_drum_parts_state() self.ui_helper.deactivate_all_toggles_in_ui() def save_pattern(self, file_path: str) -> None: self.pattern_service.save_pattern(file_path, self.drum_parts_state, self.bpm) def load_pattern(self, file_path: str) -> None: self.ui_helper.deactivate_all_toggles_in_ui() self.drum_parts_state, self.bpm = self.pattern_service.load_pattern(file_path) # Refresh UI to show new temporary parts self.window.drum_grid_builder.rebuild_drum_parts_column() self.window.drum_grid_builder.rebuild_carousel() self.ui_helper.set_bpm_in_ui(self.bpm) def _play_drum_sequence(self) -> None: current_beat = 0 while self.playing and not self.stop_event.is_set(): # Check if the loop should end or wrap around if current_beat >= self.total_beats: current_beat = 0 # Loop back to the beginning if self.stop_event.is_set(): break # Highlight the current beat (this will also de-highlight the previous one) self.ui_helper.highlight_playhead_at_beat(current_beat) self.playing_beat = current_beat if current_beat % self.beats_per_page == 0 or current_beat == 0: target_page = current_beat // self.beats_per_page GLib.idle_add(self.ui_helper.scroll_carousel_to_page, target_page) # Play sounds for the current beat drum_parts = self.sound_service.drum_part_manager.get_all_parts() for part in drum_parts: if self.drum_parts_state[part.id].get(current_beat, False): self.sound_service.play_sound(part.id) # Wait for the next beat delay_per_step = 60 / self.bpm / GROUP_TOGGLE_COUNT time.sleep(delay_per_step) GLib.idle_add( self.ui_helper.remove_playhead_highlight_at_beat, current_beat ) # Advance the playhead current_beat += 1 def preview_drum_part(self, part_id: str) -> None: """Preview a drum part sound""" drum_part_manager = self.sound_service.drum_part_manager if drum_part_manager.get_part_by_id(part_id): self.sound_service.preview_sound(part_id) def add_drum_part_state(self, part_id: str) -> None: """Add a new drum part to the state""" self.drum_parts_state[part_id] = {} def add_new_drum_part(self, file_path: str, name: str) -> Optional[object]: """Add a new drum part from an audio file""" new_part = self.sound_service.drum_part_manager.add_custom_part(name, file_path) if new_part: # Reload sounds self.sound_service.reload_sounds() # Add to drum machine state self.add_drum_part_state(new_part.id) # Update UI self.window.drum_grid_builder.add_drum_part(new_part) return new_part return None def replace_drum_part( self, drum_id: str, file_path: str, name: str ) -> Optional[object]: """Replace an existing drum part with a new audio file""" result = self.sound_service.drum_part_manager.replace_part( drum_id, file_path, name ) if result: # Reload the specific sound for this drum part self.sound_service.reload_specific_sound(drum_id) # Update UI button label self.window.drum_grid_builder.update_drum_button(drum_id) # Update total beats in case pattern changed self.update_total_beats() return result return None def remove_drum_part(self, drum_id: str) -> bool: """Remove a drum part from the service""" result = self.sound_service.drum_part_manager.remove_part(drum_id) if result: # Remove from drum machine state self.drum_parts_state.pop(drum_id, None) # Rebuild the UI to reflect the removal self.window.drum_grid_builder.rebuild_drum_parts_column() self.window.drum_grid_builder.rebuild_carousel() # Update total beats in case pattern changed self.update_total_beats() logging.info(f"Removed drum part: {drum_id}") return True else: logging.error(f"Failed to remove drum part: {drum_id}") return False drum-machine-2.2.0/src/services/drum_part_manager.py000066400000000000000000000171751514070543000225510ustar00rootroot00000000000000# services/drum_part_manager.py # # Copyright 2025 revisto # # 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, 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 . # # SPDX-License-Identifier: GPL-3.0-or-later import logging import os import uuid from typing import List, Optional, Dict from ..models.drum_part import DrumPart from ..config.constants import DEFAULT_DRUM_PARTS # Default MIDI note mapping for default drum parts DEFAULT_MIDI_NOTES = { "kick": 36, "kick-2": 35, "kick-3": 34, "snare": 38, "snare-2": 37, "hihat": 42, "hihat-2": 44, "clap": 39, "tom": 41, "crash": 49, } class DrumPartManager: def __init__(self, bundled_sounds_dir: str): self.bundled_sounds_dir = bundled_sounds_dir self._drum_parts: List[DrumPart] = [] self._load_default_parts() def _load_default_parts(self): """Load the default drum parts from the bundled sounds directory""" for name in DEFAULT_DRUM_PARTS: file_path = os.path.join(self.bundled_sounds_dir, f"{name}.wav") if os.path.exists(file_path): midi_note_id = DEFAULT_MIDI_NOTES.get(name) drum_part = DrumPart.create_default(name, file_path, midi_note_id) self._drum_parts.append(drum_part) def get_all_parts(self) -> List[DrumPart]: return self._drum_parts.copy() def get_part_by_id(self, part_id: str) -> Optional[DrumPart]: for part in self._drum_parts: if part.id == part_id: return part return None def get_parts_dict(self) -> Dict[str, DrumPart]: return {part.id: part for part in self._drum_parts} def get_part_by_midi_note(self, midi_note: int) -> Optional[DrumPart]: """Get a drum part by its MIDI note ID""" for part in self._drum_parts: if part.midi_note_id == midi_note: return part return None def get_or_create_part_for_midi_note(self, midi_note: int) -> DrumPart: """Get an existing drum part for a MIDI note, or create a temporary one if it doesn't exist""" part = self.get_part_by_midi_note(midi_note) if part: return part # Create a temporary part for unknown MIDI note temp_part = DrumPart( id=str(uuid.uuid4()), name=f"Note {midi_note}", file_path="", is_custom=True, midi_note_id=midi_note, ) self._drum_parts.append(temp_part) return temp_part def add_temporary_part(self, drum_part: DrumPart): """Add a temporary drum part (for Note X parts from patterns)""" self._drum_parts.append(drum_part) def add_custom_part(self, name: str, source_file: str) -> Optional[DrumPart]: """Add a new custom drum part from an audio file""" # Validate inputs if not name or not source_file: logging.error(f"Invalid input: name='{name}', source_file='{source_file}'") return None if not os.path.exists(source_file): logging.error(f"Source file does not exist: {source_file}") return None # Create drum part directly with the source file path midi_note_id = self._get_next_available_midi_note() drum_part = DrumPart.create_custom(name, source_file, midi_note_id) self._drum_parts.append(drum_part) return drum_part def remove_part(self, part_id: str) -> bool: """Remove a drum part""" part = self.get_part_by_id(part_id) if not part: return False self._drum_parts = [p for p in self._drum_parts if p.id != part_id] return True def reorder_part(self, part_id: str, new_index: int) -> bool: """Move a drum part to a new position in the list. Args: part_id: The ID of the drum part to move new_index: The target index (0 to len-1) Returns: True if reorder was successful, False otherwise """ part = self.get_part_by_id(part_id) if not part: return False if new_index < 0 or new_index >= len(self._drum_parts): logging.warning(f"Invalid reorder index: {new_index}") return False current_index = self._drum_parts.index(part) if current_index == new_index: return True self._drum_parts.remove(part) self._drum_parts.insert(new_index, part) return True def get_part_index(self, part_id: str) -> int: """Get the index of a drum part in the list""" for i, part in enumerate(self._drum_parts): if part.id == part_id: return i return -1 def replace_part( self, part_id: str, source_file: str, new_name: str ) -> Optional[DrumPart]: """Update an existing drum part with a new audio file path and name""" # Validate inputs if not part_id or not source_file: logging.error( f"Invalid input: part_id='{part_id}', source_file='{source_file}'" ) return None part = self.get_part_by_id(part_id) if not part: logging.error(f"Drum part not found: {part_id}") return None part.name = new_name part.file_path = source_file part.is_custom = True return part def update_part_midi_note(self, part_id: str, midi_note: int) -> bool: """Update the MIDI note for a drum part""" part = self.get_part_by_id(part_id) if not part: return False part.midi_note_id = midi_note return True def is_file_available(self, part_id: str) -> bool: """Check if a drum part's file is currently available""" part = self.get_part_by_id(part_id) if not part: return False return os.path.exists(part.file_path) def reset_to_defaults(self): """Reset drum parts to defaults, removing all custom samples""" self._drum_parts = [] self._load_default_parts() def _collect_used_notes(self) -> set: """Collect all currently used MIDI notes""" return { part.midi_note_id for part in self._drum_parts if part.midi_note_id is not None } def _get_next_available_midi_note(self) -> int: """ Get the next available MIDI note ID for custom parts based on current state """ used_notes = self._collect_used_notes() return self._compute_next_midi_note(used_notes) def _compute_next_midi_note(self, used_notes: set) -> Optional[int]: """Compute the next available MIDI note given a set of used notes""" # Start from 35 (GM percussion range start) for better compatibility # GM percussion standard is 35-81, but we check up to 127 for flexibility for note in range(35, 128): if note not in used_notes: return note # If we run out of standard percussion notes, check lower range (0-34) for note in range(0, 35): if note not in used_notes: return note return None drum-machine-2.2.0/src/services/file_encoder.py000066400000000000000000000102201514070543000214600ustar00rootroot00000000000000# services/file_encoder.py # # Copyright 2025 revisto # # 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, 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 . # # SPDX-License-Identifier: GPL-3.0-or-later import os import subprocess import logging from ..config.export_formats import ExportFormatRegistry class AudioEncoder: """Handles encoding audio data to various file formats""" def __init__(self, format_registry: ExportFormatRegistry): self.format_registry = format_registry def encode_to_file( self, audio_data, sample_rate, file_path, metadata=None, export_task=None ): """Encode audio data to the specified file format""" file_ext = os.path.splitext(file_path)[1].lower() format_info = self.format_registry.get_format_by_extension(file_ext) # WAV doesn't support metadata if not format_info.supports_metadata: metadata = None self._encode_with_ffmpeg( audio_data, sample_rate, file_path, metadata, export_task ) def _encode_with_ffmpeg( self, audio_data, sample_rate, file_path, metadata=None, export_task=None ): """Use ffmpeg to encode audio data""" cmd = [ "ffmpeg", "-y", # Overwrite output files "-f", "f32le", # Input format: 32-bit float little endian "-ar", str(sample_rate), # Sample rate "-ac", "2", # Stereo "-i", "-", # Read from stdin ] # Add cover art if provided has_cover = self._has_valid_cover_art(metadata) if has_cover: cmd.extend(["-i", metadata["cover_art"]]) # Map audio stream cmd.extend(["-map", "0:a"]) # Map cover art if present if has_cover: cmd.extend(["-map", "1:v", "-disposition:v:0", "attached_pic"]) # Add metadata tags self._add_metadata_to_command(cmd, metadata) cmd.append(file_path) # Start the subprocess and store reference in export_task process = subprocess.Popen( cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE ) if export_task: export_task.current_process = process # Check for cancellation before starting if export_task and export_task.is_cancelled: process.terminate() return try: stdout, stderr = process.communicate(input=audio_data.tobytes()) if process.returncode != 0: error_msg = stderr.decode() if stderr else "Unknown error" logging.error(f"FFmpeg encoding failed: {error_msg}") raise subprocess.CalledProcessError( process.returncode, cmd, stdout, stderr ) except subprocess.CalledProcessError as e: logging.error(f"Audio encoding failed for {file_path}: {e}") raise finally: if export_task: export_task.current_process = None def _has_valid_cover_art(self, metadata): """Check if metadata contains valid cover art""" return ( metadata and metadata.get("cover_art") and os.path.exists(metadata["cover_art"]) ) def _add_metadata_to_command(self, cmd, metadata): """Add metadata tags to the ffmpeg command""" if not metadata: return if metadata.get("title"): cmd.extend(["-metadata", f'title={metadata["title"]}']) if metadata.get("artist"): cmd.extend(["-metadata", f'artist={metadata["artist"]}']) drum-machine-2.2.0/src/services/meson.build000066400000000000000000000005621514070543000206420ustar00rootroot00000000000000modulesubdir = join_paths(moduledir, 'services') services_sources = [ 'drum_machine_service.py', 'drum_part_manager.py', 'sound_service.py', 'audio_export_service.py', 'audio_renderer.py', 'file_encoder.py', 'ui_helper.py', 'pattern_service.py', 'save_changes_service.py', ] install_data(services_sources, install_dir: modulesubdir)drum-machine-2.2.0/src/services/pattern_service.py000066400000000000000000000141211514070543000222430ustar00rootroot00000000000000# services/pattern_service.py # # Copyright 2025 revisto # # 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, 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 . # # SPDX-License-Identifier: GPL-3.0-or-later import mido import itertools import logging from typing import Dict, Tuple from ..config.constants import DEFAULT_BPM class PatternService: def __init__(self, window) -> None: self.window = window def _get_midi_note_for_part(self, part_id: str) -> int: """Get MIDI note ID for a drum part""" drum_part = self.window.sound_service.drum_part_manager.get_part_by_id(part_id) if drum_part and drum_part.midi_note_id is not None: return drum_part.midi_note_id return 0 def _get_part_id_for_midi_note(self, note: int) -> str: """Get drum part ID for a MIDI note, creating a temporary part if needed""" manager = self.window.sound_service.drum_part_manager drum_part = manager.get_or_create_part_for_midi_note(note) return drum_part.id def save_pattern( self, file_path: str, drum_parts: Dict[str, Dict[int, bool]], bpm: float ) -> None: try: mid = mido.MidiFile() track = mido.MidiTrack() mid.tracks.append(track) track.append(mido.MetaMessage("set_tempo", tempo=mido.bpm2tempo(bpm))) # 1. Collect all active notes from all pages into a list events = [] for part, notes in drum_parts.items(): for beat_index, is_active in notes.items(): if is_active: note = self._get_midi_note_for_part(part) if note != 0: # Store the note and its absolute beat index events.append({"note": note, "beat": beat_index}) # 2. Sort events by beat to process them in chronological order events.sort(key=lambda e: e["beat"]) ticks_per_beat = mid.ticks_per_beat last_time_in_ticks = 0 note_duration_ticks = ticks_per_beat // 4 # 16th note duration # 3. Group events by beat to handle chords correctly for beat, group in itertools.groupby(events, key=lambda e: e["beat"]): notes_in_chord = [event["note"] for event in group] # Calculate time for this beat/chord absolute_time_in_ticks = int(beat * ticks_per_beat / 4) delta_time = absolute_time_in_ticks - last_time_in_ticks # Add all note_on messages for the chord # The first note carries the delta_time, subsequent notes have time=0 is_first_note = True for note in notes_in_chord: d_time = delta_time if is_first_note else 0 track.append( mido.Message("note_on", note=note, velocity=100, time=d_time) ) is_first_note = False # Add all note_off messages for the chord # The first note_off has the duration, subsequent ones have time=0 is_first_note = True for note in notes_in_chord: d_time = note_duration_ticks if is_first_note else 0 track.append( mido.Message("note_off", note=note, velocity=0, time=d_time) ) is_first_note = False # Update the time of the last event last_time_in_ticks = absolute_time_in_ticks + note_duration_ticks mid.save(file_path) logging.info(f"Pattern saved successfully to {file_path}") except Exception as e: logging.error(f"Failed to save pattern to {file_path}: {e}") raise def load_pattern(self, file_path: str) -> Tuple[Dict[str, Dict[int, bool]], float]: try: mid = mido.MidiFile(file_path) drum_parts_state = ( self.window.drum_machine_service.create_empty_drum_parts_state() ) bpm = DEFAULT_BPM ticks_per_beat = mid.ticks_per_beat if ticks_per_beat is None: ticks_per_beat = 480 # A common default for track in mid.tracks: absolute_time_in_ticks = 0 for msg in track: # Keep a running total of the absolute time # by adding the delta times absolute_time_in_ticks += msg.time if msg.type == "set_tempo": bpm = mido.tempo2bpm(msg.tempo) elif msg.type == "note_on" and msg.velocity > 0: part_id = self._get_part_id_for_midi_note(msg.note) # Initialize part in state if not already present if part_id not in drum_parts_state: drum_parts_state[part_id] = {} # Convert absolute time in ticks back to a beat index # assuming 16th notes ticks_per_16th_note = ticks_per_beat / 4.0 beat_index = int( round(absolute_time_in_ticks / ticks_per_16th_note) ) drum_parts_state[part_id][beat_index] = True logging.info(f"Pattern loaded successfully from {file_path}") return drum_parts_state, bpm except Exception as e: logging.error(f"Failed to load pattern from {file_path}: {e}") raise drum-machine-2.2.0/src/services/preset_service.py000066400000000000000000000122711514070543000220740ustar00rootroot00000000000000# services/pattern_service.py # # Copyright 2025 revisto # # 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, 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 . # # SPDX-License-Identifier: GPL-3.0-or-later import mido import itertools from ..config.constants import DEFAULT_BPM class PatternService: def __init__(self, window): self.window = window def _get_midi_note_for_part(self, part_id): """Get MIDI note ID for a drum part""" drum_part = self.window.sound_service.drum_part_manager.get_part_by_id(part_id) if drum_part and drum_part.midi_note_id is not None: return drum_part.midi_note_id return 0 def _get_part_id_for_midi_note(self, note): """Get drum part ID for a MIDI note, creating a temporary part if needed""" manager = self.window.sound_service.drum_part_manager drum_part = manager.get_or_create_part_for_midi_note(note) return drum_part.id def save_pattern(self, file_path, drum_parts, bpm): mid = mido.MidiFile() track = mido.MidiTrack() mid.tracks.append(track) track.append(mido.MetaMessage("set_tempo", tempo=mido.bpm2tempo(bpm))) # 1. Collect all active notes from all pages into a list events = [] for part, notes in drum_parts.items(): for beat_index, is_active in notes.items(): if is_active: note = self._get_midi_note_for_part(part) if note != 0: # Store the note and its absolute beat index events.append({"note": note, "beat": beat_index}) # 2. Sort events by beat to process them in chronological order events.sort(key=lambda e: e["beat"]) ticks_per_beat = mid.ticks_per_beat last_time_in_ticks = 0 note_duration_ticks = ticks_per_beat // 4 # 16th note duration # 3. Group events by beat to handle chords correctly for beat, group in itertools.groupby(events, key=lambda e: e["beat"]): notes_in_chord = [event["note"] for event in group] # Calculate time for this beat/chord absolute_time_in_ticks = int(beat * ticks_per_beat / 4) delta_time = absolute_time_in_ticks - last_time_in_ticks # Add all note_on messages for the chord # The first note carries the delta_time, subsequent notes have time=0 is_first_note = True for note in notes_in_chord: d_time = delta_time if is_first_note else 0 track.append( mido.Message("note_on", note=note, velocity=100, time=d_time) ) is_first_note = False # Add all note_off messages for the chord # The first note_off has the duration, subsequent ones have time=0 is_first_note = True for note in notes_in_chord: d_time = note_duration_ticks if is_first_note else 0 track.append( mido.Message("note_off", note=note, velocity=0, time=d_time) ) is_first_note = False # Update the time of the last event last_time_in_ticks = absolute_time_in_ticks + note_duration_ticks mid.save(file_path) def load_pattern(self, file_path): mid = mido.MidiFile(file_path) drum_parts_state = ( self.window.drum_machine_service.create_empty_drum_parts_state() ) bpm = DEFAULT_BPM ticks_per_beat = mid.ticks_per_beat if ticks_per_beat is None: ticks_per_beat = 480 # A common default for track in mid.tracks: absolute_time_in_ticks = 0 for msg in track: # Keep a running total of the absolute time by adding the delta times absolute_time_in_ticks += msg.time if msg.type == "set_tempo": bpm = mido.tempo2bpm(msg.tempo) elif msg.type == "note_on" and msg.velocity > 0: part_id = self._get_part_id_for_midi_note(msg.note) # Initialize part in state if not already present if part_id not in drum_parts_state: drum_parts_state[part_id] = {} # Convert absolute time in ticks back to a beat index # assuming 16th notes ticks_per_16th_note = ticks_per_beat / 4.0 beat_index = int( round(absolute_time_in_ticks / ticks_per_16th_note) ) drum_parts_state[part_id][beat_index] = True return drum_parts_state, bpm drum-machine-2.2.0/src/services/save_changes_service.py000066400000000000000000000025621514070543000232220ustar00rootroot00000000000000from typing import Callable from .drum_machine_service import DrumMachineService from ..dialogs.save_changes_dialog import SaveChangesDialog class SaveChangesService: """ Responsible for prompting the user about unsaved changes and handling the user's decision (save or discard). """ def __init__(self, window, drum_machine_service: DrumMachineService) -> None: self.window = window self.drum_machine_service = drum_machine_service self._unsaved_changes: bool = False def mark_unsaved_changes(self, value: bool) -> None: self._unsaved_changes = value def has_unsaved_changes(self) -> bool: return self._unsaved_changes def prompt_save_changes(self, on_save: Callable, on_discard: Callable) -> None: """ Open the dialog; if user discards, call on_discard(). If user saves, call on_save(), then mark changes as saved. """ SaveChangesDialog( window=self.window, on_save_callback=self._wrap_save_callback(on_save), on_discard_callback=on_discard, ) def _wrap_save_callback(self, callback: Callable) -> Callable: """ Wrap the user-provided callback to reset unsaved changes after saving. """ def wrapper(): callback() self.mark_unsaved_changes(False) return wrapper drum-machine-2.2.0/src/services/sound_service.py000066400000000000000000000054171514070543000217260ustar00rootroot00000000000000# services/sound_service.py # # Copyright 2025 revisto # # 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, 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 . # # SPDX-License-Identifier: GPL-3.0-or-later import pygame import logging from typing import Dict from ..interfaces.sound import ISoundService from .drum_part_manager import DrumPartManager from ..config.constants import MIXER_CHANNELS class SoundService(ISoundService): def __init__(self, bundled_sounds_dir: str) -> None: pygame.init() pygame.mixer.set_num_channels(MIXER_CHANNELS) self.bundled_sounds_dir = bundled_sounds_dir self.drum_part_manager = DrumPartManager(bundled_sounds_dir) self.sounds: Dict[str, pygame.mixer.Sound] = {} self._current_volume: float = 1.0 def load_sounds(self) -> None: self.sounds = {} for part in self.drum_part_manager.get_all_parts(): try: # Skip temporary parts without file paths if not part.file_path: continue sound = pygame.mixer.Sound(part.file_path) sound.set_volume(self._current_volume) self.sounds[part.id] = sound except Exception as e: logging.error(f"Error loading sound {part.name}: {e}") def reload_sounds(self) -> None: """Reload all sounds from the current drum parts""" self.load_sounds() def reload_specific_sound(self, part_id: str) -> None: """Reload a specific sound after drum part replacement""" part = self.drum_part_manager.get_part_by_id(part_id) if part: sound = pygame.mixer.Sound(part.file_path) sound.set_volume(self._current_volume) self.sounds[part_id] = sound def play_sound(self, part_id: str) -> None: if part_id in self.sounds: self.sounds[part_id].play() def set_volume(self, volume: float) -> None: self._current_volume = volume / 100 for sound in self.sounds.values(): sound.set_volume(self._current_volume) def preview_sound(self, part_id: str) -> None: if part_id in self.sounds: self.play_sound(part_id) def stop_all_sounds(self) -> None: pygame.mixer.stop() drum-machine-2.2.0/src/services/ui_helper.py000066400000000000000000000103741514070543000210300ustar00rootroot00000000000000# services/ui_helper.py # # Copyright 2025 revisto # # 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, 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 . # # SPDX-License-Identifier: GPL-3.0-or-later import logging from typing import Dict class UIHelper: def __init__(self, window) -> None: self.window = window @property def beats_per_page(self) -> int: """Get the current number of beats per page from the grid builder.""" return self.window.drum_machine_service.beats_per_page def _set_playhead_highlight_for_beat( self, beat_index: int, highlight_on: bool ) -> None: """ Internal helper to add or remove the 'playhead-active' CSS class for a vertical column of toggles at a specific beat index. """ for part in self.window.sound_service.drum_part_manager.get_all_parts(): try: toggle = getattr(self.window, f"{part.id}_toggle_{beat_index}") if highlight_on: toggle.get_style_context().add_class("toggle-active") else: toggle.get_style_context().remove_class("toggle-active") except AttributeError: logging.debug( f"Toggle not found for playhead highlight: " f"{part.id}_toggle_{beat_index}" ) continue def highlight_playhead_at_beat(self, beat_index: int) -> None: self._set_playhead_highlight_for_beat(beat_index, highlight_on=True) def remove_playhead_highlight_at_beat(self, beat_index: int) -> None: self._set_playhead_highlight_for_beat(beat_index, highlight_on=False) def clear_all_playhead_highlights(self) -> None: """Removes all playhead highlights from the currently visible toggles.""" # This is inefficient and will be slow with many pages. # It should ideally track the last highlighted beat and only clear that one. for i in range(self.beats_per_page * self.window.carousel.get_n_pages()): self._set_playhead_highlight_for_beat(i, highlight_on=False) def deactivate_all_toggles_in_ui(self) -> None: """Sets the state of all currently rendered toggles to inactive (OFF).""" total_toggles = self.beats_per_page * self.window.carousel.get_n_pages() for part in self.window.sound_service.drum_part_manager.get_all_parts(): for i in range(total_toggles): try: toggle = getattr(self.window, f"{part.id}_toggle_{i}") if toggle.get_active(): toggle.set_active(False) except AttributeError: logging.debug( f"Toggle not found for deactivation: {part.id}_toggle_{i}" ) continue def load_pattern_into_ui( self, drum_parts_state: Dict[str, Dict[int, bool]] ) -> None: """ Updates the UI to reflect a new pattern. This is fundamentally broken with the dynamic grid and needs a redesign. The UI should pull data when it's created, not have data pushed to it. """ for part_id in drum_parts_state: for beat_index in drum_parts_state[part_id].keys(): toggle = getattr(self.window, f"{part_id}_toggle_{beat_index}") toggle.set_active(True) def set_bpm_in_ui(self, bpm_value: float) -> None: """Updates the BPM spin button with a new value.""" self.window.bpm_spin_button.set_value(bpm_value) def scroll_carousel_to_page(self, page_index: int) -> None: """Delegates the request to scroll the carousel to the main window.""" self.window.scroll_carousel_to_page(page_index) drum-machine-2.2.0/src/style-dark.css000066400000000000000000000007371514070543000174520ustar00rootroot00000000000000.adw-window { background: #6b369c; } .drum-machine-box { background-color: #00000027; } .drum-machine-box .drum-toggle.toggle-active { background-color: #bf79e7; box-shadow: 0 0 10px #bf79e7; } .drum-machine-box .drum-toggle { background-color: #ffffff1c; } .drum-machine-box .drum-toggle:hover { background-color: #ffffff42; } .drum-machine-box .drum-toggle:checked { background-color: #ffffff5e; } .bottom-wrapper { background: #6b369c; } drum-machine-2.2.0/src/style.css000066400000000000000000000033531514070543000165300ustar00rootroot00000000000000.adw-window { background: #D38CFF; } .drum-machine-box { padding: 20px; padding-bottom: 15px; border-radius: 10px; background-color: #ffffff27; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); } .drum-machine-box .drum-toggle { background-color: #ffffff65; } .drum-machine-box .drum-toggle.toggle-active { background-color: #ffffff; box-shadow: 0 0 10px #ffffff; } .drum-machine-box .drum-toggle:hover { background-color: #ffffffb0; } .drum-machine-box .drum-toggle:checked { background-color: #ffffff; } .drum-machine-box.medium button { min-width: 20px; min-height: 20px; padding: 4px; border-radius: 6px; } .drum-machine-box.compact button { min-width: 10px; min-height: 10px; padding: 0; border-radius: 6px; } .bottom-wrapper { padding: 10px; } .drum-machine-box.compact .drum-part-button { padding-left: 6px; padding-right: 6px; } .disabled { opacity: 0.5; } .drag-over-replace { background-color: @accent_bg_color !important; box-shadow: 0 0 15px @accent_bg_color !important; border: 3px solid @accent_bg_color !important; border-radius: 6px; } /* New drum placeholder styling */ .new-drum-placeholder button { opacity: 0.6; color: @accent_color; } .new-drum-placeholder.highlight button { opacity: 1; box-shadow: 0 0 10px @accent_color; border: 2px solid @accent_color; } .export-button { transition: 200ms ease-in-out; } .drag-source-active { opacity: 0.5; } /* Remove default GTK drop target outline from column */ box:drop(active) { outline: none; box-shadow: none; border: none; } .insert-above { box-shadow: 0 -3px 0 0 @accent_color; } .insert-below { box-shadow: 0 3px 0 0 @accent_color; } drum-machine-2.2.0/src/ui/000077500000000000000000000000001514070543000152675ustar00rootroot00000000000000drum-machine-2.2.0/src/ui/drum_grid_builder.py000066400000000000000000000707271514070543000213400ustar00rootroot00000000000000# ui/drum_grid_builder.py # # Copyright 2025 revisto # # 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, 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 . # # SPDX-License-Identifier: GPL-3.0-or-later import gi import logging gi.require_version("Gtk", "4.0") gi.require_version("Adw", "1") from gi.repository import Gtk, Gdk, Adw, GLib from gettext import gettext as _ from ..config.constants import GROUP_TOGGLE_COUNT from ..dialogs.midi_mapping_dialog import MidiMappingDialog class DrumGridBuilder: """Responsible for building the drum grid UI components""" def __init__(self, window): self.window = window self.main_container = None self.drum_parts_column = None @property def beats_per_page(self): """Get the current number of beats per page from the grid builder.""" return self.window.drum_machine_service.beats_per_page def build_drum_machine_interface(self): """Build the static drum machine interface and placeholders.""" self.main_container = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=10) self.main_container.set_name("main_container") horizontal_layout = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=10) horizontal_layout.set_homogeneous(False) drum_parts_column = self._create_drum_parts_column() self.drum_parts_column = drum_parts_column horizontal_layout.append(drum_parts_column) # Create a container to hold the rebuildable carousel self.carousel_container = Gtk.Box() self.carousel_container.set_hexpand(True) horizontal_layout.append(self.carousel_container) self.main_container.append(horizontal_layout) # Create a container for the dots indicator self.dots_container = Gtk.Box() self.dots_container.set_halign(Gtk.Align.CENTER) self.main_container.append(self.dots_container) # Build the carousel for the first time self.rebuild_carousel() return self.main_container def rebuild_carousel(self, focus_beat_index=0): """Builds or rebuilds only the carousel and its indicator dots.""" carousel = self._create_carousel_drum_rows() dots = self._create_dots_indicator(carousel) if self.carousel_container.get_first_child(): self.carousel_container.remove(self.carousel_container.get_first_child()) if self.dots_container.get_first_child(): self.dots_container.remove(self.dots_container.get_first_child()) self.carousel_container.append(carousel) self.dots_container.append(dots) self.window.drum_machine_service.update_total_beats() new_target_page = focus_beat_index // self.beats_per_page self.reset_carousel_pages(new_target_page) self.window.ui_helper.load_pattern_into_ui( self.window.drum_machine_service.drum_parts_state ) GLib.timeout_add(50, self._scroll_carousel_to_page_safely, new_target_page) def _scroll_carousel_to_page_safely(self, page_index): """Scrolls the carousel to a specific page, ensuring it exists.""" if hasattr(self.window, "carousel"): n_pages = self.window.carousel.get_n_pages() target_page = max(0, min(page_index, n_pages - 1)) if n_pages > 0: self.window.carousel.scroll_to( self.window.carousel.get_nth_page(target_page), True ) return GLib.SOURCE_REMOVE def _create_dots_indicator(self, carousel): """Create dots indicator for the carousel""" dots = Adw.CarouselIndicatorDots() dots.set_carousel(carousel) dots.set_margin_top(10) return dots def _create_drum_parts_column(self): """Create the drum parts buttons column""" drum_parts = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=10) # Get drum parts from the sound service drum_part_manager = self.window.sound_service.drum_part_manager for drum_part in drum_part_manager.get_all_parts(): instrument_button = self.create_instrument_button(drum_part) drum_parts.append(instrument_button) # Setup drop target on the column for reordering self.window.drag_drop_handler.setup_column_reorder_drop_target(drum_parts) return drum_parts def _create_carousel_drum_rows(self): """Create carousel with drum rows""" carousel = Adw.Carousel() carousel.set_spacing(30) self.window.carousel = carousel carousel.connect("page-changed", self._on_page_changed) key_controller = Gtk.EventControllerKey.new() key_controller.connect("key-pressed", self._on_carousel_key_pressed) carousel.add_controller(key_controller) for i in range(2): page = self._create_beat_grid_page(i) carousel.append(page) return carousel def _on_page_changed(self, carousel, index): self.reset_carousel_pages() def reset_carousel_pages(self, current_page_index=-1): """Resets the carousel pages to match the number of active pages in the current pattern.""" carousel = self.window.carousel active_pages_in_pattern = self.window.drum_machine_service.active_pages pages_for_pattern = active_pages_in_pattern + 1 if current_page_index == -1: current_page_index = carousel.get_position() pages_for_view = current_page_index + 2 desired_pages = max(2, pages_for_pattern, pages_for_view) n_pages = carousel.get_n_pages() while n_pages < desired_pages: new_page = self._create_beat_grid_page(n_pages) carousel.append(new_page) n_pages = carousel.get_n_pages() while n_pages > desired_pages: page_to_remove = carousel.get_nth_page(n_pages - 1) carousel.remove(page_to_remove) n_pages = carousel.get_n_pages() def _on_carousel_key_pressed(self, controller, keyval, keycode, state): """Handles key presses on the carousel to prevent page navigation with arrow keys.""" if keyval == Gdk.KEY_Left or keyval == Gdk.KEY_Right: return True return False def _on_instrument_button_key_pressed( self, controller, keyval, keycode, state, drum_part ): """Handles right arrow key navigation from an instrument button to the grid.""" if keyval == Gdk.KEY_Right: current_page_index = self.window.carousel.get_position() target_beat_index = int(current_page_index * self.beats_per_page) try: target_toggle = getattr( self.window, f"{drum_part}_toggle_{target_beat_index}" ) target_toggle.grab_focus() return True except AttributeError as e: logging.debug( f"Toggle not found during navigation: " f"{drum_part}_toggle_{target_beat_index}: {e}" ) return True return False def _on_toggle_key_pressed( self, controller, keyval, keycode, state, drum_part, global_beat_index ): """Handles arrow key navigation between toggle buttons.""" if keyval == Gdk.KEY_Right: return self._handle_right_arrow(drum_part, global_beat_index) elif keyval == Gdk.KEY_Left: return self._handle_left_arrow(drum_part, global_beat_index) return False def _handle_right_arrow(self, drum_part, global_beat_index): """Handle right arrow key navigation.""" # Check if we're at the rightmost position of the current page if (global_beat_index + 1) % self.beats_per_page == 0: return self._scroll_to_next_page(drum_part, global_beat_index) target_beat_index = global_beat_index + 1 return self._navigate_to_target(drum_part, global_beat_index, target_beat_index) def _scroll_to_next_page(self, drum_part, global_beat_index): """Scroll to next page and focus the leftmost toggle.""" carousel = self.window.carousel current_page = global_beat_index // self.beats_per_page n_pages = carousel.get_n_pages() if current_page < n_pages - 1: carousel.scroll_to(carousel.get_nth_page(current_page + 1), True) # Focus the leftmost toggle on the next page target_beat_index = (current_page + 1) * self.beats_per_page return self._focus_target_toggle(drum_part, target_beat_index) # If we're on the last page, stay where we are return True def _handle_left_arrow(self, drum_part, global_beat_index): """Handle left arrow key navigation.""" if global_beat_index % self.beats_per_page == 0: # At the leftmost position, scroll to previous page instead of jumping to # instrument return self._scroll_to_previous_page(drum_part, global_beat_index) target_beat_index = global_beat_index - 1 return self._navigate_to_target(drum_part, global_beat_index, target_beat_index) def _scroll_to_previous_page(self, drum_part, global_beat_index): """Scroll to previous page and focus the rightmost toggle.""" carousel = self.window.carousel current_page = global_beat_index // self.beats_per_page if current_page > 0: carousel.scroll_to(carousel.get_nth_page(current_page - 1), True) # Focus the rightmost toggle on the previous page target_beat_index = (current_page - 1) * self.beats_per_page + ( self.beats_per_page - 1 ) return self._focus_target_toggle(drum_part, target_beat_index) # If we're on the first page, go to instrument button return self._navigate_to_instrument_button(drum_part) def _navigate_to_instrument_button(self, drum_part): """Navigate to the instrument button.""" try: instrument_button = getattr(self.window, f"{drum_part}_instrument_button") instrument_button.grab_focus() return True except AttributeError as e: logging.debug( f"Instrument button not found: {drum_part}_instrument_button: {e}" ) return True def _navigate_to_target(self, drum_part, global_beat_index, target_beat_index): """Navigate to target toggle button.""" self._scroll_if_needed(global_beat_index, target_beat_index) return self._focus_target_toggle(drum_part, target_beat_index) def _scroll_if_needed(self, global_beat_index, target_beat_index): """Scroll carousel if crossing page boundary.""" current_page_index = global_beat_index // self.beats_per_page target_page_index = target_beat_index // self.beats_per_page if current_page_index != target_page_index: carousel = self.window.carousel n_pages = carousel.get_n_pages() if 0 <= target_page_index < n_pages: carousel.scroll_to(carousel.get_nth_page(target_page_index), True) def _focus_target_toggle(self, drum_part, target_beat_index): """Focus the target toggle button.""" try: target_toggle = getattr( self.window, f"{drum_part}_toggle_{target_beat_index}" ) target_toggle.grab_focus() return True except AttributeError as e: logging.debug( f"Target toggle not found: {drum_part}_toggle_{target_beat_index}: {e}" ) return True def _setup_instrument_button_right_click(self, button, drum_part): """Setup right-click gesture for instrument button to remove drum part""" right_click_gesture = Gtk.GestureClick.new() right_click_gesture.set_button(Gdk.BUTTON_SECONDARY) right_click_gesture.connect( "released", self._on_drum_part_button_right_clicked, drum_part.id ) button.add_controller(right_click_gesture) def _on_drum_part_button_right_clicked(self, gesture_click, n_press, x, y, drum_id): """Handle right-click on instrument buttons to show context menu""" self._show_drum_part_context_menu(gesture_click.get_widget(), drum_id) def _show_drum_part_context_menu(self, button, drum_id): """Show context menu for drum part button""" popover = Gtk.Popover() popover.set_parent(button) menu_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=0) # Build menu items can_remove = ( len(self.window.sound_service.drum_part_manager.get_all_parts()) > 1 ) menu_items = [ (_("Preview"), self._on_preview_clicked, True, None), ( _("Replace…"), self._on_replace_clicked, True, _("Replace with new sound"), ), ( _("Remove"), self._on_remove_clicked, can_remove, None if can_remove else _("At least one drum part must remain"), ), None, ( _("MIDI Mapping"), self._on_midi_mapping_clicked, True, _("Configure MIDI note for export"), ), ] # Create buttons for item in menu_items: if item is None: menu_box.append(Gtk.Separator(orientation=Gtk.Orientation.HORIZONTAL)) continue label, callback, enabled, tooltip = item btn = self._create_menu_button( label, callback, drum_id, popover, enabled, tooltip ) menu_box.append(btn) popover.set_child(menu_box) popover.popup() def _create_menu_button( self, label, callback, drum_id, popover, enabled=True, tooltip=None ): """Create a menu button with consistent styling""" btn = Gtk.Button(label=label) btn.add_css_class("flat") btn.set_sensitive(enabled) if enabled: btn.connect("clicked", callback, drum_id, popover) if tooltip: btn.set_tooltip_text(tooltip) return btn def _on_preview_clicked(self, button, drum_id, popover): """Handle preview button click""" self.window.drum_machine_service.preview_drum_part(drum_id) popover.popdown() def _on_midi_mapping_clicked(self, button, drum_id, popover): """Handle MIDI mapping button click""" popover.popdown() drum_part_manager = self.window.sound_service.drum_part_manager drum_part = drum_part_manager.get_part_by_id(drum_id) if not drum_part: return dialog = MidiMappingDialog(self.window, drum_part, self._on_midi_mapping_save) dialog.present(self.window) def _on_midi_mapping_save(self, drum_id, note): """Callback for saving MIDI mapping""" drum_part_manager = self.window.sound_service.drum_part_manager if drum_part_manager.update_part_midi_note(drum_id, note): self.window.show_toast(_("MIDI note updated")) self.update_drum_button(drum_id) def _on_replace_clicked(self, button, drum_id, popover): """Handle replace button click""" popover.popdown() # Open file chooser self.window.file_dialog_handler.open_audio_file_chooser( _("Select New Sound"), self.window.drag_drop_handler.handle_replacement_file_selected, drum_id, ) def _on_remove_clicked(self, button, drum_id, popover): """Handle remove button click""" # Get drum part name before removing it drum_part_manager = self.window.sound_service.drum_part_manager drum_part = drum_part_manager.get_part_by_id(drum_id) drum_name = drum_part.name if drum_part else drum_id result = self.window.drum_machine_service.remove_drum_part(drum_id) if result: self.window.show_toast(_("Removed drum part: {}").format(drum_name)) # Mark as unsaved when removing drum parts self.window.save_changes_service.mark_unsaved_changes(True) self.window.update_export_button_sensitivity() else: self.window.show_toast(_("Failed to remove drum part")) popover.popdown() def _create_beat_grid_page(self, page_index): """Creates a single page containing a full set of instrument tracks.""" page = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=10) # Get drum parts from the sound service drum_part_manager = self.window.sound_service.drum_part_manager for drum_part in drum_part_manager.get_all_parts(): drum_row = self.create_drum_row(drum_part.id, page_index) page.append(drum_row) return page def create_drum_row(self, drum_part, page_index): """Create a complete row for a drum part""" instrument_container = Gtk.Box( orientation=Gtk.Orientation.HORIZONTAL, spacing=10 ) num_beat_groups = ( self.beats_per_page + GROUP_TOGGLE_COUNT - 1 ) // GROUP_TOGGLE_COUNT for group_index in range(num_beat_groups): beat_group = self.create_beat_toggle_group( drum_part, group_index, page_index ) instrument_container.append(beat_group) if group_index != num_beat_groups - 1: beat_group.set_margin_end(20) return instrument_container def _create_drum_button(self, label, tooltip_text, clickable=True, drum_part=None): """Create a drum button with consistent styling""" button = Gtk.Button(label=label) button.set_halign(Gtk.Align.START) button.add_css_class("drum-part-button") button.add_css_class("flat") button.set_tooltip_text(tooltip_text) button.set_has_tooltip(True) if not clickable: button.set_sensitive(False) if drum_part and clickable: button.connect( "clicked", self.window.on_drum_part_button_clicked, drum_part.id ) key_controller = Gtk.EventControllerKey.new() key_controller.connect( "key-pressed", self._on_instrument_button_key_pressed, drum_part.id ) button.add_controller(key_controller) # Add right-click gesture for removing drum parts self._setup_instrument_button_right_click(button, drum_part) setattr(self.window, f"{drum_part.id}_instrument_button", button) # Setup drag and drop for replacement if drum_part: self.window.drag_drop_handler.setup_button_drop_target(button, drum_part.id) else: self.window.drag_drop_handler.setup_button_drop_target(button) return button def _create_button_container(self, button): """Create button container with consistent layout""" button_container = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) button_container.set_spacing(5) button_container.append(button) spacer = Gtk.Label() spacer.set_hexpand(True) button_container.append(spacer) return button_container def create_instrument_button(self, drum_part): """Create the instrument preview button""" # Calculate button content first label, tooltip = self._get_button_content(drum_part) button = self._create_drum_button( label, tooltip, clickable=True, drum_part=drum_part ) # Apply styling based on file availability self._apply_button_styling(button, drum_part) # Setup drag source for reordering self.window.drag_drop_handler.setup_button_reorder_drag_source( button, drum_part.id ) return self._create_button_container(button) def _get_button_content(self, drum_part): """Get the label and tooltip for a drum part button""" # Truncate long names to keep UI clean max_length = 11 display_name = ( drum_part.name[: max_length - 3] + "…" if len(drum_part.name) > max_length else drum_part.name ) # Handle temporary parts if not drum_part.file_path: tooltip_text = ( f"Temporary part: {drum_part.name} (MIDI Note {drum_part.midi_note_id})" ) return display_name, tooltip_text # Check if the file is available drum_part_manager = self.window.sound_service.drum_part_manager file_available = drum_part_manager.is_file_available(drum_part.id) # Create tooltip text based on file availability if file_available: tooltip_text = f"Click to Preview {drum_part.name}" else: tooltip_text = f"Missing file: {drum_part.file_path}" return display_name, tooltip_text def _apply_button_styling(self, button, drum_part): """Apply styling to a button based on file availability""" drum_part_manager = self.window.sound_service.drum_part_manager file_available = drum_part_manager.is_file_available(drum_part.id) if file_available: button.remove_css_class("disabled") else: button.add_css_class("disabled") def update_button_content(self, button, drum_part): """Update button content (label, tooltip, disabled state) for a drum part""" label, tooltip = self._get_button_content(drum_part) button.set_label(label) button.set_tooltip_text(tooltip) self._apply_button_styling(button, drum_part) def update_drum_button(self, drum_id): """Update an existing drum button's state""" try: # Get the drum part drum_part_manager = self.window.sound_service.drum_part_manager drum_part = drum_part_manager.get_part_by_id(drum_id) if not drum_part: logging.warning(f"Drum part not found: {drum_id}") return # Find and update the button button_attr = f"{drum_id}_instrument_button" if hasattr(self.window, button_attr): button = getattr(self.window, button_attr) # Use the shared logic self.update_button_content(button, drum_part) else: # Button doesn't exist, rebuild the drum parts column self.rebuild_drum_parts_column() except Exception as e: logging.error( f"Error updating drum button for {drum_id}: {e}", exc_info=True ) # Fallback: rebuild the drum parts column self.rebuild_drum_parts_column() def create_beat_toggle_group(self, drum_part, group_index, page_index): """Create a group of beat toggles""" beat_group = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5) for position in range(GROUP_TOGGLE_COUNT): beat_number_on_page = group_index * GROUP_TOGGLE_COUNT + position + 1 if beat_number_on_page > self.beats_per_page: break beat_toggle = self.create_single_beat_toggle( drum_part, beat_number_on_page, page_index ) beat_group.append(beat_toggle) return beat_group def rebuild_drum_parts_column(self): """Rebuild the drum parts column to reflect current drum parts""" try: # Get the current drum parts column if not self.drum_parts_column: return # Clear existing children while self.drum_parts_column.get_first_child(): self.drum_parts_column.remove(self.drum_parts_column.get_first_child()) # Rebuild with current drum parts drum_part_manager = self.window.sound_service.drum_part_manager for drum_part in drum_part_manager.get_all_parts(): instrument_button = self.create_instrument_button(drum_part) self.drum_parts_column.append(instrument_button) except Exception as e: logging.error(f"Error rebuilding drum parts column: {e}", exc_info=True) def create_single_beat_toggle(self, drum_part, beat_number_on_page, page_index): """Create a single beat toggle button""" global_beat_index = page_index * self.beats_per_page + (beat_number_on_page - 1) beat_toggle = Gtk.ToggleButton() beat_toggle.set_size_request(20, 20) beat_toggle.set_name(f"{drum_part}_toggle_{global_beat_index}") beat_toggle.set_valign(Gtk.Align.CENTER) beat_toggle.add_css_class("drum-toggle") beat_toggle.connect( "toggled", self.window.on_toggle_changed, drum_part, global_beat_index ) toggle_key_controller = Gtk.EventControllerKey.new() toggle_key_controller.connect( "key-pressed", self._on_toggle_key_pressed, drum_part, global_beat_index ) beat_toggle.add_controller(toggle_key_controller) right_click_gesture = Gtk.GestureClick.new() right_click_gesture.set_button(Gdk.BUTTON_SECONDARY) right_click_gesture.connect( "released", self.window._on_right_click_released, beat_toggle ) beat_toggle.add_controller(right_click_gesture) setattr(self.window, f"{drum_part}_toggle_{global_beat_index}", beat_toggle) return beat_toggle def update_drum_parts_spacing(self, is_compact): """Updates the spacing of the drum parts column.""" if self.drum_parts_column: new_spacing = 12 if is_compact else 10 self.drum_parts_column.set_spacing(new_spacing) def add_drum_part(self, drum_part): """Add a new drum part to the existing interface""" # Add new instrument button to drum parts column if self.drum_parts_column: instrument_button = self.create_instrument_button(drum_part) self.drum_parts_column.append(instrument_button) # Add new drum row to each carousel page if hasattr(self.window, "carousel"): n_pages = self.window.carousel.get_n_pages() for page_index in range(n_pages): page = self.window.carousel.get_nth_page(page_index) drum_row = self.create_drum_row(drum_part.id, page_index) page.append(drum_row) def _create_placeholder_button_container(self): """Create a placeholder button container""" placeholder_button = self._create_drum_button( "+ New", "Drop audio files here to add new drum", clickable=True ) return self._create_button_container(placeholder_button) def create_new_drum_placeholder(self): """Create the 'New Drum' placeholder at the end of the drum parts column""" if not self.drum_parts_column: return None placeholder_container = self._create_placeholder_button_container() placeholder_container.add_css_class("new-drum-placeholder") revealer = Gtk.Revealer() revealer.set_transition_type(Gtk.RevealerTransitionType.SLIDE_DOWN) revealer.set_transition_duration(100) revealer.set_child(placeholder_container) self.drum_parts_column.append(revealer) revealer.set_reveal_child(True) return revealer def remove_new_drum_placeholder(self, placeholder): """Remove the new drum placeholder from the drum parts column with animation""" if ( placeholder and self.drum_parts_column and placeholder.get_parent() == self.drum_parts_column ): placeholder.set_transition_duration(50) placeholder.set_reveal_child(False) GLib.timeout_add(50, self._finish_remove_placeholder, placeholder) def _finish_remove_placeholder(self, placeholder): """Actually remove the placeholder after animation completes""" if placeholder and placeholder.get_parent() == self.drum_parts_column: self.drum_parts_column.remove(placeholder) return GLib.SOURCE_REMOVE drum-machine-2.2.0/src/ui/meson.build000066400000000000000000000002161514070543000174300ustar00rootroot00000000000000modulesubdir = join_paths(moduledir, 'ui') ui_sources = [ 'drum_grid_builder.py', ] install_data(ui_sources, install_dir: modulesubdir) drum-machine-2.2.0/src/utils/000077500000000000000000000000001514070543000160125ustar00rootroot00000000000000drum-machine-2.2.0/src/utils/export_progress.py000066400000000000000000000145101514070543000216320ustar00rootroot00000000000000# utils/export_progress.py # # Copyright 2025 revisto # # 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, 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 . # # SPDX-License-Identifier: GPL-3.0-or-later import threading import time import logging from enum import Enum from typing import Optional from gi.repository import GLib, Gtk, Adw from gettext import gettext as _ from ..config.constants import PULSE_INTERVAL_SECONDS class ExportPhase(Enum): PREPARING = "preparing" RENDERING = "rendering" SAVING = "saving" class ExportProgressHandler: """Handles export progress updates and UI thread coordination""" def __init__( self, progress_bar: Gtk.ProgressBar, status_overlay: Adw.ToastOverlay, status_label: Gtk.Label, detail_label: Gtk.Label, ) -> None: self.progress_bar = progress_bar self.status_overlay = status_overlay self.status_label = status_label self.detail_label = detail_label self.pulse_thread: Optional[threading.Thread] = None self.pulse_stop_event: Optional[threading.Event] = None self.is_active: bool = False def start_progress_tracking(self) -> None: """Start showing progress UI and pulse updates""" self.is_active = True self.progress_bar.set_visible(True) self.status_overlay.set_visible(True) self._start_pulse_thread() def stop_progress_tracking(self): """Stop progress tracking and hide UI""" self.is_active = False self.progress_bar.set_visible(False) self.status_overlay.set_visible(False) self._stop_pulse_thread() def update_phase(self, phase: ExportPhase): """Update the progress UI for the current export phase""" def update_ui(): self.progress_bar.pulse() if phase == ExportPhase.PREPARING: self.status_label.set_label(_("Preparing…")) self.detail_label.set_label(_("Initializing…")) elif phase == ExportPhase.RENDERING: self.status_label.set_label(_("Rendering audio…")) self.detail_label.set_label(_("Processing beats…")) elif phase == ExportPhase.SAVING: self.status_label.set_label(_("Saving file…")) self.detail_label.set_label(_("Writing to disk…")) else: self.status_label.set_label(_("Exporting…")) self.detail_label.set_label(_("Processing…")) GLib.idle_add(update_ui) def _start_pulse_thread(self): """Start background thread for progress bar pulsing""" if self.pulse_thread and self.pulse_thread.is_alive(): return self.pulse_stop_event = threading.Event() def pulse_worker(): while not self.pulse_stop_event.is_set() and self.is_active: GLib.idle_add(self.progress_bar.pulse) time.sleep(PULSE_INTERVAL_SECONDS) self.pulse_thread = threading.Thread(target=pulse_worker, daemon=True) self.pulse_thread.start() def _stop_pulse_thread(self): """Stop the pulse thread""" if self.pulse_stop_event: self.pulse_stop_event.set() if self.pulse_thread and self.pulse_thread.is_alive(): self.pulse_thread.join(timeout=1.1) class ExportTask: """Manages the background export operation""" def __init__(self, audio_export_service, progress_handler: ExportProgressHandler): self.audio_export_service = audio_export_service self.progress_handler = progress_handler self.export_thread = None self.is_cancelled = False self.current_process = None def start_export( self, drum_parts_state, bpm, filename, repeat_count, metadata, completion_callback, ): """Start the export process in a background thread""" if self.export_thread and self.export_thread.is_alive(): return False self.is_cancelled = False self.progress_handler.start_progress_tracking() self.export_thread = threading.Thread( target=self._export_worker, args=( drum_parts_state, bpm, filename, repeat_count, metadata, completion_callback, ), daemon=True, ) self.export_thread.start() return True def cancel_export(self): """Cancel the ongoing export""" self.is_cancelled = True # Kill running process immediately if self.current_process and self.current_process.poll() is None: try: self.current_process.kill() except Exception: pass self.progress_handler.stop_progress_tracking() def _export_worker( self, drum_parts_state, bpm, filename, repeat_count, metadata, completion_callback, ): """Background worker for the export process""" try: if self.is_cancelled: return success = self.audio_export_service.export_audio( drum_parts_state, bpm, filename, progress_callback=self.progress_handler.update_phase, repeat_count=repeat_count, metadata=metadata, export_task=self, ) if not self.is_cancelled: GLib.idle_add(completion_callback, success, filename) except Exception as e: logging.error(f"Export error: {e}") if not self.is_cancelled: GLib.idle_add(completion_callback, False, filename) finally: self.progress_handler.stop_progress_tracking() drum-machine-2.2.0/src/utils/meson.build000066400000000000000000000002521514070543000201530ustar00rootroot00000000000000modulesubdir = join_paths(moduledir, 'utils') utils_sources = [ 'export_progress.py', 'name_utils.py', ] install_data(utils_sources, install_dir: modulesubdir) drum-machine-2.2.0/src/utils/name_utils.py000066400000000000000000000023301514070543000205220ustar00rootroot00000000000000# utils/name_utils.py # # Copyright 2025 revisto # # 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, 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 . # # SPDX-License-Identifier: GPL-3.0-or-later from pathlib import Path from typing import Union from gettext import gettext as _ def extract_name_from_path(file_path: Union[str, Path]) -> str: """Extract display name from file path Args: file_path: Path to the file (str or Path object) Returns: str: Display name extracted from filename, or "Custom Sound" if empty """ path = Path(file_path) name = path.stem.replace("_", " ").replace("-", " ").title() return name if name.strip() else _("Custom Sound") drum-machine-2.2.0/src/window.py000066400000000000000000000343261514070543000165430ustar00rootroot00000000000000# window.py # # Copyright 2025 revisto # # 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, 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 . # # SPDX-License-Identifier: GPL-3.0-or-later import os import logging from typing import Optional import gi gi.require_version("Gtk", "4.0") gi.require_version("Adw", "1") from gi.repository import Adw, Gtk, GLib, Gio from gettext import gettext as _ from .config.constants import NUM_TOGGLES, DEFAULT_BPM, DEFAULT_VOLUME from .handlers.file_dialog_handler import FileDialogHandler from .handlers.window_actions import WindowActionHandler from .handlers.drag_drop_handler import DragDropHandler from .services.drum_machine_service import DrumMachineService from .services.save_changes_service import SaveChangesService from .services.sound_service import SoundService from .services.audio_export_service import AudioExportService from .services.ui_helper import UIHelper from .ui.drum_grid_builder import DrumGridBuilder @Gtk.Template(resource_path="/io/github/revisto/drum-machine/window.ui") class DrumMachineWindow(Adw.ApplicationWindow): __gtype_name__ = "DrumMachineWindow" menu_button = Gtk.Template.Child() outer_box = Gtk.Template.Child() toast_overlay = Gtk.Template.Child() bpm_spin_button = Gtk.Template.Child() volume_button = Gtk.Template.Child() clear_button = Gtk.Template.Child() play_pause_button = Gtk.Template.Child() drum_machine_box = Gtk.Template.Child() file_pattern_button = Gtk.Template.Child() export_audio_button = Gtk.Template.Child() def __init__(self, **kwargs) -> None: super().__init__(**kwargs) self._setup_services() self._setup_handlers() self._initialize_interface() def _setup_services(self) -> None: """Initialize all services""" self.application = self.get_application() bundled_sounds_dir = os.path.join( os.path.dirname(__file__), "..", "data", "drumkit" ) try: self.sound_service = SoundService(bundled_sounds_dir) self.sound_service.load_sounds() except Exception as e: logging.critical(f"Failed to initialize sound service: {e}") raise self.audio_export_service = AudioExportService(self) self.ui_helper = UIHelper(self) self.drum_machine_service = DrumMachineService( self, self.sound_service, self.ui_helper ) self.save_changes_service = SaveChangesService(self, self.drum_machine_service) def _setup_handlers(self) -> None: """Initialize UI handlers""" self.drum_grid_builder = DrumGridBuilder(self) self.action_handler = WindowActionHandler(self) self.file_dialog_handler = FileDialogHandler(self) self.drag_drop_handler = DragDropHandler(self) def _initialize_interface(self) -> None: """Initialize the complete interface""" # Build drum grid drum_interface = self.drum_grid_builder.build_drum_machine_interface() self.drum_machine_box.append(drum_interface) # Setup other components self.file_dialog_handler.setup_pattern_menu() self._connect_signals() self.action_handler.setup_actions() # Setup drag and drop self.drag_drop_handler.setup_drag_drop() # Initialize export button state self.update_export_button_sensitivity() def update_export_button_sensitivity(self) -> None: """Update the sensitivity of export and clear buttons based on pattern state""" has_active_beats = any( any(beats.values()) for beats in self.drum_machine_service.drum_parts_state.values() ) self.export_audio_button.set_sensitive(has_active_beats) self.clear_button.set_sensitive(has_active_beats) def _connect_signals(self) -> None: """Connect UI signals""" self.connect("close-request", self._on_close_request) self.bpm_spin_button.connect("value-changed", self.on_bpm_changed) self.volume_button.connect("value-changed", self.on_volume_changed) self.clear_button.connect("clicked", self.handle_clear) self.play_pause_button.connect("clicked", self.handle_play_pause) self.file_pattern_button.connect("clicked", self._on_open_file_clicked) self.export_audio_button.connect("clicked", self._on_export_audio_clicked) self.drum_machine_box.connect( "notify::css-classes", self._on_breakpoint_changed ) def _on_breakpoint_changed(self, box: Gtk.Box, gparam: object) -> None: """ Called when the css-classes property of the drum_machine_box changes. """ css_classes = box.get_css_classes() # Handle responsive layout for toggles (half-view) is_tiny = "half-view" in css_classes self.handle_layout_change(is_tiny=is_tiny) # Handle compact spacing for instrument list is_compact = "compact" in css_classes self.drum_grid_builder.update_drum_parts_spacing(is_compact=is_compact) def handle_layout_change(self, is_tiny: bool) -> None: """ Rebuilds the drum grid when the layout size changes. """ focus_beat_index = 0 old_beats_per_page = self.drum_machine_service.beats_per_page if is_tiny: # For smaller views, use half the number of toggles beats_per_page = NUM_TOGGLES // 2 else: beats_per_page = NUM_TOGGLES # Avoid rebuilding if the layout hasn't actually changed if self.drum_machine_service.beats_per_page == beats_per_page: return # Determine the correct beat to focus on if self.drum_machine_service.playing: focus_beat_index = self.drum_machine_service.playing_beat else: current_page = self.carousel.get_position() focus_beat_index = current_page * old_beats_per_page self.drum_machine_service.beats_per_page = beats_per_page self.drum_machine_service.update_total_beats() # Rebuild the grid with the new size. The builder will handle loading # the pattern. self.drum_grid_builder.rebuild_carousel(focus_beat_index=focus_beat_index) # Delegate methods to handlers def _on_open_file_clicked(self, button: Gtk.Button) -> None: self.file_dialog_handler.handle_open_file() def _on_save_pattern_clicked(self) -> None: self.file_dialog_handler.handle_save_pattern() def _on_export_audio_clicked(self, button: Gtk.Button) -> None: """Handle export audio button click""" self.file_dialog_handler.handle_export_audio() def scroll_carousel_to_page(self, page_index: int) -> None: """Scrolls the carousel to a specific page if auto-scroll is enabled.""" current_page = self.carousel.get_position() if current_page != page_index: self.carousel.scroll_to(self.carousel.get_nth_page(page_index), True) # Event handlers that need to stay in window def on_toggle_changed( self, toggle_button: Gtk.ToggleButton, part: str, index: int ) -> None: state = toggle_button.get_active() if state: self.drum_machine_service.drum_parts_state[part][index] = True else: self.drum_machine_service.drum_parts_state[part].pop(index, None) # Tell the service to recalculate the total pattern length self.drum_machine_service.update_total_beats() # Update export button sensitivity self.update_export_button_sensitivity() # Mark as unsaved when toggles change self.save_changes_service.mark_unsaved_changes(True) def on_bpm_changed(self, spin_button: Gtk.SpinButton) -> None: value = spin_button.get_value() self.drum_machine_service.set_bpm(value) # Update tooltip and accessibility with current BPM bpm_text = _("{} Beats per Minute (BPM)").format(int(value)) spin_button.set_tooltip_text(bpm_text) # Mark as unsaved when BPM changes self.save_changes_service.mark_unsaved_changes(True) def on_volume_changed(self, button: Gtk.VolumeButton, value: float) -> None: self.drum_machine_service.set_volume(value) # Update button tooltip to show current volume level volume_text = _("{:.0f}% Volume").format(value) button.set_tooltip_text(volume_text) def handle_clear(self, button: Gtk.Button) -> None: """Clear the pattern but keep samples""" self.drum_machine_service.clear_all_toggles() self.drum_machine_service.update_total_beats() self.drum_grid_builder.reset_carousel_pages() self.update_export_button_sensitivity() self.save_changes_service.mark_unsaved_changes(False) def reset_to_defaults(self) -> None: """Clear pattern and restore default samples, BPM, and volume""" self.drum_machine_service.clear_all_toggles() self.sound_service.drum_part_manager.reset_to_defaults() self.sound_service.reload_sounds() self.drum_machine_service.drum_parts_state = ( self.drum_machine_service.create_empty_drum_parts_state() ) self.drum_machine_service.set_bpm(DEFAULT_BPM) self.drum_machine_service.set_volume(DEFAULT_VOLUME) self.drum_grid_builder.rebuild_drum_parts_column() self.drum_grid_builder.rebuild_carousel() self.drum_machine_service.update_total_beats() self.drum_grid_builder.reset_carousel_pages() self.bpm_spin_button.set_value(DEFAULT_BPM) self.volume_button.set_value(DEFAULT_VOLUME) self.update_export_button_sensitivity() self.save_changes_service.mark_unsaved_changes(False) def handle_play_pause(self, button: Gtk.Button) -> None: if self.drum_machine_service.playing: button.set_icon_name("media-playback-start-symbolic") button.set_tooltip_text(_("Play")) self.drum_machine_service.stop() else: button.set_icon_name("media-playback-pause-symbolic") button.set_tooltip_text(_("Pause")) self.drum_machine_service.play() def on_drum_part_button_clicked(self, button: Gtk.Button, part: str) -> None: self.drum_machine_service.preview_drum_part(part) def _on_right_click_released( self, gesture_click: Gtk.GestureClick, n_press: int, x: float, y: float, toggle_button: Gtk.ToggleButton, ) -> None: toggle_button.set_active(not toggle_button.props.active) toggle_button.emit("toggled") def _on_close_request(self, *args) -> bool: self.action_handler.on_quit_action(None, None) return True def _save_and_close(self) -> None: self.file_dialog_handler.show_save_dialog(self.cleanup_and_destroy) def cleanup(self) -> None: """Stop playback and cleanup resources""" if self.drum_machine_service.playing: self.drum_machine_service.stop() self.drum_machine_service.playing = False def cleanup_and_destroy(self) -> None: self.cleanup() self.destroy() def show_toast( self, message: str, open_file: bool = False, file_path: Optional[str] = None ) -> None: """Show a toast notification with optional action button""" toast = Adw.Toast(title=message, timeout=5) if open_file and file_path: # Setup action if not already done self._setup_toast_actions() # Set action toast.set_action_name("win.open-file") toast.set_action_target_value(GLib.Variant.new_string(file_path)) toast.set_button_label(_("Open")) self.toast_overlay.add_toast(toast) def _setup_toast_actions(self) -> None: """Setup toast action handlers""" if not hasattr(self, "_open_action"): action = Gio.SimpleAction.new("open-file", GLib.VariantType.new("s")) action.connect("activate", self._open_file) self.add_action(action) self._open_action = action def _open_file(self, action: Gio.SimpleAction, parameter: GLib.Variant) -> None: """Open file with default app""" file_path = parameter.get_string() Gio.AppInfo.launch_default_for_uri(f"file://{file_path}", None) def show_added_toast(self, name: str) -> None: self.show_toast(_("Added: {}").format(name)) def add_new_drum_part( self, file_path: str, name: str, show_success_toast: bool = True ) -> bool: """Add a new drum part""" result = self.drum_machine_service.add_new_drum_part(file_path, name) if result: if show_success_toast: self.show_added_toast(name) self.save_changes_service.mark_unsaved_changes(True) logging.info(f"Added custom drum part: {name}") return True else: logging.error(f"Failed to add custom drum part: {name} from {file_path}") self.show_toast(_("Failed to add custom sound")) return False def replace_drum_part(self, drum_id: str, file_path: str, name: str) -> bool: """Replace an existing drum part""" result = self.drum_machine_service.replace_drum_part(drum_id, file_path, name) if result: self.show_toast(_("Replaced drum with: {}").format(name)) # Update button state to reflect new file availability self.drum_grid_builder.update_drum_button(drum_id) self.save_changes_service.mark_unsaved_changes(True) logging.info(f"Replaced drum part {drum_id} with: {name}") return True else: logging.error(f"Failed to replace drum part {drum_id} with {file_path}") self.show_toast(_("Failed to replace drum sound")) return False drum-machine-2.2.0/src/window.ui000066400000000000000000000270571514070543000165330ustar00rootroot00000000000000
_Add Samples… win.add_samples _Save Pattern… win.save_pattern
_Reset to Defaults win.reset_to_defaults
_Keyboard Shortcuts win.show-help-overlay _About Drum Machine app.about