From 28aae5308dc5f44e389bfe368d9824d1b41de800 Mon Sep 17 00:00:00 2001 From: thevickypedia Date: Wed, 6 Sep 2023 23:02:59 -0500 Subject: [PATCH] Clean up and update README.md Release beta version --- .gitignore | 109 +------------- MANIFEST | 14 -- README.md | 93 ++++++------ README.rst | 92 ------------ docs/Makefile | 20 --- docs/conf.py | 154 -------------------- docs/drivers.rst | 102 ------------- docs/engine.rst | 323 ------------------------------------------ docs/index.rst | 26 ---- docs/install.rst | 93 ------------ docs/support.rst | 10 -- example/voicefile.mp3 | Bin 51016 -> 0 bytes makefile | 13 -- pyproject.toml | 10 +- requirements.txt | 12 -- 15 files changed, 61 insertions(+), 1010 deletions(-) delete mode 100644 MANIFEST delete mode 100644 README.rst delete mode 100644 docs/Makefile delete mode 100644 docs/conf.py delete mode 100644 docs/drivers.rst delete mode 100644 docs/engine.rst delete mode 100644 docs/index.rst delete mode 100644 docs/install.rst delete mode 100644 docs/support.rst delete mode 100644 example/voicefile.mp3 delete mode 100644 makefile delete mode 100644 requirements.txt diff --git a/.gitignore b/.gitignore index b684ff1..201cedf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,108 +1,9 @@ -# Byte-compiled / optimized / DLL files -__pycache__/ -*.py[cod] -*$py.class -.DS_Store +# python generated .idea +.DS_Store +__pycache__ +.pytest_cache +venv -# C extensions -*.so - -# Distribution / packaging -.Python -env/ -build/ -develop-eggs/ dist/ -downloads/ -eggs/ -.eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -wheels/ *.egg-info/ -.installed.cfg -*.egg - -# PyInstaller -# Usually these files are written by a python script from a template -# before PyInstaller builds the exe, so as to inject date/other infos into it. -*.manifest -*.spec - -# Installer logs -pip-log.txt -pip-delete-this-directory.txt - -# Unit test / coverage reports -htmlcov/ -.tox/ -.coverage -.coverage.* -.cache -nosetests.xml -coverage.xml -*.cover -.hypothesis/ - -# Translations -*.mo -*.pot - -# Django stuff: -*.log -local_settings.py - -# Flask stuff: -instance/ -.webassets-cache - -# Scrapy stuff: -.scrapy - -# Sphinx documentation -docs/_build/ - -# PyBuilder -target/ - -# Jupyter Notebook -.ipynb_checkpoints - -# pyenv -.python-version - -# celery beat schedule file -celerybeat-schedule - -# SageMath parsed files -*.sage.py - -# dotenv -.env - -# virtualenv -.venv -venv/ -ENV/ - -# Spyder project settings -.spyderproject -.spyproject - -# Rope project settings -.ropeproject - -# mkdocs documentation -/site - -# mypy -.mypy_cache/ -docs/make.bat -docs/make.bat - -# vscode -.vscode/ diff --git a/MANIFEST b/MANIFEST deleted file mode 100644 index 5e471d7..0000000 --- a/MANIFEST +++ /dev/null @@ -1,14 +0,0 @@ -# file GENERATED by distutils, do NOT edit -setup.cfg -setup.py -pyttsx3\__init__.py -pyttsx3\driver.py -pyttsx3\engine.py -pyttsx3\six.py -pyttsx3\voice.py -pyttsx3\drivers\__init__.py -pyttsx3\drivers\_espeak.py -pyttsx3\drivers\dummy.py -pyttsx3\drivers\espeak.py -pyttsx3\drivers\nsss.py -pyttsx3\drivers\sapi5.py diff --git a/README.md b/README.md index b83921c..118eb8b 100644 --- a/README.md +++ b/README.md @@ -4,33 +4,43 @@

Offline Text To Speech (TTS) converter for Python

-[![Downloads](https://pepy.tech/badge/pyttsx3)](https://pepy.tech/project/pyttsx3) ![Downloads](https://pepy.tech/badge/pyttsx3/week) [![](https://img.shields.io/github/languages/code-size/nateshmbhat/pyttsx3.svg?style=plastic)](https://github.com/nateshmbhat/pyttsx3) [![](https://img.shields.io/github/license/nateshmbhat/pyttsx3?style=plastic)](https://github.com/nateshmbhat/pyttsx3) [![](https://img.shields.io/pypi/v/pyttsx3.svg?style=plastic)](https://pypi.org/project/pyttsx3/) [![](https://img.shields.io/github/languages/top/nateshmbhat/pyttsx3.svg?style=plastic)](https://github.com/nateshmbhat/pyttsx3) [![](https://img.shields.io/badge/author-nateshmbhat-green.svg)](https://github.com/nateshmbhat) +[![](https://pepy.tech/badge/py3-tts)](https://pepy.tech/badge/py3-tts) +[![](https://pepy.tech/badge/py3-tts/month)](https://pepy.tech/badge/py3-tts/month) +[![](https://img.shields.io/github/languages/code-size/thevickypedia/py3-tts.svg?style=plastic)](https://github.com/thevickypedia/py3-tts) +[![](https://img.shields.io/github/license/thevickypedia/py3-tts?style=plastic)](https://github.com/thevickypedia/py3-tts) -`pyttsx3` is a text-to-speech conversion library in Python. Unlike alternative libraries, **it works offline**. +[![](https://img.shields.io/pypi/v/py3-tts.svg?style=plastic)](https://pypi.org/project/py3-tts/) -Buy me a coffee 😇Buy me a coffee 😇 +[![](https://img.shields.io/github/languages/top/thevickypedia/py3-tts.svg?style=plastic)](https://github.com/thevickypedia/py3-tts) -## Installation : +[![](https://img.shields.io/badge/author-thevickypedia-green.svg)](https://github.com/thevickypedia) +`py3-tts` is a text-to-speech conversion library in Python. Unlike alternative libraries, **it works offline**. - pip install py3-tts +## Installation -> If you get installation errors , make sure you first upgrade your wheel version using : -`pip install --upgrade wheel` +```shell +pip install py3-tts +``` + +> If you get installation errors, make sure you first upgrade your wheel version using -### Linux installation requirements : +```shell +pip install --upgrade wheel +``` -+ If you are on a linux system and if the voice output is not working , then : +### Linux installation requirements - Install espeak , ffmpeg and libespeak1 as shown below: ++ If you are on a linux system and if the voice output is not working, - ``` - sudo apt update && sudo apt install espeak ffmpeg libespeak1 - ``` + Install `espeak`, `ffmpeg` and `libespeak1` as shown below + ```shell + sudo apt update && sudo apt install espeak ffmpeg libespeak1 + ``` -## Features : +## Features - ✨Fully **OFFLINE** text to speech conversion - 🎈 Choose among different voices installed in your system @@ -39,11 +49,11 @@ - 📀 Save the speech audio as a file - ❤️ Simple, powerful, & intuitive API +## Usage -## Usage : - -```python3 +```python import pyttsx3 + engine = pyttsx3.init() engine.say("I will speak this text") engine.runAndWait() @@ -51,40 +61,39 @@ engine.runAndWait() **Single line usage with speak function with default options** -```python3 +```python import pyttsx3 + pyttsx3.speak("I will speak this text") ``` - -**Changing Voice , Rate and Volume :** +**Changing Voice, Rate and Volume** -```python3 +```python import pyttsx3 -engine = pyttsx3.init() # object creation -""" RATE""" -rate = engine.getProperty('rate') # getting details of current speaking rate -print (rate) #printing current voice rate -engine.setProperty('rate', 125) # setting up new voice rate +engine = pyttsx3.init() # object creation +""" RATE""" +rate = engine.getProperty('rate') # getting details of current speaking rate +print(rate) # printing current voice rate +engine.setProperty('rate', 125) # setting up new voice rate """VOLUME""" -volume = engine.getProperty('volume') #getting to know current volume level (min=0 and max=1) -print (volume) #printing current volume level -engine.setProperty('volume',1.0) # setting up volume level between 0 and 1 +volume = engine.getProperty('volume') # getting to know current volume level (min=0 and max=1) +print(volume) # printing current volume level +engine.setProperty('volume', 1.0) # setting up volume level between 0 and 1 """VOICE""" -voices = engine.getProperty('voices') #getting details of current voice -#engine.setProperty('voice', voices[0].id) #changing index, changes voices. o for male -engine.setProperty('voice', voices[1].id) #changing index, changes voices. 1 for female +voices = engine.getProperty('voices') # getting details of current voice +# engine.setProperty('voice', voices[0].id) #changing index, changes voices. o for male +engine.setProperty('voice', voices[1].id) # changing index, changes voices. 1 for female engine.say("Hello World!") engine.say('My current speaking rate is ' + str(rate)) engine.runAndWait() engine.stop() - """Saving Voice to a file""" # On linux make sure that 'espeak' and 'ffmpeg' are installed engine.save_to_file('Hello World', 'test.mp3') @@ -92,15 +101,11 @@ engine.runAndWait() ``` - - - -### **Full documentation of the Library** +### Full documentation of the Library https://pyttsx3.readthedocs.io/en/latest/ - -#### Included TTS engines: +#### Included TTS engines * sapi5 * nsss @@ -108,8 +113,12 @@ https://pyttsx3.readthedocs.io/en/latest/ Feel free to wrap another text-to-speech engine for use with ``pyttsx3``. -### Project Links : +### Project Links -* PyPI (https://pypi.python.org) -* GitHub (https://github.com/nateshmbhat/pyttsx3) +* PyPI (https://pypi.org/project/py3-tts/) +* GitHub (https://github.com/thevickypedia/py3-tts) * Full Documentation (https://pyttsx3.readthedocs.org) + +### Credits + +**[nateshmbhat](https://github.com/nateshmbhat)** for the original code [pyttsx3](https://pypi.org/project/pyttsx3/) diff --git a/README.rst b/README.rst deleted file mode 100644 index e9de944..0000000 --- a/README.rst +++ /dev/null @@ -1,92 +0,0 @@ -***************************************************** -pyttsx3 (offline TTS for Python 3) -***************************************************** - -``pyttsx3`` is a text-to-speech conversion library in Python. Unlike alternative libraries, it works offline, and is compatible with both Python 2 and 3. - -Installation -************ -:: - - pip install py3-tts - - -> If you get installation errors, make sure you first upgrade your wheel version using : -`pip install --upgrade wheel` - -**Linux installation requirements :** -##################################### - -+ If you are on a Linux system and if the voice output is not working , then : - -Install espeak, ffmpeg, and libespeak1 as shown below: - -:: - - sudo apt update && sudo apt install espeak ffmpeg libespeak1 - - -Usage : -************ -:: - - import pyttsx3 - engine = pyttsx3.init() - engine.say("I will speak this text") - engine.runAndWait() - - -**Changing Voice, Rate and Volume :** - -:: - - import pyttsx3 - engine = pyttsx3.init() # object creation - - """ RATE""" - rate = engine.getProperty('rate') # getting details of current speaking rate - print (rate) # printing current voice rate - engine.setProperty('rate', 125) # setting up new voice rate - - - """VOLUME""" - volume = engine.getProperty('volume') # getting to know current volume level (min=0 and max=1) - print (volume) # printing current volume level - engine.setProperty('volume',1.0) # setting up volume level between 0 and 1 - - """VOICE""" - voices = engine.getProperty('voices') # getting details of current voice - #engine.setProperty('voice', voices[0].id) # changing index, changes voices. o for male - engine.setProperty('voice', voices[1].id) # changing index, changes voices. 1 for female - - engine.say("Hello World!") - engine.say('My current speaking rate is ' + str(rate)) - engine.runAndWait() - engine.stop() - - """Saving Voice to a file""" - # On Linux make sure that 'espeak' and 'ffmpeg' are installed - engine.save_to_file('Hello World', 'test.mp3') - engine.runAndWait() - - -**Full documentation of the Library** -##################################### - -https://pyttsx3.readthedocs.io/en/latest/ - - -Included TTS engines: -********************* -* sapi5 -* nsss -* espeak - -Feel free to wrap another text-to-speech engine for use with ``pyttsx3``. - -Project Links: -************** - -* PyPI (https://pypi.python.org) -* GitHub (https://github.com/thevickypedia/pyttsx3) -* Full Documentation (https://pyttsx3.readthedocs.org) diff --git a/docs/Makefile b/docs/Makefile deleted file mode 100644 index ed80683..0000000 --- a/docs/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -# Minimal makefile for Sphinx documentation -# - -# You can set these variables from the command line. -SPHINXOPTS = -SPHINXBUILD = python3 -msphinx -SPHINXPROJ = pyttsx3 -SOURCEDIR = . -BUILDDIR = _build - -# Put it first so that "make" without argument is like "make help". -help: - @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) - -.PHONY: help Makefile - -# Catch-all target: route all unknown targets to Sphinx using the new -# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). -%: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/conf.py b/docs/conf.py deleted file mode 100644 index 74fd7e8..0000000 --- a/docs/conf.py +++ /dev/null @@ -1,154 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -# -# pyttsx3 documentation build configuration file, created by -# sphinx-quickstart on Sun Jun 25 11:19:31 2017. -# -# This file is execfile()d with the current directory set to its -# containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -# -# import os -# import sys -# sys.path.insert(0, os.path.abspath('.')) - - -# -- General configuration ------------------------------------------------ - -# If your documentation needs a minimal Sphinx version, state it here. -# -# needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -extensions = ['sphinx.ext.autodoc'] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix(es) of source filenames. -# You can specify multiple suffix as a list of string: -# -# source_suffix = ['.rst', '.md'] -source_suffix = '.rst' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = 'pyttsx3' -copyright = '2017, Natesh M Bhat' -author = 'Natesh M Bhat' - -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -# -# The short X.Y version. -version = '2.6' -# The full version, including alpha/beta/rc tags. -release = '2.6' - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -# -# This is also used if you do content translation via gettext catalogs. -# Usually you set "language" from the command line for these cases. -language = None - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -# This patterns also effect to html_static_path and html_extra_path -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - -# If true, `todo` and `todoList` produce output, else they produce nothing. -todo_include_todos = False - - -# -- Options for HTML output ---------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -# -html_theme = 'alabaster' - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -# -# html_theme_options = {} - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] - - -# -- Options for HTMLHelp output ------------------------------------------ - -# Output file base name for HTML help builder. -htmlhelp_basename = 'pyttsx3doc' - - -# -- Options for LaTeX output --------------------------------------------- - -latex_elements = { - # The paper size ('letterpaper' or 'a4paper'). - # - # 'papersize': 'letterpaper', - - # The font size ('10pt', '11pt' or '12pt'). - # - # 'pointsize': '10pt', - - # Additional stuff for the LaTeX preamble. - # - # 'preamble': '', - - # Latex figure (float) alignment - # - # 'figure_align': 'htbp', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, -# author, documentclass [howto, manual, or own class]). -latex_documents = [ - (master_doc, 'pyttsx3.tex', 'pyttsx3 Documentation', - 'Natesh M Bhat', 'manual'), -] - - -# -- Options for manual page output --------------------------------------- - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [ - (master_doc, 'pyttsx3', 'pyttsx3 Documentation', - [author], 1) -] - - -# -- Options for Texinfo output ------------------------------------------- - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -texinfo_documents = [ - (master_doc, 'pyttsx3', 'pyttsx3 Documentation', - author, 'pyttsx3', 'One line description of project.', - 'Miscellaneous'), -] diff --git a/docs/drivers.rst b/docs/drivers.rst deleted file mode 100644 index cb9ace9..0000000 --- a/docs/drivers.rst +++ /dev/null @@ -1,102 +0,0 @@ -Implementing drivers --------------------- - -You can implement new drivers for the :mod:`pyttsx3.Engine` by: - -#. Creating a Python module with the name of your new driver. -#. Implementing the required driver factory function and class in your module. -#. Using methods on a :class:`pyttsx3.driver.DriverProxy` instance provided by the :class:`pyttsx3.Engine` to control the event queue and notify applications about events. - -The Driver interface -~~~~~~~~~~~~~~~~~~~~ - -All drivers must implement the following factory function and driver interface. - -.. module:: pyttsx3.drivers - :synopsis: The package containing the available driver implementations - -.. function:: buildDriver(proxy : pyttsx3.driver.DriverProxy) -> pyttsx3.drivers.DriverDelegate - - Instantiates delegate subclass declared in this module. - - :param proxy: Proxy instance provided by a :class:`pyttsx3.Engine` instance. - -.. class:: DriverDelegate - - .. note:: The :class:`DriverDelegate` class is not actually declared in :mod:`pyttsx3.drivers` and cannot serve as a base class. It is only here for the purpose of documenting the interface all drivers must implement. - - .. method:: __init__(proxy : pyttsx3.drivers.DriverProxy, *args, **kwargs) -> None - - Constructor. Must store the proxy reference. - - :param proxy: Proxy instance provided by the :func:`buildDriver` function. - - .. method:: destroy() -> - - Optional. Invoked by the :class:`pyttsx3.driver.DriverProxy` when it is being destroyed so this delegate can clean up any synthesizer resources. If not implemented, the proxy proceeds safely. - - .. method:: endLoop() -> None - - Immediately ends a running driver event loop. - - .. method:: getProperty(name : string) -> object - - Immediately gets the named property value. At least those properties listed in the :meth:`pyttsx3.Engine.getProperty` documentation must be supported. - - :param name: Name of the property to query. - :return: Value of the property at the time of this invocation. - - .. method:: say(text : unicode, name : string) -> None - - Immediately speaks an utterance. The speech must be output according to the current property values applied at the time of this invocation. Before this method returns, it must invoke :meth:`pyttsx3.driver.DriverProxy.setBusy` with value :const:`True` to stall further processing of the command queue until the output completes or is interrupted. - - This method must trigger one and only one `started-utterance` notification when output begins, one `started-word` notification at the start of each word in the utterance, and a `finished-utterance` notification when output completes. - - :param text: Text to speak. - :param name: Name to associate with the utterance. Included in notifications about this utterance. - - .. method:: setProperty(name : string, value : object) -> None - - Immediately sets the named property value. At least those properties listed in the :meth:`pyttsx3.Engine.setProperty` documentation must be supported. After setting the property, the driver must invoke :meth:`pyttsx3.driver.DriverProxy.setBusy` with value :const:`False` to pump the command queue. - - :param name: Name of the property to change. - :param value: Value to set. - - .. method:: startLoop() - - Immediately starts an event loop. The loop is responsible for sending notifications about utterances and pumping the command queue by using methods on the :class:`pyttsx3.driver.DriverProxy` object given to the factory function that created this object. - - .. method:: stop() - - Immediately stops the current utterance output. This method must trigger a `finished-utterance` notification if called during on-going output. It must trigger no notification if there is no ongoing output. - - After stopping the output and sending any required notification, the driver must invoke :meth:`pyttsx3.driver.DriverProxy.setBusy` with value :const:`False` to pump the command queue. - -The DriverProxy interface -~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. module:: pyttsx3.driver - :synopsis: The module containing the driver proxy implementation - -The :func:`pyttsx3.drivers.buildDriver` factory receives an instance of a :class:`DriverProxy` class and provides it to the :class:`pyttsx3.drivers.DriverDelegate` it constructs. The driver delegate can invoke the following public methods on the proxy instance. All other public methods found in the code are reserved for use by an :class:`pyttsx3.Engine` instance. - -.. class:: DriverProxy - - .. method:: isBusy() -> bool - - Gets if the proxy is busy and cannot process the next command in the queue or not. - - :return: True means busy, False means idle. - - .. method:: notify(topic : string, **kwargs) -> None - - Fires a notification. - - :param topic: The name of the notification. - :kwargs: Name/value pairs associated with the topic. - - .. method:: setBusy(busy : bool) -> None - - Sets the proxy to busy so it cannot continue to pump the command queue or idle so it can process the next command. - - :param busy: True to set busy, false to set idle diff --git a/docs/engine.rst b/docs/engine.rst deleted file mode 100644 index a2e1417..0000000 --- a/docs/engine.rst +++ /dev/null @@ -1,323 +0,0 @@ -.. module:: pyttsx3 - :synopsis: The root pyttsx3 package defining the engine factory function - -Using pyttsx3 ------------- - -An application invokes the :func:`pyttsx3.init` factory function to get a reference to a :class:`pyttsx3.Engine` instance. During construction, the engine initializes a :class:`pyttsx3.driver.DriverProxy` object responsible for loading a speech engine driver implementation from the :mod:`pyttsx3.drivers` module. After construction, an application uses the engine object to register and unregister event callbacks; produce and stop speech; get and set speech engine properties; and start and stop event loops. - -The Engine factory -~~~~~~~~~~~~~~~~~~ - -.. function:: init([driverName : string, debug : bool]) -> pyttsx3.Engine - - Gets a reference to an engine instance that will use the given driver. If the requested driver is already in use by another engine instance, that engine is returned. Otherwise, a new engine is created. - - :param driverName: Name of the :mod:`pyttsx3.drivers` module to load and use. Defaults to the best available driver for the platform, currently: - - * `sapi5` - SAPI5 on Windows - * `nsss` - NSSpeechSynthesizer on Mac OS X - * `espeak` - eSpeak on every other platform - - :param debug: Enable debug output or not. - :raises ImportError: When the requested driver is not found - :raises RuntimeError: When the driver fails to initialize - -The Engine interface -~~~~~~~~~~~~~~~~~~~~ - -.. module:: pyttsx3.engine - :synopsis: The module containing the engine implementation - -.. class:: Engine - - Provides application access to text-to-speech synthesis. - - .. method:: connect(topic : string, cb : callable) -> dict - - Registers a callback for notifications on the given topic. - - :param topic: Name of the event to subscribe to. - :param cb: Function to invoke when the event fires. - :return: A token that the caller can use to unsubscribe the callback later. - - The following are the valid topics and their callback signatures. - - .. describe:: started-utterance - - Fired when the engine begins speaking an utterance. The associated callback must have the following signature. - - .. function:: onStartUtterance(name : string) -> None - - :param name: Name associated with the utterance. - - .. describe:: started-word - - Fired when the engine begins speaking a word. The associated callback must have the following signature. - - .. function:: onStartWord(name : string, location : integer, length : integer) - - :param name: Name associated with the utterance. - - .. describe:: finished-utterance - - Fired when the engine finishes speaking an utterance. The associated callback must have the following signature. - - .. function:: onFinishUtterance(name : string, completed : bool) -> None - - :param name: Name associated with the utterance. - :param completed: True if the utterance was output in its entirety or not. - - .. describe:: error - - Fired when the engine encounters an error. The associated callback must have the following signature. - - .. function:: onError(name : string, exception : Exception) -> None - - :param name: Name associated with the utterance that caused the error. - :param exception: Exception that was raised. - - .. method:: disconnect(token : dict) - - Unregisters a notification callback. - - :param token: Token returned by :meth:`connect` associated with the callback to be disconnected. - - .. method:: endLoop() -> None - - Ends a running event loop. If :meth:`startLoop` was called with `useDriverLoop` set to True, this method stops processing of engine commands and immediately exits the event loop. If it was called with False, this method stops processing of engine commands, but it is up to the caller to end the external event loop it started. - - :raises RuntimeError: When the loop is not running - - .. method:: getProperty(name : string) -> object - - Gets the current value of an engine property. - - :param name: Name of the property to query. - :return: Value of the property at the time of this invocation. - - The following property names are valid for all drivers. - - .. describe:: rate - - Integer speech rate in words per minute. Defaults to 200 word per minute. - - .. describe:: voice - - String identifier of the active voice. - - .. describe:: voices - - List of :class:`pyttsx3.voice.Voice` descriptor objects. - - .. describe:: volume - - Floating point volume in the range of 0.0 to 1.0 inclusive. Defaults to 1.0. - - .. method:: isBusy() -> bool - - Gets if the engine is currently busy speaking an utterance or not. - - :return: True if speaking, false if not. - - .. method:: runAndWait() -> None - - Blocks while processing all currently queued commands. Invokes callbacks for engine notifications appropriately. Returns when all commands queued before this call are emptied from the queue. - - .. method:: say(text : unicode, name : string) -> None - - Queues a command to speak an utterance. The speech is output according to the properties set before this command in the queue. - - :param text: Text to speak. - :param name: Name to associate with the utterance. Included in notifications about this utterance. - - .. method:: setProperty(name, value) -> None - - Queues a command to set an engine property. The new property value affects all utterances queued after this command. - - :param name: Name of the property to change. - :param value: Value to set. - - The following property names are valid for all drivers. - - .. describe:: rate - - Integer speech rate in words per minute. - - .. describe:: voice - - String identifier of the active voice. - - .. describe:: volume - - Floating point volume in the range of 0.0 to 1.0 inclusive. - - .. method:: startLoop([useDriverLoop : bool]) -> None - - Starts running an event loop during which queued commands are processed and notifications are fired. - - :param useDriverLoop: True to use the loop provided by the selected driver. False to indicate the caller will enter its own loop after invoking this method. The caller's loop must pump events for the driver in use so that pyttsx3 notifications are delivered properly (e.g., SAPI5 requires a COM message pump). Defaults to True. - - .. method:: stop() -> None - - Stops the current utterance and clears the command queue. - -The Voice metadata -~~~~~~~~~~~~~~~~~~ - -.. module:: pyttsx3.voice - :synopsis: The module containing the voice structure implementation - -.. class:: Voice - - Contains information about a speech synthesizer voice. - - .. attribute:: age - - Integer age of the voice in years. Defaults to :const:`None` if unknown. - - .. attribute:: gender - - String gender of the voice: `male`, `female`, or `neutral`. Defaults to :const:`None` if unknown. - - .. attribute:: id - - String identifier of the voice. Used to set the active voice via :meth:`pyttsx3.engine.Engine.setPropertyValue`. This attribute is always defined. - - .. attribute:: languages - - List of string languages supported by this voice. Defaults to an empty list of unknown. - - .. attribute:: name - - Human readable name of the voice. Defaults to :const:`None` if unknown. - -Examples -~~~~~~~~ - -Speaking text -############# - -.. sourcecode:: python - - import pyttsx3 - engine = pyttsx3.init() - engine.say('Sally sells seashells by the seashore.') - engine.say('The quick brown fox jumped over the lazy dog.') - engine.runAndWait() - - -Saving voice to a file -###################### - -.. sourcecode:: python - - import pyttsx3 - engine = pyttsx3.init() - engine.save_to_file('Hello World' , 'test.mp3') - engine.runAndWait() - - - -Listening for events -#################### - -.. sourcecode:: python - - import pyttsx3 - def onStart(name): - print 'starting', name - def onWord(name, location, length): - print 'word', name, location, length - def onEnd(name, completed): - print 'finishing', name, completed - engine = pyttsx3.init() - engine.connect('started-utterance', onStart) - engine.connect('started-word', onWord) - engine.connect('finished-utterance', onEnd) - engine.say('The quick brown fox jumped over the lazy dog.') - engine.runAndWait() - -Interrupting an utterance -######################### - -.. sourcecode:: python - - import pyttsx3 - def onWord(name, location, length): - print 'word', name, location, length - if location > 10: - engine.stop() - engine = pyttsx3.init() - engine.connect('started-word', onWord) - engine.say('The quick brown fox jumped over the lazy dog.') - engine.runAndWait() - -Changing voices -############### - -.. sourcecode:: python - - engine = pyttsx3.init() - voices = engine.getProperty('voices') - for voice in voices: - engine.setProperty('voice', voice.id) - engine.say('The quick brown fox jumped over the lazy dog.') - engine.runAndWait() - -Changing speech rate -#################### - -.. sourcecode:: python - - engine = pyttsx3.init() - rate = engine.getProperty('rate') - engine.setProperty('rate', rate+50) - engine.say('The quick brown fox jumped over the lazy dog.') - engine.runAndWait() - -Changing volume -############### - -.. sourcecode:: python - - engine = pyttsx3.init() - volume = engine.getProperty('volume') - engine.setProperty('volume', volume-0.25) - engine.say('The quick brown fox jumped over the lazy dog.') - engine.runAndWait() - -Running a driver event loop -########################### - -.. sourcecode:: python - - engine = pyttsx3.init() - def onStart(name): - print 'starting', name - def onWord(name, location, length): - print 'word', name, location, length - def onEnd(name, completed): - print 'finishing', name, completed - if name == 'fox': - engine.say('What a lazy dog!', 'dog') - elif name == 'dog': - engine.endLoop() - engine = pyttsx3.init() - engine.connect('started-utterance', onStart) - engine.connect('started-word', onWord) - engine.connect('finished-utterance', onEnd) - engine.say('The quick brown fox jumped over the lazy dog.', 'fox') - engine.startLoop() - -Using an external event loop -############################ - -.. sourcecode:: python - - engine = pyttsx3.init() - engine.say('The quick brown fox jumped over the lazy dog.', 'fox') - engine.startLoop(False) - # engine.iterate() must be called inside externalLoop() - externalLoop() - engine.endLoop() \ No newline at end of file diff --git a/docs/index.rst b/docs/index.rst deleted file mode 100644 index 33f9f50..0000000 --- a/docs/index.rst +++ /dev/null @@ -1,26 +0,0 @@ -================================== -pyttsx3 - Text-to-speech x-platform -================================== - -This documentation describes the pyttsx3 Python package v |release| and was rendered on |today|. - -.. rubric:: Table of Contents - -.. toctree:: - :maxdepth: 2 - - support - engine - drivers - - - -.. rubric:: Project Links - -* `Project home page at GitHub`__ -* `Package listing in PyPI`__ -* `Documentation at ReadTheDocs`__ - -__ https://github.com/thevickypedia/py3-tts -__ http://pypi.python.org/pypi/py3-tts -__ https://pyttsx3.readthedocs.org/ \ No newline at end of file diff --git a/docs/install.rst b/docs/install.rst deleted file mode 100644 index 813919c..0000000 --- a/docs/install.rst +++ /dev/null @@ -1,93 +0,0 @@ -Installing pyttsx3 ------------------ - -Tested versions -~~~~~~~~~~~~~~~ - -Version |version| of pyttsx3 includes drivers for the following text-to-speech synthesizers. Only operating systems on which a driver is tested and known to work are listed. The drivers may work on other systems. - -* SAPI5 on Windows XP, Windows Vista, and Windows 7 -* NSSpeechSynthesizer on Mac OS X 10.5 (Leopard), 10.6 (Snow Leopard), 10.7 (Lion), and 10.8 (Mountain Lion). -* `espeak`_ on 32-bit Ubuntu Desktop Edition 8.10 (Intrepid), 9.04 (Jaunty), 9.10 (Karmic), and 12.04 (Precise). - -The :func:`pyttsx3.init` documentation explains how to select a specific synthesizer by name as well as the default for each platform. - -Using pip to install system-wide -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -If you have pip installed, you can use it to install py3-tts in the system site-packages folder. - -On Windows -########## - -First install the `pywin32-extensions `_ package using its Windows installer. Then use pip to install py3-tts. - -.. code-block:: bash - - $ pip install py3-tts - -On OSX or Linux -############### - -.. code-block:: bash - - $ sudo pip install py3-tts - -Using pip to install in a virtualenv -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -If you have virtualenv_ installed with pip_, you can use pip to install a copy of pyttsx3 in the virtual environment folder. - -On Windows -########## - -You'll need to install the `pywin32-extensions `_ package system-wide using its Windows installer. Then you'll need to give your virtualenv access to the system site-packages in order to install py3-tts. - -.. code-block:: bash - - $ virtualenv --system-site-packages myproj - New python executable in myproj/bin/python - Installing setuptools............done. - Installing pip...............done. - $ myproj\Scripts\activate - (myproj)$ pip install py3-tts - -On OSX -###### - -Unless you wish to compile your own version of pyobjc (a lengthy process), you will need to give your virtualenv access to the system site-packages folder. - -.. code-block:: bash - - $ virtualenv --system-site-packages myproj - New python executable in myproj/bin/python - Installing setuptools............done. - Installing pip...............done. - $ . myproj/bin/activate - (myproj)$ pip install py3-tts - ... - Successfully installed pyttsx3 - Cleaning up... - -On Linux -######## - -pyttsx3 requires no Python dependencies on Linux. You can cut-off the pyttsx3 virtualenv from the system site-packages. - -code-block:: bash - - $ virtualenv --no-site-packages myproj - New python executable in myproj/bin/python - Installing setuptools............done. - Installing pip...............done. - $ . myproj/bin/activate - (myproj)$ pip install py3-tts - ... - Successfully installed py3-tts - Cleaning up... - - -.. _espeak: http://espeak.sourceforge.net/ -.. _virtualenv: https://pypi.python.org/pypi/virtualenv/1.10.1 -.. _pip: https://pypi.python.org/pypi/pip -.. _ffmpeg: https://www.ffmpeg.org/ diff --git a/docs/support.rst b/docs/support.rst deleted file mode 100644 index 028edb6..0000000 --- a/docs/support.rst +++ /dev/null @@ -1,10 +0,0 @@ -Supported synthesizers ----------------------- - -Version |version| of pyttsx3 includes drivers for the following text-to-speech synthesizers. Only operating systems on which a driver is tested and known to work are listed. The drivers may work on other systems. - -* SAPI5 on Windows XP and Windows Vista and Windows 8,8.1 , 10 -* NSSpeechSynthesizer on Mac OS X 10.5 (Leopard) and 10.6 (Snow Leopard) -* espeak on Ubuntu Desktop Edition 8.10 (Intrepid), 9.04 (Jaunty), and 9.10 (Karmic) - -The :func:`pyttsx3.init` documentation explains how to select a specific synthesizer by name as well as the default for each platform. \ No newline at end of file diff --git a/example/voicefile.mp3 b/example/voicefile.mp3 deleted file mode 100644 index a5ec83f83ec4794060237ba3d11239c6f9a2ed1d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 51016 zcmeFY<)0Ks)G*pT-94^5JG1WY!s52LyGwweOG3~f!GgO(@BqOHF2QAi#ckbP$KBfB zTJqfcy!Su2A2Ri;X{l33t4mIu>N{-Y5D0pg*<(Q8zP*MG0r!v>1VhlI^N>7Ka;-Ob z2EV?82akjx*{gq_{`>z=1OI8@KMnk+f&Vn{p9cQZz<(O}PXqsH;6Dxgr-A=8@Sg_$ z|E+;hqlSVt{e$8EH;FRi`}Y4^_P^!dF#`_*#QA?|z@TpH zo7OA%u?)DQ!Il1w^WUe|Hvpy;65JvGQ_cVwvK12IfD#mB1eCYdAOQ>o-qPP8TVV*0 zsedtm^6x)T&VX9~)`q`xgn=g%)CL)VFyIbmaqxr#SWx>rpRMH>z=wS=WxySW^?Zjx z06rkuzxBV@0Ni}%0B{fBV1VOaDO<69$Jojtpw#-l^$PAlrU9PT(pDMJ?-)4W>HQB) zAVn*OuJ1HkHP#B%DsihGTjg)%0|oNH;I37kR$2`B|5q=qvb0k8zn)qp`wrDA%Xck( z*UG;fv|6H-H}ZSgzx@A8rB$j{n|-$qz}RZLR{4QOTi>>F)>;qLroQ7KTIKsrskOzl z>Yeyk22lR5#Q(|x=z_Zc+L`x1mTjfd%5y6f_Fwz}2e45qWUG$8(*k%{0_1rFBCE)Kn46uJIPVm%f@76mKQ1!5G)&`OTTwBXqZ6ScfkOGoHqVGuzXaV{F)(xQT zteMquDN3p>arfY$=*wDR66cWY}D0o)P*MF6a=G)VwyWgVb|3t({84WJZ|8WI5-6u_>A zyaAMnHG=Q2m3|#t&NhCh3F6zNDNR0?Ff|cziSl! zP7MMQw$`wLs|D!L%sPSgxB!|1vItT_GQf+ywO;_#`QR-C>WRKv*9s(Q{Sr)U8T%FR zSOw%`0gMuggStb#pk#1Of!cz9E?doJvkyUf!9HhSvV}l898gg~{s3w?G#MHTb$~*E z)%d_7O>7>Jxqxi|vKO$g*pEOyH^AWr+|fW&?V&zUXP|+e&;(E~0knhn>=Tf#vIp6f z>^Al`YXKa31AJ-FkI+_VJHX!!&`E$20ms?wK9DZ5_t~fHDNrYyH37{>Lcu^=iO^tZ zG}HwO0B_nrBLSUYP@^8m91ID83@6w{>=O1*K;a^w*$B0R7D5}K&CnX?AfU4jY6I+W zlKqX{0WhCrH?SK46$02R67Zt}+zf_>0*ypLVNeF3k_b321)9qT@)fYp*lX-Nph*I> zrfSv-1wvy0-xGoUIzrQ+p8;Q90Q+h7ERb*#+n((Vup6M+&=ja2z`G4nf%bq@4|fCbk?d~v0I+N*dzUdXe=v3I0=5=# za+tjbMMLMHeZY!Q&>C0`4}!g+AK16-1NJd{jvc~^Srt2(y})i_v)G^5XTS<~pc~LN zs0hk~-a#jzaZo7GUuV$%w=rLsD@-$+z(%p5>|pSXJcMZI6SNz;0q~B7%AlFw+gd7U z^E;SN%pN9}T?#a(Vm$12fQN>?03YXJ8GHa<4&{UId?Nc7`v?@$r{m@zH3&g@F z;oI;~h=f){JpdPOb_(;DS;&MiKQh;ta#qBy1vWSdxd6W*us<9LcYt}I-U47(4ruW$ zpjB^Slh_!by&nPJ51I4KS9Szj1-_%-;I{A+I3HdOE1+6f0(}5h^kIiGFPPt$RZIuK zQ(tBo(Dyr_*A0*a9?VJNY==uZ9XKO6ZQ$Pl-#N?=%voj>6GGpmyD*#Bh0u7=D)>+* zIF*wLZ-e7O+t>!LgzrGr?08nna@l!oZzhX2Fp*3p_|}Tqk?cz76vvB`&WVNPpq*GC z8&uEUU@XjZmcs@zy_tcGFB=P;fv3S;U~hOHyp|({v!Hk&*C}=nXgz`S9XgAC&-}{r zfo=@!Q8<$$<@AMj!875@oUfcca4g%*>|(kxe1=PXraIBP*hHurJ_%7!e<+7D8HwaP zgf~ISurGWZ4rNQ3wX}^H3%&q^DWOMGxlAm(9B|Z&>C6s>Cva*w^WaIa0%*aANZ=jp zDrOubWHGi4^8+0~Sr}i220h3`wkv3*Huw|#7Jda6z$F|xZ02}FM&=wnjham1bOu#R z!?YjJ!)CZUCx#P;wBy|8=-^M#I%XR^njHr%g4e)4P!zilN`QH631|VGKtJNgY^NX6 zOV|oX2H!;%a`NH+kO}??Is~Uf4_Q4l3JPH6(fRB-Xb0SYOydS{E4d`rAN~`nV2?v{ z0beuNNII95Qyw~jcEgk5ujo(QIAjWZll5Z8vOVF&&|gp=cr5e}`_~{b)p_qQ|a^68fG!{JG7Ze zp>NZ9v;)4v83hM}-pZS~N7pcIiBeKYloA5+CAF4p!q-rLvdbVIN5o!X4?+ge8x+vR z>_*U9pFj`kK1?_@gq}hDLT#t66DC?pT9~82Qjh6W=6BF<#6g|u6zU)PFUE_SO3fu% z@;V&{u1_dF{hSJ=M>10SAu}FGU}VBTj}`@b@)-6fCL8pW^8xQ%Iuf*GGc<_3$t+;_V5P zoJ=pFPE$*0gqp#Or!7dLmpsXIp$~x`z?;rt63LUaH`SYZN?s!q@xh+Y_&n!p$7)-K=MZ+tdvf@% z(I?|(#-C4aY(ur3mqDckrW{I&jN2K322nwy!_c^=DT!%alDouhiaHry8FD@_!`GlZ zFL#LUp}!KVt%=5&T8EJ`<>)(WpEeF|NNh-K+NAlcGgz+Kd)uEnDEnmFH5W>BVLrnf zu|%{BG7m9uc5zm7PM}v2Z)78UjxHd>@t-_4PdxsY+sk>@uC?4YcGNx8@SEi=wasUm zRy6S%hc&jem~}2gvU$0End?3gOsnWO%o{Y3yGEcA4HkNf&Wr6*yA%;$l^hiBlpK^C z5T^4cVt=9QkxtMfMnJ^5YhAgHEbAH5@5W61KK&8>RxMA<)g0Cq>x%WWjW>+5EM09z z`ytmMTt%#*?y+4UF{c3CiQVP;bC>X6^9aFWem(aJZ$D4Ky^WP2Kf;edZ(w1kQNI(X zJZs(0JVTtT?N6+FONF(}a>Y17Tc&UCZsEH9wnV*+9uu1pJ31vYV?)R39qZFyrY%ek zjjxG$5hV?)j-->mq+e@uHThFyMS#$!qc^U|5_@MH={fRoFPFUw(=UeAn-@l&U=xI5s?_lldc<9kk z9oZ|$04`tHQH;wbC_AbKsIK@-^bx3WUw@y0KF3s#y^ni+l487i*_`Y;bX}_ZWg)54)%C$9R zjap47z0ma0`ouoS>F-IPu5y0nf0Br0V)-ul7r9aXOtD9?M@Gw}qM^LCh#9J(yAzP7 z*0s;E&}KEmx@=8e^UJ0Y4f*x;bsOrG^$qm}4dDlrZ+kzkUyJ_{zi|P+{_p*={I;ndsycYb$~{uPFq*4Iwy^i9*`6)-VjI^~Z0xHm z)^J-cHs5PG-`vS| zK>U~ZmN-?EE6C<8XzN^|%?T|Wx?Tl@T^^|pwE!h$5klGU+ zV&_TsNq40y(Xkq*c!@rfqbDcsiZ{efOd{I<-Lt&k#2$~^A5Rq~$0t6HFOT#O*dEY7 zq%_JmN)z&4wM}|inkDTodXH-GEaUseqg5S>`seb$Xg+JcJj`=O%JVn+X|soNPLBS>>($M>4^KfJ2>9k zv#ePrzP?oZUb{_mv^lo1f4!#O)3B}KVMG5$-xm-~uV@H!yxVPCof9&6ub?r-d`AFnNKiESF+ zplQ6^+`lEZS<}*AyF=f}TyEWAi+7Z}{i%3X2p>m;NVy=>C6GY`Z?(A(i!v*>)|a$o zX|weGO}Un7)>3PW<%MI8XD>Ytp32#Z?c?nehsezGIbJ-4kLhhKtJvxn(ZWQ^yC z^PO$E<&s5azF{&M4;xH+mtLxyuaUJxH=A0x8b%jvm~ZZ8yWw6-_JM-XKlts$U*+Ar zW_vGF^-;I=>Emy`g)f;t^DoGin_*33i+DByMN1@)(J$fdoa{XYNWyTEG z4U=_UH1nFpO@@|xT5s(=%~DOHuFy2uDz+Bd#P(m^Z^%Q;YW6(q^FT#;IML}(IB;XcRuAuQ6K(~q?x%m~x7BmNa~z*bD2TJ)G}hE?tq3VC zDLY+RTid=t*2rrZUVpT{wqa&tTH}?5mkk*WX-xxKinO;47fgMvkKI2~Q7i)s!5Zc< zJQZz^4MTQtLfD^~66h+J(+&qSTpzlGod#vGq2xpS5k7!eL+&E9o-((@Bf;NNed+u3 zdN7J^fL?JfBKOe19f6X%2Fu}wa(i?4a<6i;xudbmr~}#0dBj-=Rt5^j zNac|Ht>RZ9G)7CwsWv8=-=pZWG|-$eg{WDm%%!D z7;Oi$7(UrZ&LsZuJaSb!PdXhgCw`lez%S9W*cR*qf02~y{ndAa&s*;$3R0QxGvBY= z&quvnb6dKK1BW<`A=kA#1CP8f?oQqQ0-Gj$#;n= zxfu`-tl*|nC6v;0!hXU$&Un$d)v!z_ZQ4?Mr}AvsjgmJ-7Yo-EstPU?t}7Z++_em< zsI6IDf4Q-?<*Clw*um_uPO|fzkoyIxq))MXVI|UuyNvG^m4lJ*xO}A|*ehJ|Qn5_2 zRFNcal4VKL#6@DcXqs?@0OjrC8nDmkXXF~pLXE(OfzWz71gv)^5!FN|f`{M1-{Qyd z4fx;qMLZ9Gg}=f7#GOPBB8iA1P$HAqO-7P|Bt&MA=SeeJLUkZ7kqy)XsxuWr^&;!3 z#k7+8O8ZkL`V}*l8N#k%g}~R*1UxN^I0AS(N5iQ@qRWH}!cOoZ7tPhV4?G`w|HxA70 zM#zIiYp^udNvAPu*bDS}&vx5wbCtQw++b8qKz>u< z>*b?xD>RB2nOQbox>vG5oFbYdoFmxFKf>$I4Z&n+cg|P%2($pKB;V0Dsb=y8IR*4S zH;Fw>}q?CAfqdzk#13y5V1ebq?e6!IKkj#<$>K@M=*01At2=+7i!*8$?&|ltf%0 z`w)K+*TFZ^mWra*P(!FDdN(tg?E^dwjnEHpB&Q2(2L>@%h8+i_}|s&nw5bO<-cs$>1j;8$%nybm97l#}VnF<$ljC5_ksmm|e^?&>yK+)N!(od_?vn zVG<_l$WWq|*h}0ZEWk1^KpsmhCrXIJ#1xR<09!F+6tNV19f?FGDF!)%(31(^yE;KG zAzzalfL|kxxd9%K&kJMtF2fxgAsp)Pb8HVbQu zjX^1-38a(AQ_ewn5Ht{)z`kS#Q0?(KR6jTvYvLJE6nL*E@$M)_`Y2Qi$r)Y?|C_8v z{fqA`Z=-CN6j3Co9|s%{Dh=)soE5S>OdWnBqEC2H=;pvDzOPkEjC`hfu;p+2Pp*M@4{{nE%EoYF(678_f(xQ&k{qdCK2pw+-%+G0VilS4 z@iHIj18IB7Uh#8LKj90(IDQS!g_*D^sFd>sE`lzwe=w_=AX-IXlo*T;pwA(80sq7x zVk0pKw-LPv5rGitV3zWV@W*jN(3*+<#9ZPL(UBMctaOyfC9;XBAiX2pgo!92hmmv0 zW~!Q+LaXU!CJFd#XR%+P-f$47ElhJZA%Vzb&?7aV1?VSiCzvP1a}%&h*g>o(rbF)_ zuaHHY5r_gRV>EOuZAB*V778KWG>(O{j#sPL>r>;iRo)_4A&8L;Q}6ZLtDYl2EV(Fm zsh1!ql)d-ikc5~e>M0uP19V~hZJj6#1!Cc|&wE)WL%+H0v|>N=H7&L`UwEkq45j@XKq;`{Ji@W0-J z;~PA;@s9Xo&nvt$egJ=h7Z3=35_b^468DH%_#0v=F@|U&gNfP1Ua}kcmGS}OLkG%C z=Q1mpb<8n#ICKnFz|(0%<_+Vw1VvSRv}bR&%2;Bi4*wM^)$+ z5_}|-7dAY6e3&*QFW{BW66Mc|O8IB0O3;_HhyDgOJ*R;+;cd@H`&~25V8WDfZ9+!HX4h>c7yqm8H+(WaMp45b8(56Vy0IY=?|i3(o;Ucp(`TB z2hUZHR1m6OfrCS?2Q~RJs<*z&gF1wTg$u(rguM>G8o4R*kMQEqb^%9JXJj5xI{yw& ziCm={-KZ_e(qc;iUOX8bS%n4VmP_TG;|v}0TFP*;fe4ncocjHiU1z-f7rIre0VGz1K$K*br#u% zJVfd^f5VT#4Dc?iXBwy+Fdq#f#sa_0O?R@}$Mw5Q?i_Bfvp=>^w>`0qv~IKp*v{Lo z*&^*C`zYsc?)~nE9>~)|j$@*k8_XN9kI;b3Ky_$3qD64*80eGx@!E0MVnOH^bTHOi zv_$FeZw(sYztCr&Z%uee!h_VLq@>8FLDvG$g`SA$6j2}cS8#2})bL?Z%`wq2QPFQA zH$~iym=x+2*vUIjxQNwwF1xxrr#SkU+qU$sTV1QHpVTz5>2^bDZHLNjS-aXVetJl@1e>L=(5sx^Se$uCZzJ5EIUW^AIYe)A6lrHTa2|378_t!XFR;_RKl#`BpLvt9 zpSdC)F5E8i2>F6Jg5@Hv#3?x>%HgA^lJgo~1ifTZak-rZBl}nD57x=%Yx+-`pS6TB z&V1C&*KgB~)A5W=mVYdVOpPYHt&Qsyv53kfYiX9V02|8h%J0g%#_PiS#P7@>!2iJW zMc&iPfxmefzsPTNt8SD_n262c>6KP4xo zWF-C&D~Z|@JtWE$zQ_Njv;~T_kJqfL*;gqj4=Y<-wxeuh>79~|rFSbnS64PnZlvmV zS9L9Q70oZcRF+)fu07hAso!tKJy+N|&PZ;#ph0v((ndH4Gq9UHn;k~$GRtn;S6e$< zd+Rq#mOaIlAn7?NDjh6aBmR?r7{E@kE#Dg7*X^tQtHxTp zqZY5<(U9MGqIrg9vVNX1!#vs4WS(WcZ%=V26EWmzdK;SxX|bb%x#B$W0fCNR!Ji?y zDr+O$1h2+-d;UQF@WCS2CLd0|nQ%I>Hf>Iqg*`KSS-Wjd{}{JF;$zsrkc8mZ!QzmJ z$c#8=d{eY5w4K_mFnK*t>=kA+*}DB@4|B_MM-(3@%dbF6>WiL~+N%%M=QJ4`osF|v zoGr_mo9o+OXgB{E_n;S#Wf3a!CG;eI2ZJXay|rQy3UwGb)nkfx?5Vg)}mi$ zs5K5Ztutks&)9M;xyCb^;Z4~s**Zv9t6QhNWxC}#11;ob3m1wZIi$)BNDYF5BX zXH*MS!@aY;a+R6#eUj7SX`lY8O^z*FyDB{h6BV%5PQs z8ZxzV-98+f=;c3~K z)4E#H!xDP5dD-W$VRb|Dx~)&DkLej_iys+LA9%-iW1u|_Nu7~!Fu0duhR`AEEsqqP zXBy3gHGN8*MY9Uq7WXN_%Gy<{Yx~w;tbJQMwvpRXVt8PDr`xJ|*Ak=IX5?G8Ir~$5 zWSg*~Y_5EOWP{*C-Z5{`k!PWq49gqBs!0ZmUd6}p{<&qlF!wYH0Pm-e$R zP}{ZTS>yEfSW;Q{4%{$mD9WyD&@+B z@=Q@Szm``E0wHqgZ1+M-uDRAwtI2MFs;5=UtJc*ltUFT^S_?JgHr~=$459i=W2!0D zQtQZcuJi2kWE1P?Y)H ziQ5;Q9X&1TOgQ9gQHKVui#`*d9b%DXv(r2aLD)|yIox=wIye7Jo;+`1VRmt5ac=d# zI;inh)9?nUp|;VYhs>GQeU4n)aLYPJrn?rpC90KYdgZFJy=#><$`?{I{}eW#Gleob zznGu37#luoCO1_GI0OT77*&bEk%h^_`mMYP9;_!2FDF;9GdkBkmaBMQSGcQWs$-v>B|^3Pm{) zX#0%=Huhf9?oPYKonG}CF?9W)w9bl@eTkuomiS@O=73>drvh)p4o&j|-km~WaG<9y>2$HD42BWML~ahwRH!W)()7+%ltVz^;)^*XJG#8ld z7Si6yInebAPxokDA3WQ+#{#ob`I*DJ9ci;Xb!*#qJ!TJB+xKv%`6+8sp0$~khQ^N$ za`?;({W(#Y8W33^T}+I$`FrNl`#rby){5*R-;y)s@5)}}FZgmZKe{ryvAXeag|VQj zaC3EzzKdFpO)^o-$SR7`&<{VNibQQ zC>s8Y^Q<%X|pQUfF zd#j7q?$&kDRp?h4I~lI%ann(2Kg$+NwTU(zf(9v1#Kg6mkj@7!C>0ouCc+nB>IsSdsvt><^rJ_U99Iu1& zQGz8%K75v453OhR;kB;44zn}Ze#4ezOwygyKGi-kcGm0l$MrgWnQ4HP@5pkFbN2&# z`^%Vr5Df7~QQi{XT>(ctQhZkQQv9PRTa+#CE?yuw#XZHN(cK)1^OO!CcM>Z-giGk? zXdeK!_B6m#w%njL^fheOFV*K5Ht8eu1*QY~e0`c8HjUtfs&ixarDwys34S|yaw3F1| zTcNTz8fHv0 z))__^>THWGBQ1;UXYH?C;rIsN@l6LYDhC)FvJt(Dj>PWpdT|@LHo-aGIi8Z2!@Y~m zKy%REa2seeyNPNf&k>EDL++VQhuvYnXMJP6U_Ni!Y{rajjhGH={ztzIzaVf1L`BRF zb_QGsjgD7ms5_2rvnAnT!nm|{ZMU=;7vC>*Y~-@EBVBkM-^Rvxz2p0cW0cDkF`N}< zP1Cq$jZV{Yx$1r1iZ3flN^44Lj+FHMuq>zOld7bt=8vlLWd)^3O@yw&HqzO{5$0S^ z-{KFK$|Yw6!Q5_wYWWmZwW_PEQuI_jS^Bf=XK96CCHeuyxdYHE@MXG#C&ty{UglA| zX4@`W-&kf^&fD%;3#|>-CDuERdgp%Eeh=*4kMAW@=)LSPRtC?9li)Atb>uU85?hU2 z1M7@|SUlnnqKmX3+UY2J6!@jwct7`B*JkG|N0e1%&9KZgZq%RCcxi3!bnXWAt&nK} z3;jSSV3a34CZl_5P2ASl_Q@|YV$z?-Tnt+l@iqBWmy7K$#L_;PNG1P8O?!Xg-E#)& z9Qs1Dw{c$ms^W+^FyJA$y3b zBn%G9cEYv9G056ryK7N`{psVj9oCiBbn7dt)qdMm=hnLBdae-L2?(^SSP+r)9{LU1 z4r}4Xa8Ed#Jpnaz^@ZYc$8D^dTyU>J#9InAE$rs8joZtAivwbS5&at z7Wy&%V@g0`LKGR15j#00FexZ{O^7q3Z~T;Y-P+!WFA1FLwOn;M&=c5Su^v{q{T#2{ zUhYo%t2LsECsp>Qz-C9)z1)93sJ^O-gUd~2^Yc=^%*ijQ*jE3((Np)Ral3K7tByGU zg;V}iXU+-XC`E>1o^-WDBE9b2)|aa;R-IC&C|~&U)LWIeWb1^vf|r6@d<&+4dQj`| zFg(pO!dYj}vxQmmEI-;_TK1cInqQd}mUP>6TfUuRedQSGYH%&~Y#^542Z;kzKE071 zMddTE=_TMhIuG`j?oykm-ed#ezz=zPyAHZ?9HXs~rbFf&Pb1n#zSR3yGqdq= z#v}DU)pHu!YhoH#lpp=_;A3pAr#P!@d_n2who83P7MF3W##Sz^Xsq3&IcHzu>E&AN z+K-1pJp`x43&b~tdxW&isHD^ewMgZ!^7mN@_O`NAM-`XlJ~FP~8kF@mwG={4VjD zYD12segykQ!%2t;0e-1d?zNt$?$(_)gKd@B-{Oz^akS$8-Z5bBcbs}@$e37FLQZ@` z)Qrgdgz%IRiFL7=;R_?qB;RVA-R^eMt+2G&F3m-<|AJV^BtwV%SRW!`7-lspS(UL&6WR@N0;BPE^2Nzx$K7>%j`V&GNuG; zFBm6yz+WLKm0tGR=6wvrL&T{j_-6S%^22?$dk;_!RL=GCm&c1&@&=-xkOX)T^Mss? zC%8^JKRfldr`FY$K+{t&z8FkHj9&~UV^`Bq(+%?}^L$Hl|iEu4(Djf*eTPh@@I7>xMinhR8=u)+W@}jrJJ&0Qo z`7p9HAuee^f?teZ*vH6;31s?{G<{q^*yj*&#G05tBbk8R(rP}#+rv$PySs)NhG`+) zI{gUEk2PM!X@%h>;T5CGl|_ZQ=f3vNZ!Ec2*0%IQ>C#G7{eA6Q(-E_erGsM*`H<5e zd&I-JgkY|;Bk(kJ^46;+`6T#~0fxXXepSA^eUjBxK2jwk-zy2>-{N)07QnUaLb4WL z2%^nc&?@#?_ky^YVU}*D8z!l-+E8umX8P0g%t)JeTb_aSxzWDMKG-?f)x~wvZSYJ2 zi3FqcBwPgcyyNkS_(xB?=cDJiyQ6c09d}G1w44tDkIYxrUw+x!6I2>CE_Ph(oM@k@ zBk?gw{o*f1&ki3Oz9p8MJT_@*OrJ0;xNVp-dQ6meP=?nb(Xad*t^>(%A2haUdEIok zWmKcGYGlEkZ?=N;q5~z<3$0)CKL3^bvT%LL`qB|4sinC!q0MJ>XG|gHskRW$SEw5{ zg=-Z2BHS%W@-nCft18tyeLDO8?7uQ#qW?hOGWB+KnW|JdUQsGJDtO0xfX(5k*|*eN zuxs7cg*j&0BdxtH5#~1LgQl~lo~G%>dJ}9;Gp{%2S}fL7o7q0qant$SdCL9Vvm2M- zMk0t4XM+U!ejCyZinZ^rX}rlzEIrWgqRC z$^42P6e7X~iI;q&@{Z4sehNR>cfY^f-x4q_V1X~IHmex#uS%)BN-{*So4X5n3K{4M zVwH<@oUoN!I+;5eAL$3^=jz_;R_HG4j_6}RzG&=g>}x8v%(Bd~ZMNq)N4rP6l|%&5 zhD>LsQ}rNfJdC*w<$_3qX<+^$XZJD7>AkcM*qv?xUs1CAu>HP$zGp1GmitU1k@S&W z@Qw=jC-O~vPC`yxMqHP~oFqpQ8Mia+T-czi}oK~kgm$`i=mGZHC;0|+IHDD+CPCv zhmUwUd4LkqJLsNl9t?wh+*BwV9uI$mzk&7dR;GpJF$-uHZ6e=-UCCeYK6r*Z!`a(* z-io>oQ74d%!n@*8Qk&NSfB%RPu@e#>CG?0Jk@zUNfAY43qfx$LDPb)!7vpEgR7Y$H zGzGN_KNa~U{EdH+VvVQ^|0G6IC#<5D88vOHH&#zCwdLtP-TCy;!I(?(NZGV-OYa5d>X`2ely7RQ?;jC%$jW7LOrA(uFuog z8PhC_Y(Lss=XgC_i->S)Bvns)u`{4voCvf5DMaof1?V{p!BErz7s8|ACUD9^#T1dv zgcIz?&hj+7id}u}F2`2KJL@HLiD|iQ8-9t?B3dr#Als&l^(&3Q6XvGGC3Q^DCFxU6 zr0SCcqASBEM@){HobW7uNTe~ODrjif>4;&WHU62hGlEPco6Yw0FyuAtuN+aHUbdtp zBG3NC`!o90JO5tMm?CFkQ_<4W`<3Hr9@Ji{_i22n&9d|d@sAV8GWHmDOmtknN_kZk z;B(UNWI$pd$o^malYFcEx~fgyr@i*dScyfHDVT;Wg!9-DW~Fv+h%UEy60#_NvW z$GomcV+AXC4?!>747DTMxeq(u*n3-NnsSWi^h!Nq@Y26D!iGBIBGU--H0w>sp+t@tnTK`e9_Q)!gy69-PM{S`5NzWEZSiBU<>-B+E%XLfF&Xq|GQ*>E z7dQ`qc;b9(Ps?AXh318pO!HI_DLTxQY#L(yVoL(EqLbED_6p}G=M($imdCgdEmOpX z91S}fQX1Aj>V3+Uw%QJ!ws9#R(*Mqw*jA8U9={`cQ0&U&P8nA-^vQomUk!NzM%=5a z3fW1n0ZJmow$FxVP1kFJDxX#UP`RhVST?lid49KCQ*L$M)Pn9s!KK|RPFMe47uq0e zKBHe}O9kHEOr{6hgAn@1y=ETna%5tszB)_KOoyEEsz(;?uwW2dUNi=IqXd8 z9*%;wTcp)#!z?P}ANn!ccG^Gm?SLO-i$2;g*3e=qu^hIJbGSXF#5ig>Qwn*ID?C3Q z&W{%i6s!`@lTMZzB~_v!;whr};u^_R-Z$<-#Dat&_0U<`P9W~y9&cBnW3#=FWtsWD z`J#E8c|7oGm6_vA11-lb@s<-dJ@CU&&Xca^?mgg0-(FfqLU=abgSyS{;awjdo-iuG z5r;K1%vK{-*?en~Dx6J0zx3kwbi+$*ZMPB&S3R z_^HTCdXf93EnmN(xmW$Unu9f)sv|2d6#wzbV!Oim6zM}o-Ps4~3ligOC3?2de~v|f@f_>rgJzC?#})-eiC zuG8X_gE>%$b(m4AJq1!%U69tO*`uL#T@7G%2;v8K*;ctK@Kux!obUJv`3W1yKQ7uK ziIbJd2gtX19rY?zwpY%Pmn!omHL;UL5_>{2JH>Rj?Pzw@_MUw7tqE=VZaSv;{& zUyx8xQM9tWqJEV|X!5sovcy|ES^XV2{u6T?d&Do3f~kY-iu{;NC_kp?=p|4dlV6dR ziAwqXxxXQoIU3lPc}QtI?;Q`VAB@`#j}6BS0S1v?q}S`_>5~jU=xI}u<&=$eEpYE8 zAX?6VeFn6icUH&|)=PUzH_93nGv(fjF^V_xrSfKJiMXGL$6wCtfNJ14b^=+BANLG& zJhoL>#72Yhr2eU1qNO$SwZXa+-Cjd?!%ah;d66y6vB(8`MiK~h7n*^bM>k=Sd{o#@ z)GV1TE*ASpVkGY+S%UZIBNX@Y3*V6u(B)Hl=ZIBa*A%P$zJygJJda~ys^jJ-rM5{; zyA@}N^n{OytxwBOPlyljYmi-&RI1m87e@~b|6P5W_k!GSePqyTf6{EwPuKmd{oEv} z>{B%BtNL@d&+gBj-0W}TzpVe-@$>O-lZpZ=des-U%+n-kikp{d_8Q;WL&$yb2i_yG zmo#54l&zAjR-j(Hy)USzsKzSiD{jewH$*%@SjXFr>fu$?RnKTgq3ycmu;rrpl5whW z0f;)T)%Ivvta%JVgm#)p^F8ZzXIED-@s>(vI{qYWm=_nr*>nDQ|r_g>7|BoCYjk{ z{mrq%HPADO3}o&>P9zyS%qke|;2EJ6Q3n&&ByElv0_HNyW9Ov)mho3|r_jYd4L*Uv zfpKqAxe2F2UdU59E8JH523x-6XKSUU(HN|~Q70|!{w?c6_J?&J1z$oxdp^SN2E4uX zF)mk7(y?-VZCrg^{gwLdjRRV6Q@W=ooX6*g<3WU_%cU0+K zGZYc>mC~O@O5QnmH4{LJT&o>}Ed`eImcgb%Qybk=%{5ITh$fz=8?4)GOfucGt#L|R zYjCg!!D1XKQpD}b{e}NkJVw%07A+5!?U7HBkCknaEEioAs`*p7M^G31mib1#BZhhw zIJeqmmVTza#s@}UU8%OcZkl$VuGX+mpKaiq=2|>ft^GIW9d}0}o@qTH`V>vTp7Li3 zouWgacU~&%CN;_~O1Fwj#5cv4#M1;1d3jhUk_Oj9JE(ykFGqnRf$1fD;zI?^R5c2^ z(oOU-%qg$-Ee;6rV}o8qtcbZ4_aS;=`0a?7ap@_y+r%dijH(Fg?5_;%5-U!gmE;}n zR9)xqVNQYh+%U&YM?c%|X24l+x^;uL++&eSH1#*RPukuT{@# zh-y|ht*Li4KG)1KZ*|5H8aRu4TYOnDK+#eDQhvp2q&nPZrLRaWQchBy^V+3YCC?D6 zg!gzf0_J$c80TBZ8v9y%vMt2yHXSi!8(NIR^`-i3y~hY!2H0SGzSGZ@P8^^oLI+?y zoP)N(Hu1X%=LvFz7eo#TCZQ#3ME8YK!CJvkJ`cNz%z;|KdgBb8N#uD_T~_A=ht~d= zHQ!ukUTl71;edFRjh4@rPqts}*Bl1d1y&ip`6fL*n})YmLoU0JpLRZ*t_J% zay9&Ez#IEe;NgW}?a>EV3wJ8whW0QF9Ya5$?~}{G36!y}p-z`mW!r42wzl>B!>JM% zdi9o$;U&U@;ir7D{IlBO_pATLfG5GDL$8M44JRXXQ57*eW7DI1hLr~%^gHWE1icC$ z5a|{A%10|5fLY-Y&?5FP5Y>0a4cqrw#v6ULo|cDAn&#A|1@)JzJ>@lJ%gbL>-)~51 zs?l&YU$xO1lg6Z-ua7p-c9mD|wC!7tO9mqJK z{{!49-1*#o7|GqhYsb6D3*k<|Hh_4qzp-@GpEDco1U-XJLG4&I-3~n*aI#P+lqd}M)E`gMEFh|F4-gfB;Tn>_v)tf_wKB6sbBe|tLLlUsyeB> zRN<<0RlG{7iuZ2k)g*r|og%&{S|mIs*uxL!&O*N+J%E(6p)qV*dJ$5mn(VpYL0MtE)2Au4Goqo>oPJ?T_OY2_b)_U&YlZh~}=NU)drZ&@anYN6T?E}v2 zAAsj_;yAkz0rDeaLg%6{(JBzFosKQTs7E87vwBGT4(TBde%1nhW9zPcb;F04JoMfr#fM_#r2hvkvKicu);? zh#SE@1EOpA{6fJ)p^tE!aF}qbP%rvj94}rgekJ}}{9Jq%M2VdhFB1wp_|k91o+qdgQp8^nGu0sA|bs9-9G4ySK3|A(nFfwQUnAOG3zI{R2=?7L8EM4^oq zHMEcvvX<1)VrP^>B@+^&Muo9Os3sCBOd+GBAw*P@EMuAVZs*>!{ol`>zOUbZ&g^VGA~I-Q&?WGHxzRkm638bwi_Qg$epSoiP*ajM5ORcoVl*M@3SnV~PW z@3cZ~qqafY%=rdwsrHiAUu&;5Py@vKZBb{ay;V&qRX%3cI?5q=1FNoYl**(%(io{@ ze6{{?r@iB|zq8*&^Kq;{tpnC)R<3oQF7V=xO(|I{}Y%>>KSz z?9W+4Kb>p^0qF*@`d?0vN67mWS$Rt-RVSk1-=wW}CAfCFZ+7o-M?H6YCU_2bv%GJ6 zEnf#BK$rT8e82n3eG#AT3;K$Eg}&!~y?nCwJMUy~JI^`K2G0n$;eN{%1eU#wQ3v&N zRaNH8)$$zKB|T4$gInx_c9wP6YHBVqt{6`kS}ZqqM|5TMPVCvw>Fpv%SfO@vq+z%u zd?5T;cy4%pcnqsk)`m|<nN}sTfzZ)3@espr3N1VEL)V^%5vfr`0 z+Sdc6j#X*>Vf|!nWc~F5>vPugu3=63r`A4eul2We2{l_Kd%&IcU|P9^c)Fc-siQfq zojb_OFxh#HmCZ#&v3o^k5AuIJKrV>~rM~237>BiGCTq>_B)dgjDTj#Bx=ty%WDb+j zVwckbdYs|(cA7cQu|C8nEs*?Vs;J9K?eC;xatA!SugmkrN_u6k@}+WBokVQ>1KKl0 z6Yg=fblvA#1=L`xW;=zPGtYxKrJJqL}}3z2z}jaQBP zV@;#sXe{zKtLaUEG z)hZ=h#8=L3MCcnZw=NWsoW!Q;!nqA*2x1KiFm@)HlE6<#0mY6M!56nJB zH56x>xyR^g7Ms1y=H~X;4r`wIt2NVHXjEGpi0t2FEwVngCNc{?yTTb@orkkNCO2>j zoKAAK{EkwG91cIr9h7#`QTep$Azt$|Sr|T&>!}yy%SurGSQ)1Jq#kM-Hnm^Kmaz{= zt0$ds{*`kTMSjp3X?^5mOWl>$@;}yDbD%X-+D{E#p#bOXubnBVs zv{P%TR>{4TTw9fgNS`Y&Dov!u@{>w?*ILgh_X;OlIVV5kdC=2IEmA&||8;G2ec>A- z{pMOB)mQhpM`@G1U&>9isG8x+(8emW?QPOV@7>A{^-`=x>fs!c4$E&DUpqh9&DBi1 zy=>Xtq=00!D>S||`q~YhvF1I}0wY)c&?qHy z#xeU=#cyUggDk&%zjH|%VO_P`OV^pb)vm?|@(KGr`B7!P^S1Jv@xC_540-r zC#)l$8BUJ7D7HkJYL~D|^Fix+xry0GnPPq+ueYMkE7rgEB>8ze@=U<~#b2ab4O z3s3aEsXl8S50wPIv#oF^wN3R3b6%BOT4}5?evjT;wawlZUZ5VYX>HtBQ(!EQhRp8K z>d+C>U;VXuV@-zKqpC-&nLZ1R4K)XBSExnEr@UOf$-U>w``Wzny;30dQSg$QcdHY&D1<_!nF8^?UVH)`ew93S3n+J(KgoJChcL@}!+gsopcWTR7jF6&xuSN~e@lYN75` z$44c9KXSbcGJ9HCt}H8G&5Z5T`kCXMOx0`WXnL%QRj|5KrWKmHB$iMJbn8JWAPGew$-5|6nx0ja=g*9kIHhWHxw$K+x+rmHFgvj{>Q$?Zd^^?EJerqWP%+5g&&b8* z+07_*6+|~`&CL=u$JrS>h&LF8QTI^{a8SiTsJ7t#mN&=Y)MPbQb5FY8y zw|dfoQX*6Gs%9nb3}+=51jf5_^i!@=nxtoWyOrnFtt!t;KUG$7Wr@YtiZe>D zWdRjCwNfQNTIw&oT9B4%u)0(48C~QmlqAohaFNrE$ct=}rInebTCQ2(8WhRaO59au zwpARO)c0#J2<7a(+XlG((tY`Absse3ejJPas zZnVJLJTyqklH2*R%_4Zt$XKqcRP(w^tMXWHQsvHa&kE{WCDgDZFQgf;b>a+`$sQn^& z)}oZ6Se~!sO7oP$Kv8;ru*k^LvdvTe)XMQ`TUlvfYu%c=JG#C&~xXuQ%*TI3m|dTR=$0=1ti`7#5=PJx{&jaRCqGOZ|@W9r6u zf0aAiVjeUwMyO?-kI3WH>jq_B~|oG*NtwjoY;7@p<*Y;mu2i!bE6v-Z{$?!##pADtEU=d z+pzLo`PD_zJr8H1jZ&7(+a#?kryGrX8&P~*>RAuPpvyw_`c3MSAJ8Sgx z!b`K#OKPeT#ydSDdSbiEf>gb#EGf%KRdTIC;jFaWNRclyk{R7;7yEn4nNcE8qglwt z;Qac)i`U%t*1GsYpqS z>~?mUp5^4a+DV0yZugV)KviO)-pw!BC6SG;R9&i@Q=RWk4GeNsxpjS(XI3S15vcNJ zMaLrw=7+lZi$f)H6}nWaQe+g`#ia7fbfrcmb)#OQwezIvx;wQhD?tjEdb8wQ5+W8? zHLo+s_PQ5U=h-9WL7t8N(u$p0W=&Szolc37BV|W*ung<7Fh+_so+juZfvKw9pjkeE{WtN6o7A%(Ok-c!h4}&scIp8TqN&Q@%qM^ z%Nu3jE>d9YR+*LQ?inj~=Z3tls%VLnmn7-Mo<-%7zo*?Uu{c&zU6jyGZA}2dqpm?QI?o@M;@}54*{cZHBdcE2=I@8rqpXhqT ze$u_rNS1CiKa_X5n#3+^C&ItDciW?tEz);puEZF+y+&i@73+B<|A18~eZe@ZzMY$Y1s@`n&XW}b(>hhH*V612(WCyyD^I2*R}V;O8TigMR^G3V z^S@iu#(yU0NjMxmA{DA?==Ov+0?Yh8!Y$<8PM2t*J2|w@^Gx6q&qm|4^`7fO_;dG5 z;dQPBu{zFayF8lY8XZ~h8W)*OFAp1sU1sE>TBV;==9>GYsqz)$K38@$*WD)er)voQ z__v)`&E>8nW2Wa7{fZnWp8j>aHG0Rt=3?!ZSR?Jc;Z{F4%cN{)qtius!fdL{i%rrx znZqQ5h_Pi#Ln}*p(_ANiX+J8xB42g-D(_jl)j7^$rH-25+^SrYvbFJYLuDMf<=#^> zl-{Z>*HsxqrJY))99C_mKsl?nS2}5qa#ic4bVA23RwinB${8(5UaQ_DuTZDsE1#yk zs$?jel`Qp&vXJ!xJynm~M(wP8PbA|k=ZbXRDPx_@v)&r-UH;EKzj$r$9^Vpgh39kc zAMQ=w?e4b|278YAzH$HHY3d*DyDPEWJJ|1XU-mEaw)H*XYv}pR^P<|u^^RQbaw!k1 z{pAm(awO+pq+856&MjsLi%oa4yEVpGZMG-x#WLg7*z6dq8)Ln(fpyZCMOx@d;r-!j z;jC~2;^^NAUkF9RABQK0dxlHM5+j8U;Z*n~TsPb=ME<34>+tzV^T>h7alM-!)Q=;d z9cR6KzgV%+oIC}m%$`Kxoy8JSh$P?F-fW+8San6V#*yR@+e_xbZ?SirAvdJs>?iNu zLGn@>d{=UB2UmX}+u=$w$-P1z$eCmaTuENO&(Wyf-v&o#j67S>(;}jr2G6@AnraWF_P$&PWQRJdnC7ZDxA6^d0Gu zI*sZ)#{c1ISJFD9{*l@z<;xT~`RSysNlz#4N_;$Fh5sGjF7Fu63-0DF3Ek>Nxr<}k zRn+P=8yVALzs3eeFGU~GFX~+*o5PjiCqtiy(u4DYO5p84TFpN-D{9`ZSzNQM=KGpI z1N8#k0z(6NSRc0pDuZ=`je{=)KMwvD>KytYWDwn06ZwQVu9eXzqI+Yv#(pqvGhW70 z_prIkYGMtx{OQ)6?iZ!|&g8(9@e53dQG3pERl2)t5ru%>DC6II8mZme8W`B=r3iX#dISZ{K}( z7B&pYDz(1D(v)Y7=eUpK2B6)G8~HF6n0)YaJXYX4%uI5M6dSWxcb<(VH6VICniuP4 z#eK1w9e4AZeogwb;y0>ws@uT^o z)!mwnMR%E9NEX%4oN_WZo{)QDbMYz5R9Q__7pR}AtI0o5s1~SSsY9{Wwo~>ig{%+m zrgTv>tj|T*{07K9nUw?5GHiaC&I!C8W3c&^+DFMsI>vs;PO_WWGPc{0wHu4qcI#zw zcZ{(*TKAKOFl_nEqvkQz^-C-dVH^Aq!Z^EEzGiLM%m-Pv!Z8^?@qu_!!Y^f#`H zeZ*>Hn0M?k=QKhi{$euDk~_jrj(?ab+2WN zXfVFvf`-Q%WjAWpu()APg8`ZAG6!Vr&)8Vsthc;wJ~Q%N`akJI({`pVP0mY_6LMIg z-Ob%mtybzf*X%atve=erR>TTdhrbNxgo2?d!M6j;YR=cRsD8WZa#d#KQx)G=bSnR| ze0}+p^4aCPDw}p(c}y^i}e{UX=cj=8@ep9eOnuORQ{PWDWRAdxgE& z9&SHPO)cz>%*`?D2$t~))~n>F=t$&e>Fo1vl-5O3zB~PX?7fsfkJ9gi?P!Z?gMltpgE5d#&R}I5tuLGEyh3g>DW8L-m4(g3ksv z)#O)Ss%}v=u1c%yQL(wAYx%bF56j;upHRN9qFzN|)egaiZqIn$3Zvz^K56 zz-hczj|JC-GD5q<_eNZillmLc>9NkSL&iGOV}4{kXic`=_VeTx@;JAWjkgi9=K-=8 z%v0JZ? zCvxi+IJdzm66_zDm#>(W{r2njQt#=EAJ#7GkhR)+&w3M^ z@i6T8E#VsFV9gh-;C{;NVKy-pVt0SRL$wT_)nKES;fr01ZD)4I#FB}S{!@QY|0MRL z`8T%IzOMf6T=y#X!|wiM!YcCo?Rz?5XL93|t8nfGDZx}N?a8{gW$bBqwn>X7*P7T( z7B$||=#Pe58suh{WiH8FnE7XK38$NVpN5vyt4d2`GpF(Vqk?? z`B~NC>OR#+YVNK1tfn+DDDY9>*I?^lm*5=udsb*`_`dM*$P#@xzKycjA~Hr5oBfch zdXn)gOqSjS_IAgIpP+!8)UV*#7%s1sFDZ{GgP5lelw7_?E5cIzJ9@)xxrLmGjr>z- zADOPFOH;_|+>*?$-{N6-nXJd1p<##NCvQ;d3*gIB_Ol#|?6=4r`!!jY50gvz2kw7u z@4-j$wY{Dku=&j58_eEhdz3vI{JO_(g}>t*eCGpeigmk{K{liBS#$p!^Oa(pF-|a7 zL&&l5EtyLu;j?=|e}!oLt+8jUIr1x7PxqUiN8P`Wr7Q=&KgRo#|E{DqDP7XqrYorx zsd=dj(`xFy*`Q_P)=kGZJ>K-QrUROEXq?mNv4&|4<~Qh>sb_wc@m#$*b+)B9OM5u2 zN$S3olH_L-yZV0hY;oPHrb=b@D)VH_j@}UYFmy1O8Az|us=sCR)Em_ctJ_x{s_IQP zqtT+i&HKH5N` zs_!E=$e3s@k<<^z7L&WHk1^gTH#_1(ze4tul~xd_p27J2=?p}U`ii{geWiEtja-r& zAPLlwC*ZrSE8k1j?+awpo+Ncc65h+R3HCllco-bTN6zR;)-zUr>rSfyviuHnzgcXx zvYMHf$v{UgONn>^hB;-}FD@o#n1_y{Rr$8as(*zv$#p>zWx=T19R} zYI(4HX?f~3>8khg*~=p@e|4qx)kWpG6{o5Ss!M7TYt9Gege85bF@V135?!#s{@5v2 zvK3RkMm*bh$^iKql&DO;(|N((Vhyk~>kiW!D`qv&_;60Rab!!RFjN)H4crk}5Xy}V zj+90gg=a((^#!qOly{t?pM8fkRH@YVX-g^bxYpQ}#oEM~?jf#r#HO{=>S(`eBa~O9 zznypOJn|zCw0oFyiIe{zIxjZRXcfIKawak`;@01aPK{30_vwB0zoY$Qdl=&m=Kbbg zE8W_JEFG3!B8&SnX}f&C(vVn)7R@|(OJ;}(T`anI3S!x6!Ak|DeZ9mJL2!-e6*yh7`fBvb>dT*A?p^lJl~NP%L9}f)B&z8?rWa2-u1p^z6<^n{wcm; zo)hj{TrasE!G}0iy;T}+zeI-XCt@3-U+8-yDdDc69!TbWgWkZ-nu1_vuq2cp&SwVm zBHf6LEi=23(>mMEc8c(hJ*CO`;wQLTxVpOsdt~=)_oJ?-w8gFl+H`GSW6BayfQev?Y0c*62@1&P9%~7G@&S)@{+3qibUQjZJ2MYohg`wZ^{3X(%<6 z`^a0d^ZX#6Q9e@VtE_ufZdY0d&u{(zqS86viVy6UcNS-(VnTE zyIgx+Bh(Chs2*#TSw()rcCqG>s>t}zKfx2hUxNLD{Q{?g-eAXIH1vHqExbF@MDHF; zioH#g!glK)k+ommByUn15U+efTd1vc)h8RvC)!WiE9ynGY9Gt} zQYSZU)9Q4y{qsn7&Yxh^~2Rw~ES)M#^s<*D^ISLP zWY&*JL+qFArRH(tOUBVlti>Gc5W^$SMtVg$MCuX~lM`7%Ow7WlE4n^5+Q>8(qn-R^ zt+R&`5%VDaja#JOWKJ$R@x3dg)&zMn8LDh`eSOojyo;Q;;L3 z5`7}1?^AYXIMpN8G5o%htZKB^+wiwvu;0TA{1LX9b#{T{wrAP}NFo0sg{+5uAGTja zI=lyNb}Z{Yh1xWA?IWXRFvN*K5=G zP~(O5#wWk$@0a*Pdfg0PgRU8WW&Dx(T*Hh;_huH7$+=DPnNyXfH9(ddQf*l1TcKx2Jxw2NL69UPq;?GybqdL}k2_OJ1taUQ8;KbC-D z)^6rx08(EPHo145BhnzK*BT;BdJqGY2;Q{Cg678xl!WzXne(gjz0(zs+EAW;h`5qp z?fvXv@Q>4wT~XXljvXLcRuSDpK0J4VJbC5ef0bV{twmeD;3xSDG>}yDvVYI|O#1}qIM%9z{ zG)YmA#%7Ntp?o-A(LIW8Lld zJj2rc4V28D>1UD_`e!D#NF7@DVEy*>mU5UGlQJjPUsvamR4wUv@~5dv+NM+~smdSr zdR-qYU7S;9W1{3b7**yIvHIbW)vGGbmVaLPWYv7*>& zGx8O?NWxXOS`X1!RdE%#r35)@JRr z_8`|aw2wM%u@JpaJj+>UtMmf1m>@mOybee1f0`(uRQ95o&h8fvu!l=Kb|9(G&N$16 z=Ge|IMZaN>t-y=ZkiA=G620*T6u2|?*Bi0MK86*shkeFr&m33V+n9yF(X1zcU&HLX z(c+##18_0F9qsn^5I%Pk4YLu<>x?crf*8>^?5)@WpFksj%idvsz-+H$cb0Q}27&F_ zMDt9+hII#e%^INLAv+cL7|icJNMk=)HP#RIJ=PxN;Q7{AYl-!;sbD=E)I&%AOk&oQ}j3S!zS=M(r&k-KLOhZh|&edlqX=Ti0#cYifP` zH1Eq(*tA+nX~CE+WG=G7-!bg4vw`_}o5ZMxu-VB8ce zTdxz-wjV6q0jIs)jxhTtnE8YDN^I+?T(^l{Yh@cway*JH!@1cu@$y|J66z7||3t5K zJ4A$BnOy?S|I^;Vjwmbn|0Fg3LrFV-#>bUg{lbKc(fT-I?CGPHNrj>g-AlCclul zJMn6AX7bVG8xl|ZmwL~*_pAHmm+fw7R4w2rADM;GicoRDUtL;#F|d|6(O0oRP6)^~ zdzk$R!KT44!$TswqZ`P3It3lPspYfIJ7cBs@@L9@>ciRt*bJ-HH`I^RDlJv}K)Xe2 zq<*Gs!f_yxDxg9F8W8r=0IM!0&a&qsE75#ueoMe8l|P{0`k< zESCG7^t=lrU(Tq8!N$j&GH0oCk-0pD1-}b>B6VlSs$tTb_�(!xyq|(}UOnhO={0 zFKIrsd@#EdjpuGhsSSH(wP6RbPR=aweIL8JY+~P?Rn9ZWO09&g%()I9jo)dA_IL>m z|7UxxeaN26cPZ5OfSr#uZKnOLBeCPr8T&91xCh|uK|APVv4_tfMoInewdFm^XPDT%$5M!+RH z02STAkC>gx{x^-mlf&j@dzsq8z1nxi(_0}n*GiDDcwb8?NIRKQmgx31_8v}Xko<7U zh17dfwxxQ~>ZPZo9ZvZvX;8v530aA$iC-n|Oz7p??oD%D)$W!bbM7YlhMM0CFp3P&_@O|%5pcavZEUQ4z1*}piyNyTiA zmycC4n-x3j)Em_eWL=+v-2If6q4r?C=QZ|C3KHM@5E%9qqqf#gv)(Ze60tiH8)I8E zZm+S@>|pG{-g}IleP)|kRuWOZCy5N5N7U{~I{~?AD|bD-o<)43jE#y$6an8Bs=vy_UhUM9#@c8au8OA zp~w%dp+k2f(ci%iVjY30_Uv_KIL{OJUl(tYj~wHc^DI|-!j%-t7ZPD9G~sXiij#;$ z@FycvhNa>!XvSeEMLALH6<8?3@ywDQTC)K-J4;0EYNWw0kOU>HOD%{Wy4U@K_d{1m zF0r=QijwbZp8QH`O48Tcs7j70FLgvYbv6R*ic|t8i ztHO_9BiKOZSI79qOgC>P$MH6Mg|kX}6Dv+cIjA;PekT6)1*JkwSC^}Qs<){(D{m`x z<#!|ppTQ_83y>mNN@kdK5T)iG?9cDAcH=o@x%qeo{;(A6o-6Sk?6yu@ zr|ogj#JzSgbOJBRrCu~XnIBAl< zlc%pc>YbKwW73UD&5#0`Bt?^dOTLiwBedaH-@E=c{@)T>V3*qCdCOI<-9of(4{AzA zr+n6_Yc-GcBJWaR=t_7&WJzRe_wGYlxEuMPJ+j14#FOtp zkKT@s*0dD>V$B&SBu`7IQ zFl$5}f-l^T74jw^qCK|BK4dGp*LeV5@eEfxapiWX$K7a_&jBS50ztO}D-Ss>DPt&m z6t?156Q>DvcBj4)ESP73(PSXtBGjpZ`hP$c`4R}JhR=Qq?b-`}xdPYG;aU+p2Gwc> zRTH$N964hHZJxy%lF8^P8P*JIxV=E}y4rf4cPA;beZAFQ+UA~_U?xA5IM!Rms;Q>l zp$Q!l_a&}R9G$o-X<+gg)=R$QZ{`j78u=prfPa^7fv3Vvq?tNMEwhlQslwNFl>XL>5Zb3Vy~f7n9z~|=1{AjwFCTGD?Kbf zDz9aIf{fSkZ}}f6$TqdFIvTyNMCr%wXG1v}V?kbxwfH6^^l9MB-RRNviFJy_SB=cH zKElu51`k(r>v?Mk)aE_w5c=__c3;c3`?Jzu4D+{-+3W;nPG^)yK?%NQwy&ap*b+OZ zqQ$FdfgbiL90LuR2Ax?fJ;#cJT&{kAUNI%EQ@j9VO+e0UjkK9A^~57ujePMX`}!?# zmII5q%yBldOA-+RY0!vnQ2r?NBbk{jblSpOesk_Ym-Mi9ECt=7l69>$Y%BW#(2~u& z1Fv=+0U+q^YCUICZqFYaRKI<^Pz?yF`18h!zLpA$358GJxq z&JJm_oMXn)=xoy~kM=y_&-L|peWJ9NpHy#f@9?$u4fbC0&hgFjUru=5|ADum`*HXE zo_Bn?{yTiHdh5DhWk-TLl`45LSlU2Nl*^RsrAoV-v4yN7VWW*X-Rg}u>{0U9%rV|F zrUFBI%nvQYX+Y@WAm*Y6n%-6Udu4&TN6T~F;flKcaeG}c*Cuz0`)>C+&sUxkUdc1b zz1{taOLv{cbNL!OuiWfP(sr=sC6`q$%@mbLgoW%c`iJx-GQ}>mfql^C5ol@;*jdQu zw*XZuNnJQ=!BLOv2~q{?Yrd8?VIdz6f9nC4Yf1diZ^Q(>kG}FU zl;Re4ByA2HD{!ZiVE#$ui9>LN&CrOm$O|WF%L(W}#5U~9SS#8W0t-yR9&F`&L5 zpNT}XOaco=BeBe2&CN`x(HPDr@p+E(iDaT1$FFYiw2|=1C!kG_L%(`J$vV)22k?`2 z=YJO1)X}*CTGfs^+VQ^?5HIB7c3f=?=gy*~jc9Kj%DNrCD2`Sfchas5T67cpyWYmg ziCtE2f=1TmE%x+uZbQId&=M89Xz0@YLYVF`P7I+uh-v>U1#0|oosB3jGoeeB#+c+y#Z?++efw7RAZsB zpG<4{`l)Do>_+3P)d_j!PPF~qaD$(qG_SEP`Z{@zvR1uCi6}kfcjc~lI4&vgsmbco z?78t0aTXr|ZIk4iuq76;its)~A{IS>9HT%EBN&;3*iS+{c^v-K1kU{p@pY|A`*;>j){-tQyY^b~ggwpfsB*z0xyI~?D{zP^7rKcb1fiZtCN z&V_a(hkS@!@-+Iyb7031tQI#zWxHX;7-kPZhnp&VwLJ4R+VdV{91B`^6GuN{sfNH^ zryze7uq*L596O<(#mHtSI8I}a`H6_QKfs_}jKdDBs)wM`8;Fp59V_;myz?;-JPKa= z5K{dF=Oy@O3UJm9sGP?6^*~@E=e>d9N0GDOtMR!};GA~%Oz8ji`}Z9xhT3^udm;t zUx_x-XW+xRFB&5LaGy~V-4WT2muP(Kpm_~VIsqT*2LAW5?}r<1vtN_atp5wBhq-=%Rcu??iM5_mOuWN=${8h19tiBrMViWm9<9KWzLq^o zesk^z-lp4c+uzz3z~V$KpG$~(Y-ek>ioN7v=;CRxwVV<999i}UBITwqn=z#E=0p(< zVZZ4O(hl|&ZVycE#s7Ck{t27SlJK6WwFCUe6;m4XIzb(Io)OZ8* zahJ3d{@WK#;55GcLf~T&`x2W_y>F3Lwk+}VY^dJk|q z4EbXx)ME%WrGgDFWAT`W6u8&k&J`#-nulbaa-LG!kRhPA@|(TDc-%N5!4uIEC%V3n z8sec{t-awrLoSY)_<`HG-}G(pulEkt66MCS<8J8RoA|!}9@p3MDRy3ak@eY<MJ} zS#n493+)?avNc!#H`nl<>atJutXiH?2`K-hg>JSl>tERV)a$N?@}LCJ*;>< z#NO2Bl<(D-k!Vto8*d_NaJN(?%hEOJ2zz;-kT$X>@&`cbvrwx5<31O;>j&28-^dKSp`v1?a{*FZSL_s6qM&H&pe}a<6;0vJe^Kum zuww%eCCl*HJP8dQfv!K(eh2t`2im$8J?wk@0cYWaZs^vnyxSkz^%8u0E;Mi#o{IDA zIQ$!uMhNI^h@H#A)}6^&C-6+;@UQ|F>!@Q9*ZLRHt=LUy$2Q`{J_B%5%6grwRQn6#{f+Yu$!bahBJWdzVK)-ko*d8xEM;@la@V)7OpK>ls?=uPnD9w!}o5kimX1Ep@n z_-sYu+=XV*7E1CMtBF_GSL89O?UL08otKT1MmzgEt-_z0AbGmUWbP&E!&W8&Dd$*|`=xpdE3ju` zJGn)Eoj8~^Nc_i*0hE5S9KpHj?Vo@;lMY??8*Mhfl5nc$f)nM}VP&Q0D_c)=$n>Aa)XPGZpxqhMwLZ z8hb0BzDO8-fu@$g=q<>XeWAt=BBkB}haU~6pAL2H!_^#Q3G7(l`V2~#0qtB3CI1kr zyBI3Gk(#!0B@gJGOwWHr9{Z3tAE(BAw8l^9LqBF^SiF?w$O(;r)K0Xh0BFuaPydDA zFR=&xVC1qTSbr~p2{Vvqn_GEyE9qADSgh8D$epcw+0Q9e8R~WUKkX;x?#H08$36Xh>wM$fBb3$h_3DG3Z3zPtKJt!GLwKWGs9x<^^?P|Mcz?I@yf#EV zDLrPq7^#jNjU8p>@*d}R^B?kiHqiS-8x!Mko&H5MIX2I{3oA>#=wFdPBM<9K4X@P~ zc`eVXCUSZeUgq=G70V(oW+(Y?HAU^kI*=Q%nmoj=a*wfk?GN<|yJgK)+bA1|vn!U5 zDgD`J=rz`dI7%mZu=E4m`4j1koGG`LEY@rFVRpx%s}#b0KfyXSnEBA~gI^^t&96wc zH)08&hR<8@?$uE0;lR|-@WaKg8vYfM#Gl}-;QY(^ zzXB+^898+#Sh4^Js|Vff1q8m%c?0yJ?oi*k(C0g$&UXWC^Ejq}RXM=1&^zDdt+iOg zggqi33@L(-okgNvP6=Cyi@SoHogbGYw!jDWQ_GmRtzt29&k`tiOXT#1!2A+glm*>o z)iyZ)vU3+Y?k*^@4W2#XB%yCEV#E#t<2PdiTV+{L=gv|iMJL(pQJ@zxn4#F)VRAT+vQRNyV@KTOVR^+Wwa9+Z7#DTmSfB$>he9KYxF@~ z)>}mv8}C?MfZ_!5fSkadd0PD0T2F~82}H(>U>(d;${4jPIc5w^R!_4# z)&WUna&x&Gn)=uH9eW`^uE7RZEw~{ToO9?q z6Ns(ZM_olkV&p@=4|AH$ zf3Sa*p_ARL^hLH9uH3D(R1#&2{2Pa$-vv>bZNz?mg6HemxV1Zjx!eG)nTSN$ z0guBGB3F0QvQ5~B-@vo{Fx+A|n%axRgFFqT9tS-V)VVM&FP{|FZ+J{LbnpBdyrXWkS!jtBbnn9C$aCDLCU@vP9Ufu+)t_x+p3_J&rjZelQ{4*qsFQA0) zA+wHxM!twV@d{XXFY@p0{C)`t?1P1~1=`nGD6)uMzn{-Ao_Y&to5~ZTfciy9OohPi zETDHb6k#{ie?6^ZS5)x02#I1Bl=@wyjP*RXgQxR&Zb6)`=RtLHkTu?nuY>9hXLu}L z@1s!ZdQj_ophSHu0pNceUEpVZ-{4?Hd|?}eB?Up z%S*`eZE`0nJLSpB9Ym8OFSAk66!{Z%jJl5%^s}Nr>I0+atYlhz#HupdL^JehdQr3y zdR|4edu*_Az+7Oa$7ZvBP0_!IO*f|^bKGY)fM##Cz9-866!dhhb5icDOi+F&MsHl) zUK$0S&LKOWRDUL~OGmu4J!KtB>rmxibqE&3X3FbO%`RA{zLfS#LGtTABWFpU!bgG5G|8i*LyYT&|(EI124L;6HoCOY!!P9R<)0+#N z?vYh&{@-GEI3$0J9=8+u;~rvHuLsUOK>8C(7j(c4a-O_|6(>K*Z&H6yI>c(NP1xzP z;}BLF=fLBbrG`LwIk>kS_%5LS`FI0{V{>>68G0l!8Ix#79#WCWF0&C0^cr(ofj=V? zXd4f`6WY~0AoMq&Tu9JSq>B!~w~Cx`D{{v}KzUnizxRQqw{xczznV%Obnk#9;Yo5K z4HW>JpT(tu^}z37;Q3u7>1XgIwLn&W7C3$yuYidi;z90D0AcH-Le&$hXs|Gi!781|NEEm{MdQNX$HmE zijD3aN*VyATF4lFYM*B<#44pbmgXDej`keuM*Bl$iu()iSDt?AMroMyiG0Xa*E86& z*ge6u)D`hG^L*;wp?$CRVE?#M^4)*zo#{HIK7%Ky9AEK5r9HGzZyf#(PqooT>Z1id3{l=15qd2SxI!76)fwJ zP(CFNyatO%FCbQI;rb$x{s(0RYxy@=5vF3@-i9~wO;*liAQ4n3&yhzWK?y3Gl!u_D zZzIzjCvtCx^slT)VPLcc)I)e-+A}w4K)VYmB?x`YC96?G@)bRVq`L}uTM6ZS4XU~p z{p~O#D=bB?!E?Wc8vO;WY>jVe7M$X&?3PLW`Eg|1?j|=vU#LKX-Hc^sw)8w+t8_HB5{^T_!yIP-HQmf?b;Szhp=FnmMk{P6)-H;S+#P*N{Reu5KSp*H83}syi{Cy7`eM^}K_xQa4 z8oU5ny_oNJxcV{FdL5GVQl8le&TNK0Y(rDrgB-sH`DYt?z)7@#ahFAD^Mk zSBu#{_!Vqss#-^@uN`&ua!q#Kr>(&M;#1SqquM#w7S};n4{Zu|%TW~Pz8b({oS)o-2Z+JIiC3=|iEE%6@ z39+9oh$0m-%s+N(`yFhMZ_=kLjKnYWZ=X{EUmn5g)&SlF4>82skPF62Z$Ul(mSSMV zPtqz@y9!Td3n`JvxaO=FYwS3TT^@ZO2&Ww%=eR@RbX~EEHpNrrhk7)oo!Ri|d*G5C zh;|T~&`d^g2{XC}xw0Cbf5nNQqjf_*e-0br%lKA5!shXz^f40BX)MSgsgxDB-*bMA z<8RusM=FNX><0Ii0OzmK&R6h{^dYjRJ?(2kX)@A8DfYErnV}z$V^=fB>*KJt42XIY znl=ZBdyDV4IG;;Y?J&;fSgPbyot-`qge*SaNsluKy}`Df5-B z%3`#=_t`1@QF*`e5T5-H$thL>FCT*4&60kTN~8+bGG5P0(HCgl8*x2+3S4m+pIqlY z_|8V;&nMx_XYo*UBtj~J&bI;yb-R56n7$9LIUPPY0^Oz?lG!-0b|1YG6zEsRXg750 zXZloy4c2C~VsWd)Z#?lYkQiVLO5=ynr%p3ohnSgjjMr)YALlsDxE$kZ3D?RPuS@(E zZ=ZLraa`deMw+sjl}aas?JT|lCH6EAvO!bq5)Gm4ZTQ@b{Cgu(K^wHajzkaiKuQpD za3?;U`R)upWC71NAvd%kw%|Jcx8(Vz;Atk&h;HD)jC-7Y!ba!l)ERVYfRi%dubQ6K z2n~|9{>TWNWR@=@Szn;%C7c!0OXwhNQjkqFBypL1cf_|4q22+j>n*gPHCDg2Sb@6J z)>~<13cRF-ntfnb6Z(_HIG&`mUqr2FG9gClG?4ovqx>&+Pmh$0#jqMU`;~TFBa$+S zai~KrUP-0x2K9^4X&txBBmuoHq`d^%p;3pzbEIwI{V?UncsG%ryYQ7u$XFiYwbHRx zrt@?HIG}S}0^-ZDu2)fORh+W?E%}J;bo1*f_y3^IKWJruTGDvG4x^`1qKa)OiI}i7 zzQy&_cuO4W@naE5r*0qrWquiqfy7fT^ztO$OP~)i$_t{qgs34FZ->tBV7%QTj{=U~ z`1J_S)o?Y)HG`fS&`!~Ahh8Mn(>jbw3geG#NR26?eSEv=PlQnrBPEI17L<}tBBLVe zzQ9PHr-#?@_&G?HN%8((qD~#1OJcrU%!I;khd#JCe6*Wh(?=iUkR;l|eSM5>4Q zAB{h+Q*s!%itsGGkGE5zWhyQ6#7h#T*nAv*Yg|c=w>?NHL159M?gY3>s#7USiMOVV zdzbhXpd5*NGEteDsD)Z>#$KYAD&yc`JW^?CBImT3vTXV)dK}>$fn6d$1+Yaa5uO!) zqLrdoDt*yJ53&2uQhurNwmV>}b0f8uR}n&o)^;v+;E9^Ol&yae9VxM$OA@s>#| z#R%fP;m~>CAHh&-2Qg_w^RZn~1OehXL zUf@BrM!-WQ_eKA8N)+Sgr#)=vDn^>N#QPQRIge97~lVYG=W^|a~LHtwxV=q zg15!kiYLXK*qqt%L$sIi<=NUpj=v|)1w@Fs5i=^FskTM|rL=+f#XM=eS=(mOr~l?y zl*T^)ifFmY; z#YgmiwTp3PWH=;7Qb3@XJ2AduhD6C?HpJNRBv&>gqQMSMw0o9@=Ee@Sx?ilI#FF~v0bH{yw4PxZ~*Edm%=wmJQ z6Y~WeP>{e#0c8@j$ApH}UKO|tw*WS&B|hF^dR@)0AZ5gWQ1Dg2ELW(7_L*^r6Hq5c zSoGZBOlJmko?*NxQP4M&Pi@Zx42yd_P4C3WMEFGGZ5KTkPzG&_&k(JT{}M1PC}-_G zfuA1EMg0afMdNTTY6FvLV*(#Hcg2ix2BwPAMBfF*5MNARmWft~F^uCI zZ`965ErqBZRWTN|^ocf#v7>FGFK|pss>O5BK2aKT!I{7?F%E)u15@#N7QGVV@juKL zkR{#_7;MKON8o}UFTb|k-gp^;GQ@c^Ps2kf5uD&jF_z*=E%g=@EAOlyhJ3H8CG?Uc)sZ9RZ>Ll}3T_whOK!KBC08zb~kV zs8zJ4mZpmF1_R?S2rRC>U&{?@YZGuHMxYjxvHwfExV zMaukLosin{Q{mv@5R`Px&(d* zz9+C!v{+zBoQCpC)F?PWE$oST6cj>G%Q*M?Z)C*?iJ1^}*76?#$zld*gJ_W`Thzq+ z;t-ON;1#uFT01VH4Wd3VkD}%Au@JK+#y$SFkO^oZWg!Q~`&^4}Vs1n$ zeuwW`{HleE+Fpqn5pXHq67>nV6~9EuwLD5tD}fEQ<05L~kGubUcwf|1J3pe#|AUxX zToca=c#J~@_eIO&93wu0wNKafSDe?rUpph>x&OT<>JzXTFDc#{(URIZ5WN%QEU10$ z2!Lli4VH6F$PcwRDCS$xZF(1PlPDqniT@H1Cq_oV+W$d^fDAD!|7&ObK3C!}5Pw?K zEw0wKzLq`+m=v?ioN})g2gNg@pJH?c<@jIk#M%EoJRnMnza?rFf3-AQ%%Z4OJSkx4 zKfH@S9mjy$5-D5Ing4sY_UwNp(NWP?YN@SVeEZ-w~942W|7zYiDV zzeJ1UPyTnW_MLcHJiHM&Pv%ksxF2Wd?` zv9tbV6hc?Of0&MJyjT1txvI;X#!veFEL1iW`DwMQ&%*VVOI@lmbvt6#eFt>r^0=6( zSPF@JEpQ?d3}SiZoE`wXhh%_}xfGGp2s`U&D-|5STsJ}<6m$x>M-;^~KB+0O4C!6$ z9Vs_!ylz)9QW35cSPY^Ip#~Gpv~69GcScx35|xK}LBt!8m5A(Yd6TcdT%?9y%h#`| za-g5}Le9>jTHeiedi4KWH^f)B>FQ#17!L#Jq1VVgQO%Hj#y*$A!On+K-pYj%Prp!6 zruXagn>Twa@ppi}tqra1_FaD=;GIv;`pnQ8&{T(*BS_-9nvJVQD>Lj!dCqQBl!;oU zE(6^W*|P)Avy<+PI;g zIF}B#TpULaw2V? z90MaqNY*cpTHJp*6fn47f8_tGSGh^0=i+pTe(55_?>Hc1xC$ZD(;d_TXVl8Qv1%6; OI?ly&pSjrne~=%dqDTz@ diff --git a/makefile b/makefile deleted file mode 100644 index 0bf7b97..0000000 --- a/makefile +++ /dev/null @@ -1,13 +0,0 @@ -clean: - rm -rf dist/ - rm -rf build/ -build: - pip3 install wheel - python3 setup.py bdist_wheel -upload: - pip3 install twine - python3 -m twine upload dist/*.whl -deploy: - make clean - make build - make upload diff --git a/pyproject.toml b/pyproject.toml index 71a76dd..2e1322e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "py3-tts" -version = "3.1.1" +version = "3.2b" dependencies = [ "comtypes; platform_system == 'Windows'", "pypiwin32; platform_system == 'Windows'", @@ -8,7 +8,7 @@ dependencies = [ "pyobjc>=2.4; platform_system == 'Darwin'" ] description = "Text to Speech (TTS) library for Python 3. Works without internet connection or delay. Supports multiple TTS engines, including Sapi5, nsss, and espeak." -readme = "README.rst" +readme = "README.md" authors = [{ name = "Vignesh Sivanandha Rao", email = "svignesh1793@gmail.com" }] license = { file = "LICENSE" } classifiers = [ @@ -25,7 +25,7 @@ classifiers = [ "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7" ] -keywords = ["pyttsx", "ivona", "pyttsx for python3", "TTS for python3", "pyttsx3", "text to speech for python", "tts", +keywords = ["pyttsx", "ivona", "pyttsx for python3", "TTS for python3", "py3-tts", "text to speech for python", "tts", "text to speech", "speech", "speech synthesis", "offline text to speech", "offline tts", "gtts"] requires-python = ">=3" @@ -37,6 +37,6 @@ requires = ["setuptools", "wheel"] build-backend = "setuptools.build_meta" [project.urls] -Homepage = "https://github.com/thevickypedia/pyttsx3" +Homepage = "https://github.com/thevickypedia/py3-tts" Docs = "https://pyttsx3.readthedocs.org/" -Source = "https://github.com/thevickypedia/pyttsx3" +Source = "https://github.com/thevickypedia/py3-tts" diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index aedc347..0000000 --- a/requirements.txt +++ /dev/null @@ -1,12 +0,0 @@ -# see setup.py -# pyttsx3 only requires `espeak` driver/library which is system-dependent - -### Ubuntu -#$ sudo apt install espeak ffmpeg - -### Mac OS X (os.platform == 'Darwin') -# pyobjc>=2.4 - -### Windows (os.platform == 'Windows') -# pypiwin32 -