From 871cac6b724d09971ed60e157ed8772af2864a3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?y=C2=B2?= Date: Mon, 26 Nov 2018 02:37:32 -0800 Subject: [PATCH] TTS (Text To Speech) for ROS --- .gitignore | 2 + .travis.yml | 28 + CODE_OF_CONDUCT.md | 4 - CONTRIBUTING.md | 61 - NOTICE | 2 - README.md | 247 +++- tts/CMakeLists.txt | 71 ++ LICENSE => tts/LICENSE.txt | 2 +- tts/NOTICE.txt | 4 + tts/action/Speech.action | 9 + tts/config/sample_configuration.yaml | 6 + tts/launch/sample_application.launch | 13 + tts/launch/tts_polly.launch | 29 + tts/package.xml | 38 + tts/scripts/polly_node.py | 19 + tts/scripts/synthesizer_node.py | 19 + tts/scripts/tts_node.py | 120 ++ tts/scripts/voicer.py | 50 + tts/setup.py | 33 + tts/src/tts/__init__.py | 0 tts/src/tts/amazonpolly.py | 428 +++++++ tts/src/tts/data/connerror.ogg | Bin 0 -> 23124 bytes tts/src/tts/data/error.ogg | Bin 0 -> 27767 bytes .../models/polly/2016-06-10/examples-1.json | 171 +++ .../models/polly/2016-06-10/paginators-1.json | 9 + .../models/polly/2016-06-10/service-2.json | 1022 +++++++++++++++++ tts/src/tts/synthesizer.py | 206 ++++ tts/srv/Polly.srv | 22 + tts/srv/Synthesizer.srv | 4 + tts/test/integration_tests.test | 7 + tts/test/test_integration.py | 214 ++++ tts/test/test_unit_polly.py | 178 +++ tts/test/test_unit_synthesizer.py | 148 +++ wiki/images/cpu.svg | 4 + wiki/images/memory.svg | 4 + 35 files changed, 3102 insertions(+), 72 deletions(-) create mode 100644 .gitignore create mode 100644 .travis.yml delete mode 100644 CODE_OF_CONDUCT.md delete mode 100644 CONTRIBUTING.md delete mode 100644 NOTICE create mode 100644 tts/CMakeLists.txt rename LICENSE => tts/LICENSE.txt (99%) create mode 100644 tts/NOTICE.txt create mode 100644 tts/action/Speech.action create mode 100644 tts/config/sample_configuration.yaml create mode 100644 tts/launch/sample_application.launch create mode 100644 tts/launch/tts_polly.launch create mode 100644 tts/package.xml create mode 100755 tts/scripts/polly_node.py create mode 100755 tts/scripts/synthesizer_node.py create mode 100755 tts/scripts/tts_node.py create mode 100755 tts/scripts/voicer.py create mode 100644 tts/setup.py create mode 100644 tts/src/tts/__init__.py create mode 100755 tts/src/tts/amazonpolly.py create mode 100644 tts/src/tts/data/connerror.ogg create mode 100644 tts/src/tts/data/error.ogg create mode 100644 tts/src/tts/data/models/polly/2016-06-10/examples-1.json create mode 100644 tts/src/tts/data/models/polly/2016-06-10/paginators-1.json create mode 100644 tts/src/tts/data/models/polly/2016-06-10/service-2.json create mode 100755 tts/src/tts/synthesizer.py create mode 100644 tts/srv/Polly.srv create mode 100644 tts/srv/Synthesizer.srv create mode 100644 tts/test/integration_tests.test create mode 100755 tts/test/test_integration.py create mode 100755 tts/test/test_unit_polly.py create mode 100755 tts/test/test_unit_synthesizer.py create mode 100644 wiki/images/cpu.svg create mode 100644 wiki/images/memory.svg diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..44dbcd6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.pyc +.idea/ diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..cd519f1 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,28 @@ +sudo: required +language: generic +compiler: + - gcc +notifications: + email: + on_success: change + on_failure: always + recipients: + - ros-contributions@amazon.com +env: + matrix: + - ROS_DISTRO="kinetic" ROS_REPOSITORY_PATH=http://packages.ros.org/ros/ubuntu + - ROS_DISTRO="kinetic" ROS_REPOSITORY_PATH=http://packages.ros.org/ros-shadow-fixed/ubuntu + - ROS_DISTRO="lunar" ROS_REPOSITORY_PATH=http://packages.ros.org/ros/ubuntu + - ROS_DISTRO="lunar" ROS_REPOSITORY_PATH=http://packages.ros.org/ros-shadow-fixed/ubuntu + - ROS_DISTRO="melodic" ROS_REPOSITORY_PATH=http://packages.ros.org/ros/ubuntu + - ROS_DISTRO="melodic" ROS_REPOSITORY_PATH=http://packages.ros.org/ros-shadow-fixed/ubuntu +matrix: + allow_failures: + - env: ROS_DISTRO="lunar" ROS_REPOSITORY_PATH=http://packages.ros.org/ros/ubuntu + - env: ROS_DISTRO="lunar" ROS_REPOSITORY_PATH=http://packages.ros.org/ros-shadow-fixed/ubuntu + - env: ROS_DISTRO="melodic" ROS_REPOSITORY_PATH=http://packages.ros.org/ros/ubuntu + - env: ROS_DISTRO="melodic" ROS_REPOSITORY_PATH=http://packages.ros.org/ros-shadow-fixed/ubuntu +install: + - git clone https://github.com/ros-industrial/industrial_ci.git .ros_ci +script: + - .ros_ci/travis.sh diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md deleted file mode 100644 index 3b64466..0000000 --- a/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,4 +0,0 @@ -## Code of Conduct -This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). -For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact -opensource-codeofconduct@amazon.com with any additional questions or comments. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index 43b98b6..0000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,61 +0,0 @@ -# Contributing Guidelines - -Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional -documentation, we greatly value feedback and contributions from our community. - -Please read through this document before submitting any issues or pull requests to ensure we have all the necessary -information to effectively respond to your bug report or contribution. - - -## Reporting Bugs/Feature Requests - -We welcome you to use the GitHub issue tracker to report bugs or suggest features. - -When filing an issue, please check [existing open](https://github.com/aws/aws-ros-tts-ros1/issues), or [recently closed](https://github.com/aws/aws-ros-tts-ros1/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aclosed%20), issues to make sure somebody else hasn't already -reported the issue. Please try to include as much information as you can. Details like these are incredibly useful: - -* A reproducible test case or series of steps -* The version of our code being used -* Any modifications you've made relevant to the bug -* Anything unusual about your environment or deployment - - -## Contributing via Pull Requests -Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that: - -1. You are working against the latest source on the *master* branch. -2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already. -3. You open an issue to discuss any significant work - we would hate for your time to be wasted. - -To send us a pull request, please: - -1. Fork the repository. -2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change. -3. Ensure local tests pass. -4. Commit to your fork using clear commit messages. -5. Send us a pull request, answering any default questions in the pull request interface. -6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation. - -GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and -[creating a pull request](https://help.github.com/articles/creating-a-pull-request/). - - -## Finding contributions to work on -Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any ['help wanted'](https://github.com/aws/aws-ros-tts-ros1/labels/help%20wanted) issues is a great place to start. - - -## Code of Conduct -This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). -For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact -opensource-codeofconduct@amazon.com with any additional questions or comments. - - -## Security issue notifications -If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue. - - -## Licensing - -See the [LICENSE](https://github.com/aws/aws-ros-tts-ros1/blob/master/LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution. - -We may ask you to sign a [Contributor License Agreement (CLA)](http://en.wikipedia.org/wiki/Contributor_License_Agreement) for larger changes. diff --git a/NOTICE b/NOTICE deleted file mode 100644 index 14c7012..0000000 --- a/NOTICE +++ /dev/null @@ -1,2 +0,0 @@ -AWS Ros Tts Ros1 -Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/README.md b/README.md index 1bb2e76..37392d7 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,246 @@ -## AWS Ros Tts Ros1 +# tts -ROS packages for facilitating text-to-speech and the use of Amazon Polly. -## License +## Overview +The `tts` ROS node enables a robot to speak with a human voice by providing a Text-To-Speech service. +Out of the box this package listens to a speech topic, submits text to the Amazon Polly cloud service to generate an audio stream file, +retrieves the audio stream from Amazon Polly, and plays the audio stream via the default output device. +The nodes can be configured to use different voices as well as custom lexicons and SSML tags which enable you to control aspects of speech, +such as pronunciation, volume, pitch, speed rate, etc. A [sample ROS application] with this node, +and more details on speech customization are available within the [Amazon Polly documentation]. -This library is licensed under the Apache 2.0 License. +**Amazon Polly Summary**: Amazon Polly is a service that turns text into lifelike speech, allowing you to create applications that talk, +and build entirely new categories of speech-enabled products. Amazon Polly is a Text-to-Speech service that uses advanced deep learning technologies to synthesize speech that sounds like a human voice. +With dozens of lifelike voices across a variety of languages, you can select the ideal voice and build speech-enabled applications that work in many different countries. + +**Features in Active Development**: +- Offline TTS + +### License +The source code is released under an [Apache 2.0]. + +**Author**: AWS RoboMaker
+**Affiliation**: [Amazon Web Services (AWS)]
+**Maintainer**: AWS RoboMaker, ros-contributions@amazon.com + +### Supported ROS Distributions +- Kinetic +- Lunar +- Melodic + + +## Installation + +### AWS Credentials +You will need to create an AWS Account and configure the credentials to be able to communicate with AWS services. You may find [AWS Configuration and Credential Files] helpful. + +This node will require the following AWS account IAM role permissions: +- `polly:SynthesizeSpeech` + +### Build and Test + +#### Build from Source + +If you test this package on versions of Ubuntu older than 18.x (16.04 for example), please upgrade `mock` to the latest version by using `pip`. + + sudo apt-get python-pip + pip install -U mock requests + +Create a ROS workspace and a source directory + + mkdir -p ~/ros-workspace/src + +To install from source, clone the latest version from master branch and compile the package + +- Clone the package into the source directory + + cd ~/ros-workspace + git clone https://github.com/aws-robotics/tts-ros1.git + +- Install dependencies + + cd ~/ros-workspace && sudo apt-get update + rosdep install --from-paths src --ignore-src -r -y + +- Install the packages + + cd ~/ros-workspace && colcon build + +- Configure ROS library Path + + source ~/ros-workspace/install/setup.bash + +- Build and run the unit tests + + colcon test --packages-select tts && colcon test-result --all + +#### Test on Containers/Virtual Machines + +Even if your container or virtual machine does not have audio device, you can still test TTS by leveraging an audio server. + +The following is an example setup on a MacBook with PulseAudio as the audio server. +If you are new to PulseAudio, you may want to read the [PulseAudio Documentation]. + +**Step 1: Start PulseAudio on your laptop** + +After installation, start the audio server with *module-native-protocol-tcp* loaded: + + pulseaudio --load=module-native-protocol-tcp --exit-idle-time=-1 --log-target=stderr -v + +Note the extra arguments `-v` and `--log-target` are used for easier troubleshooting. + +**Step 2: Run TTS nodes in container** + +In your container, make sure you set the right environment variables. +For example, you can start the container using `docker run -it -e PULSE_SERVER=docker.for.mac.localhost ubuntu:16.04`. + +Then you will be able to run ROS nodes in the container and hear the audio from your laptop speakers. + +**Troubleshooting** + +If your laptop has multiple audio output devices, make sure the right one has the right volume. +This command will give you a list of output devices and tell you which one has been selected: + + pacmd list-sinks | grep -E '(index:|name:|product.name)' + +## Launch Files +An example launch file called `sample_application.launch` is provided. + + +## Usage + +### Run the node +- **Plain text** + - `roslaunch tts sample_application.launch` + - `rosrun tts voicer.py 'Hello World'` + +- **SSML** + - `roslaunch tts sample_application.launch` + - `rosrun tts voicer.py 'Mary has a little lamb.' '{"text_type":"ssml"}'` + + +## Configuration File and Parameters +| Parameter Name | Type | Description | +| -------------- | ---- | ----------- | +| polly_action | *string* | Currently only one action named `SynthesizeSpeech` is supported. | +| text | *string* | The text to be synthesized. It can be plain text or SSML. See also `text_type`. | +| text_type | *string* | A user can choose from `text` and `ssml`. Default: `text`. | +| voice_id | *string* | The list of supported voices can be found on [official Amazon Polly document]. Default: Joanna | +| output_format | *string* | Valid formats are `ogg_vorbis`, `mp3` and `pcm`. Default: `ogg_vorbis` | +| output_path | *string* | The audio data will be saved as a local file for playback and reuse/inspection purposes. This parameter is to provide a preferred path to save the file. Default: `.` | +| sample_rate | *string* | Note `16000` is a valid sample rate for all supported formats. Default: `16000`. | + + +## Performance and Benchmark Results +We evaluated the performance of this node by runnning the followning scenario on a Raspberry Pi 3 Model B: +- Launch a baseline graph containing the talker and listener nodes from the [roscpp_tutorials package](https://wiki.ros.org/roscpp_tutorials), plus two additional nodes that collect CPU and memory usage statistics. Allow the nodes to run for 60 seconds. +- Launch the nodes `polly_node`, `synthesizer_node` and `tts_node` by using the launch file `sample_application.launch` as described above. At the same time, perform several calls to the action `tts/action/Speech.action` using the `voicer.py` script descried above, by running the following script in the background: + +```bash +rosrun tts voicer.py 'Amazon Polly is a Text-to-Speech (TTS) cloud service' '{"text_type":"ssml"}' ; sleep 1 +rosrun tts voicer.py 'that converts text into lifelike speech' '{"text_type":"ssml"}' ; sleep 1 +rosrun tts voicer.py 'You can use Amazon Polly to develop applications that increase engagement and accessibility' '{"text_type":"ssml"}' ; sleep 1 +rosrun tts voicer.py 'Amazon Polly supports multiple languages and includes a variety of lifelike voices' '{"text_type":"ssml"}' ; sleep 1 +rosrun tts voicer.py 'so you can build speech-enabled applications that work in multiple locations' '{"text_type":"ssml"}' ; sleep 1 +rosrun tts voicer.py 'and use the ideal voice for your customers' '{"text_type":"ssml"}' ; sleep 1 +``` + +- Allow the nodes to run for 180 seconds. +- Terminate the `polly_node`, `synthesizer_node` and `tts_node` nodes, and allow the reamaining nodes to run for 60 seconds. + +The following graph shows the CPU usage during that scenario. The 1 minute average CPU usage starts at 16.75% during the launch of the baseline graph, and stabilizes at 6%. When we launch the Polly nodes around second 85, the 1 minute average CPU increases up to a peak of 22.25% and stabilizes around 20%. After we stop making requests with the script `voicer.py` around second 206 the 1 minute average CPU usage moves to around 12%, and decreases gradually, and goes down again to 2.5 % after we stop the Polly nodes at the end of the scenario. + +![cpu](wiki/images/cpu.svg) + +The following graph shows the memory usage during that scenario. We start with a memory usage of around 227 MB that increases to around 335 MB (+47.58%) when we lanch the Polly nodes around second 85, and gets to a peak of 361 MB (+59% wrt. initial value) while we are calling the script `voicer.py`. The memory usage goes back to the initial values after stopping the Polly nodes. + +![memory](wiki/images/memory.svg) + + +## Nodes + +### polly +Polly node is the engine for the synthesizing job. It provides user-friendly yet powerful APIs so a user doesn't have to deal with technical details of AWS service calls. + +#### Services +- **`polly (tts/Polly)`** + + Call the service to use Amazon Polly to synthesize the audio. + +#### Reserved for future usage +- `language_code (string, default: None)` + + A user doesn't have to provide a language code and this is reserved for future usage. + +- `lexicon_content (string, default: None)` + +- `lexicon_name (string, default: None)` + +- `lexicon_names (string[], default: empty)` + +- `speech_mark_types (string[], default: empty)` + +- `max_results (uint32, default: None)` + +- `next_token (string, default: None)` + +- `sns_topic_arn (string, default: None)` + +- `task_id (string, default: None)` + +- `task_status (string, default: iNone)` + +- `output_s3_bucket_name (string, default: None)` + +- `output_s3_key_prefix (string, default: None)` + +- `include_additional_language_codes (bool, default: None)` + +### synthesizer node + +#### Services +- **`synthesizer (tts/Synthesizer)`** + + Call the service to synthesize. + +#### Parameters + +- **`text (string)`** + + The text to be synthesized. + +- **`metadata (string, JSON format)`** + + Optional, for user to have control over how synthesis happens. + +### tts node + +#### Action + +- **`speech`** + +#### Parameters + +- **`text (string)`** + + The text to be synthesized. + +- **`metadata (string, JSON format)`** + + Optional, for user to have control over how synthesis happens. + + +## Bugs & Feature Requests +Please contact the team directly if you would like to request a feature. + +Please report bugs in [Issue Tracker]. + + +[AWS Configuration and Credential Files]: https://docs.aws.amazon.com/cli/latest/userguide/cli-config-files.html +[Amazon Polly documentation]: https://docs.aws.amazon.com/polly/latest/dg/what-is.html +[Amazon Web Services (AWS)]: https://aws.amazon.com/ +[Apache 2.0]: https://aws.amazon.com/apache-2-0/ +[Issue Tracker]: https://github.com/aws-robotics/tts-ros1/issues +[PulseAudio Documentation]: https://www.freedesktop.org/wiki/Software/PulseAudio/Documentation/ +[official Amazon Polly document]: https://docs.aws.amazon.com/polly/latest/dg/voicelist.html +[sample ROS application]: https://github.com/aws-robotics/aws-robomaker-sample-application-voiceinteraction diff --git a/tts/CMakeLists.txt b/tts/CMakeLists.txt new file mode 100644 index 0000000..e5a05e9 --- /dev/null +++ b/tts/CMakeLists.txt @@ -0,0 +1,71 @@ +cmake_minimum_required(VERSION 2.8.3) +project(tts) + +find_package(catkin REQUIRED COMPONENTS actionlib_msgs message_generation rospy rosunit rostest std_msgs sound_play) + +catkin_python_setup() + +################################################ +## Declare ROS messages, services and actions ## +################################################ + +## Generate services in the 'srv' folder +add_service_files(FILES Synthesizer.srv Polly.srv) + +## Generate actions in the 'action' folder +add_action_files(FILES Speech.action) + +## Generate added messages and services with any dependencies listed here +generate_messages(DEPENDENCIES actionlib_msgs std_msgs) + +################################### +## catkin specific configuration ## +################################### +## The catkin_package macro generates cmake config files for your package +## Declare things to be passed to dependent projects +## LIBRARIES: libraries you create in this project that dependent projects also need +## CATKIN_DEPENDS: catkin_packages dependent projects also need +## DEPENDS: system dependencies of this project that dependent projects also need +catkin_package( + LIBRARIES tts + CATKIN_DEPENDS actionlib_msgs message_runtime rospy std_msgs +) + +############# +## Install ## +############# + +# all install targets should use catkin DESTINATION variables +# See http://ros.org/doc/api/catkin/html/adv_user_guide/variables.html + +## Mark executable scripts (Python etc.) for installation +## in contrast to setup.py, you can choose the destination +install(PROGRAMS + scripts/polly_node.py + scripts/synthesizer_node.py + scripts/tts_node.py + scripts/voicer.py + DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} +) + +install(DIRECTORY + config + launch + DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION} +) + +############# +## Testing ## +############# +if(CATKIN_ENABLE_TESTING) + ## Add folders to be run by python nosetests + catkin_add_nosetests(test/test_unit_synthesizer.py) + catkin_add_nosetests(test/test_unit_polly.py) + + if(BUILD_AWS_TESTING) + find_package(rostest REQUIRED COMPONENTS tts) + add_rostest(test/integration_tests.test DEPENDENCIES ${tts_EXPORTED_TARGETS}) + endif() +endif() + + diff --git a/LICENSE b/tts/LICENSE.txt similarity index 99% rename from LICENSE rename to tts/LICENSE.txt index d645695..d8a44c5 100644 --- a/LICENSE +++ b/tts/LICENSE.txt @@ -187,7 +187,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright [yyyy] [name of copyright owner] + Copyright 2018 Amazon.com, Inc. or its affiliates Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/tts/NOTICE.txt b/tts/NOTICE.txt new file mode 100644 index 0000000..13033fe --- /dev/null +++ b/tts/NOTICE.txt @@ -0,0 +1,4 @@ +Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + +This product includes software developed by +Amazon Technologies, Inc (http://www.amazon.com/). diff --git a/tts/action/Speech.action b/tts/action/Speech.action new file mode 100644 index 0000000..2da3ffe --- /dev/null +++ b/tts/action/Speech.action @@ -0,0 +1,9 @@ +#goal definition +string text +string metadata +--- +#result definition +string response +--- +#feedback +string data diff --git a/tts/config/sample_configuration.yaml b/tts/config/sample_configuration.yaml new file mode 100644 index 0000000..4c74e77 --- /dev/null +++ b/tts/config/sample_configuration.yaml @@ -0,0 +1,6 @@ +# This is the AWS Client Configuration used by the AWS service client in the Node. If given the node will load the +# provided configuration when initializing the client. +aws_client_configuration: + # Specifies where you want the client to communicate. Examples include us-east-1 or us-west-1. You must ensure that + # the service you want to use has an endpoint in the region you configure. + region: "us-west-2" diff --git a/tts/launch/sample_application.launch b/tts/launch/sample_application.launch new file mode 100644 index 0000000..42137f3 --- /dev/null +++ b/tts/launch/sample_application.launch @@ -0,0 +1,13 @@ + + + + + + + + + + + + diff --git a/tts/launch/tts_polly.launch b/tts/launch/tts_polly.launch new file mode 100644 index 0000000..0e6fcec --- /dev/null +++ b/tts/launch/tts_polly.launch @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tts/package.xml b/tts/package.xml new file mode 100644 index 0000000..1e3d80f --- /dev/null +++ b/tts/package.xml @@ -0,0 +1,38 @@ + + + tts + 1.0.0 + Package enabling a robot to speak with a human voice by providing a Text-To-Speech ROS service + http://wiki.ros.org/tts + + AWS RoboMaker + AWS RoboMaker + + Apache 2.0 + + catkin + + actionlib_msgs + message_generation + rospy + std_msgs + python-boto3 + sound_play + rosunit + rostest + + actionlib_msgs + rospy + std_msgs + sound_play + + actionlib_msgs + rospy + std_msgs + message_runtime + python-boto3 + sound_play + + rosunit + rostest + diff --git a/tts/scripts/polly_node.py b/tts/scripts/polly_node.py new file mode 100755 index 0000000..d07dfd3 --- /dev/null +++ b/tts/scripts/polly_node.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python + +# Copyright (c) 2018, Amazon.com, Inc. or its affiliates. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"). +# You may not use this file except in compliance with the License. +# A copy of the License is located at +# +# http://aws.amazon.com/apache2.0 +# +# or in the "license" file accompanying this file. This file is distributed +# on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +# express or implied. See the License for the specific language governing +# permissions and limitations under the License. + + +if __name__ == '__main__': + import tts.amazonpolly + tts.amazonpolly.main() diff --git a/tts/scripts/synthesizer_node.py b/tts/scripts/synthesizer_node.py new file mode 100755 index 0000000..937870b --- /dev/null +++ b/tts/scripts/synthesizer_node.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python + +# Copyright (c) 2018, Amazon.com, Inc. or its affiliates. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"). +# You may not use this file except in compliance with the License. +# A copy of the License is located at +# +# http://aws.amazon.com/apache2.0 +# +# or in the "license" file accompanying this file. This file is distributed +# on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +# express or implied. See the License for the specific language governing +# permissions and limitations under the License. + + +if __name__ == "__main__": + import tts.synthesizer + tts.synthesizer.main() diff --git a/tts/scripts/tts_node.py b/tts/scripts/tts_node.py new file mode 100755 index 0000000..b8bdd6a --- /dev/null +++ b/tts/scripts/tts_node.py @@ -0,0 +1,120 @@ +#!/usr/bin/env python + +# Copyright (c) 2018, Amazon.com, Inc. or its affiliates. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"). +# You may not use this file except in compliance with the License. +# A copy of the License is located at +# +# http://aws.amazon.com/apache2.0 +# +# or in the "license" file accompanying this file. This file is distributed +# on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +# express or implied. See the License for the specific language governing +# permissions and limitations under the License. + +"""A very simple Action Server that does TTS. + +It is a combination of a synthesizer and a player. Being an action server, it can be used in two different manners. + +1. Play and wait for it to finish +--------------------------------- + +A user can choose to be blocked until the audio playing is done. This is especially useful in interactive scenarios. + +Example:: + + rospy.init_node('tts_action_client') + client = actionlib.SimpleActionClient('tts', SpeechAction) + client.wait_for_server() + goal = SpeechGoal() + goal.text = 'Let me ask you a question, please give me your answer.' + client.send_goal(goal) + client.wait_for_result() + + # start listening to a response or waiting for some input to continue the interaction + +2. Play and forget +------------------ + +A user can also choose not to wait:: + + rospy.init_node('tts_action_client') + client = actionlib.SimpleActionClient('tts', SpeechAction) + client.wait_for_server() + goal = SpeechGoal() + goal.text = 'Let me talk, you can to something else in the meanwhile.' + client.send_goal(goal) + +This is useful when the robot wants to do stuff while the audio is being played. For example, a robot may start to +read some instructions and immediately get ready for any input. +""" + +import json + +import actionlib +import rospy +from tts.msg import SpeechAction, SpeechResult +from tts.srv import Synthesizer + +from sound_play.libsoundplay import SoundClient + + +def play(filename): + """plays the wav or ogg file using sound_play""" + SoundClient(blocking=True).playWave(filename) + + +def do_synthesize(goal): + """calls synthesizer service to do the job""" + rospy.wait_for_service('synthesizer') + synthesize = rospy.ServiceProxy('synthesizer', Synthesizer) + return synthesize(goal.text, goal.metadata) + + +def finish_with_result(s): + """responds the client""" + tts_server_result = SpeechResult(s) + server.set_succeeded(tts_server_result) + rospy.loginfo(tts_server_result) + + +def do_speak(goal): + """The action handler. + + Note that although it responds to client after the audio play is finished, a client can choose + not to wait by not calling ``SimpleActionClient.waite_for_result()``. + """ + rospy.loginfo('speech goal: {}'.format(goal)) + + res = do_synthesize(goal) + rospy.loginfo('synthesizer returns: {}'.format(res)) + + try: + r = json.loads(res.result) + except Exception as e: + s = 'Expecting JSON from synthesizer but got {}'.format(res.result) + rospy.logerr('{}. Exception: {}'.format(s, e)) + finish_with_result(s) + return + + result = '' + + if 'Audio File' in r: + audio_file = r['Audio File'] + rospy.loginfo('Will play {}'.format(audio_file)) + play(audio_file) + result = audio_file + + if 'Exception' in r: + result = '[ERROR] {}'.format(r) + rospy.logerr(result) + + finish_with_result(result) + + +if __name__ == '__main__': + rospy.init_node('tts_node') + server = actionlib.SimpleActionServer('tts', SpeechAction, do_speak, False) + server.start() + rospy.spin() diff --git a/tts/scripts/voicer.py b/tts/scripts/voicer.py new file mode 100755 index 0000000..9bbd551 --- /dev/null +++ b/tts/scripts/voicer.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python + +# Copyright (c) 2018, Amazon.com, Inc. or its affiliates. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"). +# You may not use this file except in compliance with the License. +# A copy of the License is located at +# +# http://aws.amazon.com/apache2.0 +# +# or in the "license" file accompanying this file. This file is distributed +# on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +# express or implied. See the License for the specific language governing +# permissions and limitations under the License. + +"""Usage: + +(assuming TTS action server has been started via `roslaunch tts tts_polly.launch`) + +Plain text:: + + $ rosrun tts voicer.py 'Hello World' + +SSML:: + + $ rosrun tts voicer.py \ + 'Mary has a little lamb.' \ + '{"text_type":"ssml"}' +""" + + +import sys +import actionlib +import rospy +from tts.msg import SpeechAction, SpeechGoal + + +if __name__ == '__main__': + rospy.init_node('tts_action_client') + client = actionlib.SimpleActionClient('tts', SpeechAction) + client.wait_for_server() + + goal = SpeechGoal() + + goal.text = sys.argv[1] if len(sys.argv) > 1 else 'I got no idea.' + goal.metadata = sys.argv[2] if len(sys.argv) > 2 else '' + + client.send_goal(goal) + client.wait_for_result() + print('\n' + client.get_result().response) diff --git a/tts/setup.py b/tts/setup.py new file mode 100644 index 0000000..66098bd --- /dev/null +++ b/tts/setup.py @@ -0,0 +1,33 @@ +# Copyright (c) 2018, Amazon.com, Inc. or its affiliates. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"). +# You may not use this file except in compliance with the License. +# A copy of the License is located at +# +# http://aws.amazon.com/apache2.0 +# +# or in the "license" file accompanying this file. This file is distributed +# on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +# express or implied. See the License for the specific language governing +# permissions and limitations under the License. + +import os +from distutils.core import setup +from catkin_pkg.python_setup import generate_distutils_setup + + +# ROS PACKAGING +# using distutils : https://docs.python.org/2/distutils +# fetch values from package.xml +setup_args = generate_distutils_setup( + packages=[ + 'tts', + ], + package_dir={ + '': 'src', + }, + package_data={ + '': ['data/*.ogg', 'data/models/polly/2016-06-10/*.json'] + }, +) +setup(**setup_args) diff --git a/tts/src/tts/__init__.py b/tts/src/tts/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tts/src/tts/amazonpolly.py b/tts/src/tts/amazonpolly.py new file mode 100755 index 0000000..d6da9f4 --- /dev/null +++ b/tts/src/tts/amazonpolly.py @@ -0,0 +1,428 @@ +#!/usr/bin/env python + +# Copyright (c) 2018, Amazon.com, Inc. or its affiliates. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"). +# You may not use this file except in compliance with the License. +# A copy of the License is located at +# +# http://aws.amazon.com/apache2.0 +# +# or in the "license" file accompanying this file. This file is distributed +# on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +# express or implied. See the License for the specific language governing +# permissions and limitations under the License. + +import json +import os +import sys +import wave +import traceback +import requests +from boto3 import Session +from botocore.credentials import CredentialProvider, RefreshableCredentials +from botocore.session import get_session +from botocore.exceptions import UnknownServiceError +from contextlib import closing +from optparse import OptionParser + +import rospy +from tts.srv import Polly, PollyRequest, PollyResponse + + +def get_ros_param(param, default=None): + try: + key = rospy.search_param(param) + return default if key is None else rospy.get_param(key, default) + except Exception as e: + rospy.logwarn('Failed to get ros param {}, will use default {}. Exception: '.format(param, default, e)) + return default + + +class AwsIotCredentialProvider(CredentialProvider): + METHOD = 'aws-iot' + CANONICAL_NAME = 'customIoTwithCertificate' + + DEFAULT_AUTH_CONNECT_TIMEOUT_MS = 5000 + DEFAULT_AUTH_TOTAL_TIMEOUT_MS = 10000 + + def __init__(self): + super(AwsIotCredentialProvider, self).__init__() + self.ros_param_prefix = 'iot/' + + def get_param(self, param, default=None): + return get_ros_param(self.ros_param_prefix + param, default) + + def retrieve_credentials(self): + try: + cert_file = self.get_param('certfile') + key_file = self.get_param('keyfile') + endpoint = self.get_param('endpoint') + role_alias = self.get_param('role') + connect_timeout = self.get_param('connect_timeout_ms', self.DEFAULT_AUTH_CONNECT_TIMEOUT_MS) + total_timeout = self.get_param('total_timeout_ms', self.DEFAULT_AUTH_TOTAL_TIMEOUT_MS) + thing_name = self.get_param('thing_name', '') + + if any(v is None for v in (cert_file, key_file, endpoint, role_alias, thing_name)): + return None + + headers = {'x-amzn-iot-thingname': thing_name} if len(thing_name) > 0 else None + url = 'https://{}/role-aliases/{}/credentials'.format(endpoint, role_alias) + timeout = (connect_timeout, total_timeout - connect_timeout) # see also: urllib3/util/timeout.py + + response = requests.get(url, cert=(cert_file, key_file), headers=headers, timeout=timeout) + d = response.json()['credentials'] + + rospy.loginfo('Credentials expiry time: {}'.format(d['expiration'])) + + return { + 'access_key': d['accessKeyId'], + 'secret_key': d['secretAccessKey'], + 'token': d['sessionToken'], + 'expiry_time': d['expiration'], + } + except Exception as e: + rospy.logwarn('Failed to fetch credentials from AWS IoT: {}'.format(e)) + return None + + def load(self): + return RefreshableCredentials.create_from_metadata( + self.retrieve_credentials(), + self.retrieve_credentials, + 'aws-iot-with-certificate' + ) + + +class AmazonPolly: + """A TTS engine that can be used in two different ways. + + Usage + ----- + + 1. It can run as a ROS service node. + + Start a polly node:: + + $ rosrun tts polly_node.py + + Call the service from command line:: + + $ rosservice call /polly SynthesizeSpeech 'hello polly' '' '' '' '' '' '' '' '' [] [] 0 '' '' '' '' '' '' false + + Call the service programmatically:: + + from tts.srv import Polly + rospy.wait_for_service('polly') + polly = rospy.ServiceProxy('polly', Polly) + res = polly(**kw) + + 2. It can also be used as a normal python class:: + + AmazonPolly().synthesize(text='hi polly') + + PollyRequest supports many parameters, but the majority of the users can safely ignore most of them and just + use the vanilla version which involves only one argument, ``text``. + + If in some use cases more control is needed, SSML will come handy. Example:: + + AmazonPolly().synthesize( + text='Mary has a little lamb.', + text_type='ssml' + ) + + A user can also control the voice, output format and so on. Example:: + + AmazonPolly().synthesize( + text='Mary has a little lamb.', + text_type='ssml', + voice_id='Joey', + output_format='mp3', + output_path='/tmp/blah' + ) + + + Parameters + ---------- + + Among the parameters defined in Polly.srv, the following are supported while others are reserved for future. + + * polly_action : currently only ``SynthesizeSpeech`` is supported + * text : the text to speak + * text_type : can be either ``text`` (default) or ``ssml`` + * voice_id : any voice id supported by Amazon Polly, default is Joanna + * output_format : ogg (default), mp3 or pcm + * output_path : where the audio file is saved + * sample_rate : default is 16000 for pcm or 22050 for mp3 and ogg + + The following are the reserved ones. Note that ``language_code`` is rarely needed (this may seem counter-intuitive). + See official Amazon Polly documentation for details (link can be found below). + + * language_code + * lexicon_content + * lexicon_name + * lexicon_names + * speech_mark_types + * max_results + * next_token + * sns_topic_arn + * task_id + * task_status + * output_s3_bucket_name + * output_s3_key_prefix + * include_additional_language_codes + + + Links + ----- + + Amazon Polly documentation: https://docs.aws.amazon.com/polly/latest/dg/API_SynthesizeSpeech.html + + """ + + def __init__(self, aws_access_key_id=None, aws_secret_access_key=None, aws_session_token=None, region_name=None): + if region_name is None: + region_name = get_ros_param('aws_client_configuration/region', default='us-west-2') + + self.polly = self._get_polly_client(aws_access_key_id, aws_secret_access_key, aws_session_token, region_name) + self.default_text_type = 'text' + self.default_voice_id = 'Joanna' + self.default_output_format = 'ogg_vorbis' + self.default_output_folder = '.' + self.default_output_file_basename = 'output' + + def _get_polly_client(self, aws_access_key_id=None, aws_secret_access_key=None, aws_session_token=None, + region_name=None, with_service_model_patch=False): + """Note we get a new botocore session each time this function is called. + This is to avoid potential problems caused by inner state of the session. + """ + botocore_session = get_session() + + if with_service_model_patch: + # Older versions of botocore don't have polly. We can possibly fix it by appending + # extra path with polly service model files to the search path. + current_dir = os.path.dirname(os.path.abspath(__file__)) + service_model_path = os.path.join(current_dir, 'data', 'models') + botocore_session.set_config_variable('data_path', service_model_path) + rospy.loginfo('patching service model data path: {}'.format(service_model_path)) + + botocore_session.get_component('credential_provider').insert_after('boto-config', AwsIotCredentialProvider()) + + botocore_session.user_agent_extra = self._generate_user_agent_suffix() + + session = Session(aws_access_key_id=aws_access_key_id, aws_secret_access_key=aws_secret_access_key, + aws_session_token=aws_session_token, region_name=region_name, + botocore_session=botocore_session) + + try: + return session.client("polly") + except UnknownServiceError: + # the first time we reach here, we try to fix the problem + if not with_service_model_patch: + return self._get_polly_client(aws_access_key_id, aws_secret_access_key, aws_session_token, region_name, + with_service_model_patch=True) + else: + # we have tried our best, time to panic + rospy.logerr('Amazon Polly is not available. Please install the latest boto3.') + raise + + def _generate_user_agent_suffix(self): + exec_env = get_ros_param('exec_env', 'AWS_RoboMaker').strip() + if 'AWS_RoboMaker' in exec_env: + ver = get_ros_param('robomaker_version', None) + if ver: + exec_env += '-' + ver.strip() + ros_distro = get_ros_param('rosdistro', 'Unknown_ROS_DISTRO').strip() + ros_version = get_ros_param('rosversion', 'Unknown_ROS_VERSION').strip() + return 'exec-env/{} ros-{}/{}'.format(exec_env, ros_distro, ros_version) + + def _pcm2wav(self, audio_data, wav_filename, sample_rate): + """per Amazon Polly official doc, the pcm in a signed 16-bit, 1 channel (mono), little-endian format.""" + wavf = wave.open(wav_filename, 'w') + wavf.setframerate(int(sample_rate)) + wavf.setnchannels(1) # 1 channel + wavf.setsampwidth(2) # 2 bytes == 16 bits + wavf.writeframes(audio_data) + wavf.close() + + def _make_audio_file_fullpath(self, output_path, output_format): + """Makes a full path for audio file based on given output path and format. + + If ``output_path`` doesn't have a path, current path is used. + + :param output_path: the output path received + :param output_format: the audio format, e.g., mp3, ogg_vorbis, pcm + :return: a full path for the output audio file. File ext will be constructed from audio format. + """ + head, tail = os.path.split(output_path) + if not head: + head = self.default_output_folder + if not tail: + tail = self.default_output_file_basename + + file_ext = {'pcm': '.wav', 'mp3': '.mp3', 'ogg_vorbis': '.ogg'}[output_format.lower()] + if not tail.endswith(file_ext): + tail += file_ext + + return os.path.realpath(os.path.join(head, tail)) + + def _synthesize_speech_and_save(self, request): + """Calls Amazon Polly and writes the returned audio data to a local file. + + To make it practical, three things will be returned in a JSON form string, which are audio file path, + audio type and Amazon Polly response metadata. + + If the Amazon Polly call fails, audio file name will be an empty string and audio type will be "N/A". + + Please see https://boto3.readthedocs.io/reference/services/polly.html#Polly.Client.synthesize_speech + for more details on Amazon Polly API. + + :param request: an instance of PollyRequest + :return: a string in JSON form with two attributes, "Audio File" and "Amazon Polly Response". + """ + kws = { + 'LexiconNames': request.lexicon_names if request.lexicon_names else [], + 'OutputFormat': request.output_format if request.output_format else self.default_output_format, + 'SampleRate': request.sample_rate, + 'SpeechMarkTypes': request.speech_mark_types if request.speech_mark_types else [], + 'Text': request.text, + 'TextType': request.text_type if request.text_type else self.default_text_type, + 'VoiceId': request.voice_id if request.voice_id else self.default_voice_id + } + + if not kws['SampleRate']: + kws['SampleRate'] = '16000' if kws['OutputFormat'].lower() == 'pcm' else '22050' + + rospy.loginfo('Amazon Polly Request: {}'.format(kws)) + response = self.polly.synthesize_speech(**kws) + rospy.loginfo('Amazon Polly Response: {}'.format(response)) + + if "AudioStream" in response: + audiofile = self._make_audio_file_fullpath(request.output_path, kws['OutputFormat']) + rospy.loginfo('will save audio as {}'.format(audiofile)) + + with closing(response["AudioStream"]) as stream: + if kws['OutputFormat'].lower() == 'pcm': + self._pcm2wav(stream.read(), audiofile, kws['SampleRate']) + else: + with open(audiofile, "wb") as f: + f.write(stream.read()) + + audiotype = response['ContentType'] + else: + audiofile = '' + audiotype = 'N/A' + + return json.dumps({ + 'Audio File': audiofile, + 'Audio Type': audiotype, + 'Amazon Polly Response Metadata': str(response['ResponseMetadata']) + }) + + def _dispatch(self, request): + """Amazon Polly supports a number of APIs. This will call the right one based on the content of request. + + Currently "SynthesizeSpeech" is the only recognized action. Basically this method just delegates the work + to ``self._synthesize_speech_and_save`` and returns the result as is. It will simply raise if a different + action is passed in. + + :param request: an instance of PollyRequest + :return: whatever returned by the delegate + """ + actions = { + 'SynthesizeSpeech': self._synthesize_speech_and_save + # ... more actions could go in here ... + } + + if request.polly_action not in actions: + raise RuntimeError('bad or unsupported Amazon Polly action: "' + request.polly_action + '".') + + return actions[request.polly_action](request) + + def _node_request_handler(self, request): + """The callback function for processing service request. + + It never raises. If anything unexpected happens, it will return a PollyResponse with details of the exception. + + :param request: an instance of PollyRequest + :return: a PollyResponse + """ + rospy.loginfo('Amazon Polly Request: {}'.format(request)) + + try: + response = self._dispatch(request) + rospy.loginfo('will return {}'.format(response)) + return PollyResponse(result=response) + except Exception as e: + current_dir = os.path.dirname(os.path.abspath(__file__)) + exc_type = sys.exc_info()[0] + + # not using `issubclass(exc_type, ConnectionError)` for the condition below because some versions + # of urllib3 raises exception when doing `from requests.exceptions import ConnectionError` + error_ogg_filename = 'connerror.ogg' if 'ConnectionError' in exc_type.__name__ else 'error.ogg' + + error_details = { + 'Audio File': os.path.join(current_dir, 'data', error_ogg_filename), + 'Audio Type': 'ogg', + 'Exception': { + 'Type': str(exc_type), + 'Module': exc_type.__module__, + 'Name': exc_type.__name__, + 'Value': str(e), + }, + 'Traceback': traceback.format_exc() + } + + error_str = json.dumps(error_details) + rospy.logerr(error_str) + return PollyResponse(result=error_str) + + def synthesize(self, **kws): + """Call this method if you want to use polly but don't want to start a node. + + :param kws: input as defined in Polly.srv + :return: a string in JSON form with detailed information, success or failure + """ + req = PollyRequest(polly_action='SynthesizeSpeech', **kws) + return self._node_request_handler(req) + + def start(self, node_name='polly_node', service_name='polly'): + """The entry point of a ROS service node. + + Details of the service API can be found in Polly.srv. + + :param node_name: name of ROS node + :param service_name: name of ROS service + :return: it doesn't return + """ + rospy.init_node(node_name) + + service = rospy.Service(service_name, Polly, self._node_request_handler) + + rospy.loginfo('polly running: {}'.format(service.uri)) + + rospy.spin() + + +def main(): + usage = '''usage: %prog [options] + ''' + + parser = OptionParser(usage) + + parser.add_option("-n", "--node-name", dest="node_name", default='polly_node', + help="name of the ROS node", + metavar="NODE_NAME") + parser.add_option("-s", "--service-name", dest="service_name", default='polly', + help="name of the ROS service", + metavar="SERVICE_NAME") + + (options, args) = parser.parse_args() + + node_name = options.node_name + service_name = options.service_name + + AmazonPolly().start(node_name=node_name, service_name=service_name) + + +if __name__ == "__main__": + main() diff --git a/tts/src/tts/data/connerror.ogg b/tts/src/tts/data/connerror.ogg new file mode 100644 index 0000000000000000000000000000000000000000..7414355a75bebdefde40e6086306f2f15c412235 GIT binary patch literal 23124 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 XcLKhn&+pJ>&_7HP^DVIO&sF#zwH5!F literal 0 HcmV?d00001 diff --git a/tts/src/tts/data/error.ogg b/tts/src/tts/data/error.ogg new file mode 100644 index 0000000000000000000000000000000000000000..4cf247d7165f4d169df6914a74041aec7cb1b1f4 GIT binary patch literal 27767 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 nLr!roLT}l;*ucaDIi;hXuqPSMvu;r;-b; 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 z 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 literal 0 HcmV?d00001 diff --git a/tts/src/tts/data/models/polly/2016-06-10/examples-1.json b/tts/src/tts/data/models/polly/2016-06-10/examples-1.json new file mode 100644 index 0000000..38205db --- /dev/null +++ b/tts/src/tts/data/models/polly/2016-06-10/examples-1.json @@ -0,0 +1,171 @@ +{ + "version": "1.0", + "examples": { + "DeleteLexicon": [ + { + "input": { + "Name": "example" + }, + "output": { + }, + "comments": { + "input": { + }, + "output": { + } + }, + "description": "Deletes a specified pronunciation lexicon stored in an AWS Region.", + "id": "to-delete-a-lexicon-1481922498332", + "title": "To delete a lexicon" + } + ], + "DescribeVoices": [ + { + "input": { + "LanguageCode": "en-GB" + }, + "output": { + "Voices": [ + { + "Gender": "Female", + "Id": "Emma", + "LanguageCode": "en-GB", + "LanguageName": "British English", + "Name": "Emma" + }, + { + "Gender": "Male", + "Id": "Brian", + "LanguageCode": "en-GB", + "LanguageName": "British English", + "Name": "Brian" + }, + { + "Gender": "Female", + "Id": "Amy", + "LanguageCode": "en-GB", + "LanguageName": "British English", + "Name": "Amy" + } + ] + }, + "comments": { + "input": { + }, + "output": { + } + }, + "description": "Returns the list of voices that are available for use when requesting speech synthesis. Displayed languages are those within the specified language code. If no language code is specified, voices for all available languages are displayed.", + "id": "to-describe-available-voices-1482180557753", + "title": "To describe available voices" + } + ], + "GetLexicon": [ + { + "input": { + "Name": "" + }, + "output": { + "Lexicon": { + "Content": "\r\n\r\n \r\n W3C\r\n World Wide Web Consortium\r\n \r\n", + "Name": "example" + }, + "LexiconAttributes": { + "Alphabet": "ipa", + "LanguageCode": "en-US", + "LastModified": 1478542980.117, + "LexemesCount": 1, + "LexiconArn": "arn:aws:polly:us-east-1:123456789012:lexicon/example", + "Size": 503 + } + }, + "comments": { + "input": { + }, + "output": { + } + }, + "description": "Returns the content of the specified pronunciation lexicon stored in an AWS Region.", + "id": "to-retrieve-a-lexicon-1481912870836", + "title": "To retrieve a lexicon" + } + ], + "ListLexicons": [ + { + "input": { + }, + "output": { + "Lexicons": [ + { + "Attributes": { + "Alphabet": "ipa", + "LanguageCode": "en-US", + "LastModified": 1478542980.117, + "LexemesCount": 1, + "LexiconArn": "arn:aws:polly:us-east-1:123456789012:lexicon/example", + "Size": 503 + }, + "Name": "example" + } + ] + }, + "comments": { + "input": { + }, + "output": { + } + }, + "description": "Returns a list of pronunciation lexicons stored in an AWS Region.", + "id": "to-list-all-lexicons-in-a-region-1481842106487", + "title": "To list all lexicons in a region" + } + ], + "PutLexicon": [ + { + "input": { + "Content": "file://example.pls", + "Name": "W3C" + }, + "output": { + }, + "comments": { + "input": { + }, + "output": { + } + }, + "description": "Stores a pronunciation lexicon in an AWS Region.", + "id": "to-save-a-lexicon-1482272584088", + "title": "To save a lexicon" + } + ], + "SynthesizeSpeech": [ + { + "input": { + "LexiconNames": [ + "example" + ], + "OutputFormat": "mp3", + "SampleRate": "8000", + "Text": "All Gaul is divided into three parts", + "TextType": "text", + "VoiceId": "Joanna" + }, + "output": { + "AudioStream": "TEXT", + "ContentType": "audio/mpeg", + "RequestCharacters": 37 + }, + "comments": { + "input": { + }, + "output": { + } + }, + "description": "Synthesizes plain text or SSML into a file of human-like speech.", + "id": "to-synthesize-speech-1482186064046", + "title": "To synthesize speech" + } + ] + } +} diff --git a/tts/src/tts/data/models/polly/2016-06-10/paginators-1.json b/tts/src/tts/data/models/polly/2016-06-10/paginators-1.json new file mode 100644 index 0000000..c24ff03 --- /dev/null +++ b/tts/src/tts/data/models/polly/2016-06-10/paginators-1.json @@ -0,0 +1,9 @@ +{ + "pagination": { + "DescribeVoices": { + "input_token": "NextToken", + "output_token": "NextToken", + "result_key": "Voices" + } + } +} diff --git a/tts/src/tts/data/models/polly/2016-06-10/service-2.json b/tts/src/tts/data/models/polly/2016-06-10/service-2.json new file mode 100644 index 0000000..bfd6491 --- /dev/null +++ b/tts/src/tts/data/models/polly/2016-06-10/service-2.json @@ -0,0 +1,1022 @@ +{ + "version":"2.0", + "metadata":{ + "apiVersion":"2016-06-10", + "endpointPrefix":"polly", + "protocol":"rest-json", + "serviceFullName":"Amazon Polly", + "serviceId":"Polly", + "signatureVersion":"v4", + "uid":"polly-2016-06-10" + }, + "operations":{ + "DeleteLexicon":{ + "name":"DeleteLexicon", + "http":{ + "method":"DELETE", + "requestUri":"/v1/lexicons/{LexiconName}", + "responseCode":200 + }, + "input":{"shape":"DeleteLexiconInput"}, + "output":{"shape":"DeleteLexiconOutput"}, + "errors":[ + {"shape":"LexiconNotFoundException"}, + {"shape":"ServiceFailureException"} + ], + "documentation":"

Deletes the specified pronunciation lexicon stored in an AWS Region. A lexicon which has been deleted is not available for speech synthesis, nor is it possible to retrieve it using either the GetLexicon or ListLexicon APIs.

For more information, see Managing Lexicons.

" + }, + "DescribeVoices":{ + "name":"DescribeVoices", + "http":{ + "method":"GET", + "requestUri":"/v1/voices", + "responseCode":200 + }, + "input":{"shape":"DescribeVoicesInput"}, + "output":{"shape":"DescribeVoicesOutput"}, + "errors":[ + {"shape":"InvalidNextTokenException"}, + {"shape":"ServiceFailureException"} + ], + "documentation":"

Returns the list of voices that are available for use when requesting speech synthesis. Each voice speaks a specified language, is either male or female, and is identified by an ID, which is the ASCII version of the voice name.

When synthesizing speech ( SynthesizeSpeech ), you provide the voice ID for the voice you want from the list of voices returned by DescribeVoices.

For example, you want your news reader application to read news in a specific language, but giving a user the option to choose the voice. Using the DescribeVoices operation you can provide the user with a list of available voices to select from.

You can optionally specify a language code to filter the available voices. For example, if you specify en-US, the operation returns a list of all available US English voices.

This operation requires permissions to perform the polly:DescribeVoices action.

" + }, + "GetLexicon":{ + "name":"GetLexicon", + "http":{ + "method":"GET", + "requestUri":"/v1/lexicons/{LexiconName}", + "responseCode":200 + }, + "input":{"shape":"GetLexiconInput"}, + "output":{"shape":"GetLexiconOutput"}, + "errors":[ + {"shape":"LexiconNotFoundException"}, + {"shape":"ServiceFailureException"} + ], + "documentation":"

Returns the content of the specified pronunciation lexicon stored in an AWS Region. For more information, see Managing Lexicons.

" + }, + "GetSpeechSynthesisTask":{ + "name":"GetSpeechSynthesisTask", + "http":{ + "method":"GET", + "requestUri":"/v1/synthesisTasks/{TaskId}", + "responseCode":200 + }, + "input":{"shape":"GetSpeechSynthesisTaskInput"}, + "output":{"shape":"GetSpeechSynthesisTaskOutput"}, + "errors":[ + {"shape":"InvalidTaskIdException"}, + {"shape":"ServiceFailureException"}, + {"shape":"SynthesisTaskNotFoundException"} + ], + "documentation":"

Retrieves a specific SpeechSynthesisTask object based on its TaskID. This object contains information about the given speech synthesis task, including the status of the task, and a link to the S3 bucket containing the output of the task.

" + }, + "ListLexicons":{ + "name":"ListLexicons", + "http":{ + "method":"GET", + "requestUri":"/v1/lexicons", + "responseCode":200 + }, + "input":{"shape":"ListLexiconsInput"}, + "output":{"shape":"ListLexiconsOutput"}, + "errors":[ + {"shape":"InvalidNextTokenException"}, + {"shape":"ServiceFailureException"} + ], + "documentation":"

Returns a list of pronunciation lexicons stored in an AWS Region. For more information, see Managing Lexicons.

" + }, + "ListSpeechSynthesisTasks":{ + "name":"ListSpeechSynthesisTasks", + "http":{ + "method":"GET", + "requestUri":"/v1/synthesisTasks", + "responseCode":200 + }, + "input":{"shape":"ListSpeechSynthesisTasksInput"}, + "output":{"shape":"ListSpeechSynthesisTasksOutput"}, + "errors":[ + {"shape":"InvalidNextTokenException"}, + {"shape":"ServiceFailureException"} + ], + "documentation":"

Returns a list of SpeechSynthesisTask objects ordered by their creation date. This operation can filter the tasks by their status, for example, allowing users to list only tasks that are completed.

" + }, + "PutLexicon":{ + "name":"PutLexicon", + "http":{ + "method":"PUT", + "requestUri":"/v1/lexicons/{LexiconName}", + "responseCode":200 + }, + "input":{"shape":"PutLexiconInput"}, + "output":{"shape":"PutLexiconOutput"}, + "errors":[ + {"shape":"InvalidLexiconException"}, + {"shape":"UnsupportedPlsAlphabetException"}, + {"shape":"UnsupportedPlsLanguageException"}, + {"shape":"LexiconSizeExceededException"}, + {"shape":"MaxLexemeLengthExceededException"}, + {"shape":"MaxLexiconsNumberExceededException"}, + {"shape":"ServiceFailureException"} + ], + "documentation":"

Stores a pronunciation lexicon in an AWS Region. If a lexicon with the same name already exists in the region, it is overwritten by the new lexicon. Lexicon operations have eventual consistency, therefore, it might take some time before the lexicon is available to the SynthesizeSpeech operation.

For more information, see Managing Lexicons.

" + }, + "StartSpeechSynthesisTask":{ + "name":"StartSpeechSynthesisTask", + "http":{ + "method":"POST", + "requestUri":"/v1/synthesisTasks", + "responseCode":200 + }, + "input":{"shape":"StartSpeechSynthesisTaskInput"}, + "output":{"shape":"StartSpeechSynthesisTaskOutput"}, + "errors":[ + {"shape":"TextLengthExceededException"}, + {"shape":"InvalidS3BucketException"}, + {"shape":"InvalidS3KeyException"}, + {"shape":"InvalidSampleRateException"}, + {"shape":"InvalidSnsTopicArnException"}, + {"shape":"InvalidSsmlException"}, + {"shape":"LexiconNotFoundException"}, + {"shape":"ServiceFailureException"}, + {"shape":"MarksNotSupportedForFormatException"}, + {"shape":"SsmlMarksNotSupportedForTextTypeException"}, + {"shape":"LanguageNotSupportedException"} + ], + "documentation":"

Allows the creation of an asynchronous synthesis task, by starting a new SpeechSynthesisTask. This operation requires all the standard information needed for speech synthesis, plus the name of an Amazon S3 bucket for the service to store the output of the synthesis task and two optional parameters (OutputS3KeyPrefix and SnsTopicArn). Once the synthesis task is created, this operation will return a SpeechSynthesisTask object, which will include an identifier of this task as well as the current status.

" + }, + "SynthesizeSpeech":{ + "name":"SynthesizeSpeech", + "http":{ + "method":"POST", + "requestUri":"/v1/speech", + "responseCode":200 + }, + "input":{"shape":"SynthesizeSpeechInput"}, + "output":{"shape":"SynthesizeSpeechOutput"}, + "errors":[ + {"shape":"TextLengthExceededException"}, + {"shape":"InvalidSampleRateException"}, + {"shape":"InvalidSsmlException"}, + {"shape":"LexiconNotFoundException"}, + {"shape":"ServiceFailureException"}, + {"shape":"MarksNotSupportedForFormatException"}, + {"shape":"SsmlMarksNotSupportedForTextTypeException"}, + {"shape":"LanguageNotSupportedException"} + ], + "documentation":"

Synthesizes UTF-8 input, plain text or SSML, to a stream of bytes. SSML input must be valid, well-formed SSML. Some alphabets might not be available with all the voices (for example, Cyrillic might not be read at all by English voices) unless phoneme mapping is used. For more information, see How it Works.

" + } + }, + "shapes":{ + "Alphabet":{"type":"string"}, + "AudioStream":{ + "type":"blob", + "streaming":true + }, + "ContentType":{"type":"string"}, + "DateTime":{"type":"timestamp"}, + "DeleteLexiconInput":{ + "type":"structure", + "required":["Name"], + "members":{ + "Name":{ + "shape":"LexiconName", + "documentation":"

The name of the lexicon to delete. Must be an existing lexicon in the region.

", + "location":"uri", + "locationName":"LexiconName" + } + } + }, + "DeleteLexiconOutput":{ + "type":"structure", + "members":{ + } + }, + "DescribeVoicesInput":{ + "type":"structure", + "members":{ + "LanguageCode":{ + "shape":"LanguageCode", + "documentation":"

The language identification tag (ISO 639 code for the language name-ISO 3166 country code) for filtering the list of voices returned. If you don't specify this optional parameter, all available voices are returned.

", + "location":"querystring", + "locationName":"LanguageCode" + }, + "IncludeAdditionalLanguageCodes":{ + "shape":"IncludeAdditionalLanguageCodes", + "documentation":"

Boolean value indicating whether to return any bilingual voices that use the specified language as an additional language. For instance, if you request all languages that use US English (es-US), and there is an Italian voice that speaks both Italian (it-IT) and US English, that voice will be included if you specify yes but not if you specify no.

", + "location":"querystring", + "locationName":"IncludeAdditionalLanguageCodes" + }, + "NextToken":{ + "shape":"NextToken", + "documentation":"

An opaque pagination token returned from the previous DescribeVoices operation. If present, this indicates where to continue the listing.

", + "location":"querystring", + "locationName":"NextToken" + } + } + }, + "DescribeVoicesOutput":{ + "type":"structure", + "members":{ + "Voices":{ + "shape":"VoiceList", + "documentation":"

A list of voices with their properties.

" + }, + "NextToken":{ + "shape":"NextToken", + "documentation":"

The pagination token to use in the next request to continue the listing of voices. NextToken is returned only if the response is truncated.

" + } + } + }, + "ErrorMessage":{"type":"string"}, + "Gender":{ + "type":"string", + "enum":[ + "Female", + "Male" + ] + }, + "GetLexiconInput":{ + "type":"structure", + "required":["Name"], + "members":{ + "Name":{ + "shape":"LexiconName", + "documentation":"

Name of the lexicon.

", + "location":"uri", + "locationName":"LexiconName" + } + } + }, + "GetLexiconOutput":{ + "type":"structure", + "members":{ + "Lexicon":{ + "shape":"Lexicon", + "documentation":"

Lexicon object that provides name and the string content of the lexicon.

" + }, + "LexiconAttributes":{ + "shape":"LexiconAttributes", + "documentation":"

Metadata of the lexicon, including phonetic alphabetic used, language code, lexicon ARN, number of lexemes defined in the lexicon, and size of lexicon in bytes.

" + } + } + }, + "GetSpeechSynthesisTaskInput":{ + "type":"structure", + "required":["TaskId"], + "members":{ + "TaskId":{ + "shape":"TaskId", + "documentation":"

The Amazon Polly generated identifier for a speech synthesis task.

", + "location":"uri", + "locationName":"TaskId" + } + } + }, + "GetSpeechSynthesisTaskOutput":{ + "type":"structure", + "members":{ + "SynthesisTask":{ + "shape":"SynthesisTask", + "documentation":"

SynthesisTask object that provides information from the requested task, including output format, creation time, task status, and so on.

" + } + } + }, + "IncludeAdditionalLanguageCodes":{"type":"boolean"}, + "InvalidLexiconException":{ + "type":"structure", + "members":{ + "message":{"shape":"ErrorMessage"} + }, + "documentation":"

Amazon Polly can't find the specified lexicon. Verify that the lexicon's name is spelled correctly, and then try again.

", + "error":{"httpStatusCode":400}, + "exception":true + }, + "InvalidNextTokenException":{ + "type":"structure", + "members":{ + "message":{"shape":"ErrorMessage"} + }, + "documentation":"

The NextToken is invalid. Verify that it's spelled correctly, and then try again.

", + "error":{"httpStatusCode":400}, + "exception":true + }, + "InvalidS3BucketException":{ + "type":"structure", + "members":{ + "message":{"shape":"ErrorMessage"} + }, + "documentation":"

The provided Amazon S3 bucket name is invalid. Please check your input with S3 bucket naming requirements and try again.

", + "error":{"httpStatusCode":400}, + "exception":true + }, + "InvalidS3KeyException":{ + "type":"structure", + "members":{ + "message":{"shape":"ErrorMessage"} + }, + "documentation":"

The provided Amazon S3 key prefix is invalid. Please provide a valid S3 object key name.

", + "error":{"httpStatusCode":400}, + "exception":true + }, + "InvalidSampleRateException":{ + "type":"structure", + "members":{ + "message":{"shape":"ErrorMessage"} + }, + "documentation":"

The specified sample rate is not valid.

", + "error":{"httpStatusCode":400}, + "exception":true + }, + "InvalidSnsTopicArnException":{ + "type":"structure", + "members":{ + "message":{"shape":"ErrorMessage"} + }, + "documentation":"

The provided SNS topic ARN is invalid. Please provide a valid SNS topic ARN and try again.

", + "error":{"httpStatusCode":400}, + "exception":true + }, + "InvalidSsmlException":{ + "type":"structure", + "members":{ + "message":{"shape":"ErrorMessage"} + }, + "documentation":"

The SSML you provided is invalid. Verify the SSML syntax, spelling of tags and values, and then try again.

", + "error":{"httpStatusCode":400}, + "exception":true + }, + "InvalidTaskIdException":{ + "type":"structure", + "members":{ + "message":{"shape":"ErrorMessage"} + }, + "documentation":"

The provided Task ID is not valid. Please provide a valid Task ID and try again.

", + "error":{"httpStatusCode":400}, + "exception":true + }, + "LanguageCode":{ + "type":"string", + "enum":[ + "cmn-CN", + "cy-GB", + "da-DK", + "de-DE", + "en-AU", + "en-GB", + "en-GB-WLS", + "en-IN", + "en-US", + "es-ES", + "es-US", + "fr-CA", + "fr-FR", + "is-IS", + "it-IT", + "ja-JP", + "hi-IN", + "ko-KR", + "nb-NO", + "nl-NL", + "pl-PL", + "pt-BR", + "pt-PT", + "ro-RO", + "ru-RU", + "sv-SE", + "tr-TR" + ] + }, + "LanguageCodeList":{ + "type":"list", + "member":{"shape":"LanguageCode"} + }, + "LanguageName":{"type":"string"}, + "LanguageNotSupportedException":{ + "type":"structure", + "members":{ + "message":{"shape":"ErrorMessage"} + }, + "documentation":"

The language specified is not currently supported by Amazon Polly in this capacity.

", + "error":{"httpStatusCode":400}, + "exception":true + }, + "LastModified":{"type":"timestamp"}, + "LexemesCount":{"type":"integer"}, + "Lexicon":{ + "type":"structure", + "members":{ + "Content":{ + "shape":"LexiconContent", + "documentation":"

Lexicon content in string format. The content of a lexicon must be in PLS format.

" + }, + "Name":{ + "shape":"LexiconName", + "documentation":"

Name of the lexicon.

" + } + }, + "documentation":"

Provides lexicon name and lexicon content in string format. For more information, see Pronunciation Lexicon Specification (PLS) Version 1.0.

" + }, + "LexiconArn":{"type":"string"}, + "LexiconAttributes":{ + "type":"structure", + "members":{ + "Alphabet":{ + "shape":"Alphabet", + "documentation":"

Phonetic alphabet used in the lexicon. Valid values are ipa and x-sampa.

" + }, + "LanguageCode":{ + "shape":"LanguageCode", + "documentation":"

Language code that the lexicon applies to. A lexicon with a language code such as \"en\" would be applied to all English languages (en-GB, en-US, en-AUS, en-WLS, and so on.

" + }, + "LastModified":{ + "shape":"LastModified", + "documentation":"

Date lexicon was last modified (a timestamp value).

" + }, + "LexiconArn":{ + "shape":"LexiconArn", + "documentation":"

Amazon Resource Name (ARN) of the lexicon.

" + }, + "LexemesCount":{ + "shape":"LexemesCount", + "documentation":"

Number of lexemes in the lexicon.

" + }, + "Size":{ + "shape":"Size", + "documentation":"

Total size of the lexicon, in characters.

" + } + }, + "documentation":"

Contains metadata describing the lexicon such as the number of lexemes, language code, and so on. For more information, see Managing Lexicons.

" + }, + "LexiconContent":{"type":"string"}, + "LexiconDescription":{ + "type":"structure", + "members":{ + "Name":{ + "shape":"LexiconName", + "documentation":"

Name of the lexicon.

" + }, + "Attributes":{ + "shape":"LexiconAttributes", + "documentation":"

Provides lexicon metadata.

" + } + }, + "documentation":"

Describes the content of the lexicon.

" + }, + "LexiconDescriptionList":{ + "type":"list", + "member":{"shape":"LexiconDescription"} + }, + "LexiconName":{ + "type":"string", + "pattern":"[0-9A-Za-z]{1,20}", + "sensitive":true + }, + "LexiconNameList":{ + "type":"list", + "member":{"shape":"LexiconName"}, + "max":5 + }, + "LexiconNotFoundException":{ + "type":"structure", + "members":{ + "message":{"shape":"ErrorMessage"} + }, + "documentation":"

Amazon Polly can't find the specified lexicon. This could be caused by a lexicon that is missing, its name is misspelled or specifying a lexicon that is in a different region.

Verify that the lexicon exists, is in the region (see ListLexicons) and that you spelled its name is spelled correctly. Then try again.

", + "error":{"httpStatusCode":404}, + "exception":true + }, + "LexiconSizeExceededException":{ + "type":"structure", + "members":{ + "message":{"shape":"ErrorMessage"} + }, + "documentation":"

The maximum size of the specified lexicon would be exceeded by this operation.

", + "error":{"httpStatusCode":400}, + "exception":true + }, + "ListLexiconsInput":{ + "type":"structure", + "members":{ + "NextToken":{ + "shape":"NextToken", + "documentation":"

An opaque pagination token returned from previous ListLexicons operation. If present, indicates where to continue the list of lexicons.

", + "location":"querystring", + "locationName":"NextToken" + } + } + }, + "ListLexiconsOutput":{ + "type":"structure", + "members":{ + "Lexicons":{ + "shape":"LexiconDescriptionList", + "documentation":"

A list of lexicon names and attributes.

" + }, + "NextToken":{ + "shape":"NextToken", + "documentation":"

The pagination token to use in the next request to continue the listing of lexicons. NextToken is returned only if the response is truncated.

" + } + } + }, + "ListSpeechSynthesisTasksInput":{ + "type":"structure", + "members":{ + "MaxResults":{ + "shape":"MaxResults", + "documentation":"

Maximum number of speech synthesis tasks returned in a List operation.

", + "location":"querystring", + "locationName":"MaxResults" + }, + "NextToken":{ + "shape":"NextToken", + "documentation":"

The pagination token to use in the next request to continue the listing of speech synthesis tasks.

", + "location":"querystring", + "locationName":"NextToken" + }, + "Status":{ + "shape":"TaskStatus", + "documentation":"

Status of the speech synthesis tasks returned in a List operation

", + "location":"querystring", + "locationName":"Status" + } + } + }, + "ListSpeechSynthesisTasksOutput":{ + "type":"structure", + "members":{ + "NextToken":{ + "shape":"NextToken", + "documentation":"

An opaque pagination token returned from the previous List operation in this request. If present, this indicates where to continue the listing.

" + }, + "SynthesisTasks":{ + "shape":"SynthesisTasks", + "documentation":"

List of SynthesisTask objects that provides information from the specified task in the list request, including output format, creation time, task status, and so on.

" + } + } + }, + "MarksNotSupportedForFormatException":{ + "type":"structure", + "members":{ + "message":{"shape":"ErrorMessage"} + }, + "documentation":"

Speech marks are not supported for the OutputFormat selected. Speech marks are only available for content in json format.

", + "error":{"httpStatusCode":400}, + "exception":true + }, + "MaxLexemeLengthExceededException":{ + "type":"structure", + "members":{ + "message":{"shape":"ErrorMessage"} + }, + "documentation":"

The maximum size of the lexeme would be exceeded by this operation.

", + "error":{"httpStatusCode":400}, + "exception":true + }, + "MaxLexiconsNumberExceededException":{ + "type":"structure", + "members":{ + "message":{"shape":"ErrorMessage"} + }, + "documentation":"

The maximum number of lexicons would be exceeded by this operation.

", + "error":{"httpStatusCode":400}, + "exception":true + }, + "MaxResults":{ + "type":"integer", + "max":100, + "min":1 + }, + "NextToken":{"type":"string"}, + "OutputFormat":{ + "type":"string", + "enum":[ + "json", + "mp3", + "ogg_vorbis", + "pcm" + ] + }, + "OutputS3BucketName":{ + "type":"string", + "pattern":"^[a-z0-9][\\.\\-a-z0-9]{1,61}[a-z0-9]$" + }, + "OutputS3KeyPrefix":{ + "type":"string", + "pattern":"^[0-9a-zA-Z\\/\\!\\-_\\.\\*\\'\\(\\)]{0,800}$" + }, + "OutputUri":{"type":"string"}, + "PutLexiconInput":{ + "type":"structure", + "required":[ + "Name", + "Content" + ], + "members":{ + "Name":{ + "shape":"LexiconName", + "documentation":"

Name of the lexicon. The name must follow the regular express format [0-9A-Za-z]{1,20}. That is, the name is a case-sensitive alphanumeric string up to 20 characters long.

", + "location":"uri", + "locationName":"LexiconName" + }, + "Content":{ + "shape":"LexiconContent", + "documentation":"

Content of the PLS lexicon as string data.

" + } + } + }, + "PutLexiconOutput":{ + "type":"structure", + "members":{ + } + }, + "RequestCharacters":{"type":"integer"}, + "SampleRate":{"type":"string"}, + "ServiceFailureException":{ + "type":"structure", + "members":{ + "message":{"shape":"ErrorMessage"} + }, + "documentation":"

An unknown condition has caused a service failure.

", + "error":{"httpStatusCode":500}, + "exception":true, + "fault":true + }, + "Size":{"type":"integer"}, + "SnsTopicArn":{ + "type":"string", + "pattern":"^arn:aws(-(cn|iso(-b)?|us-gov))?:sns:.*:\\w{12}:.+$" + }, + "SpeechMarkType":{ + "type":"string", + "enum":[ + "sentence", + "ssml", + "viseme", + "word" + ] + }, + "SpeechMarkTypeList":{ + "type":"list", + "member":{"shape":"SpeechMarkType"}, + "max":4 + }, + "SsmlMarksNotSupportedForTextTypeException":{ + "type":"structure", + "members":{ + "message":{"shape":"ErrorMessage"} + }, + "documentation":"

SSML speech marks are not supported for plain text-type input.

", + "error":{"httpStatusCode":400}, + "exception":true + }, + "StartSpeechSynthesisTaskInput":{ + "type":"structure", + "required":[ + "OutputFormat", + "OutputS3BucketName", + "Text", + "VoiceId" + ], + "members":{ + "LexiconNames":{ + "shape":"LexiconNameList", + "documentation":"

List of one or more pronunciation lexicon names you want the service to apply during synthesis. Lexicons are applied only if the language of the lexicon is the same as the language of the voice.

" + }, + "OutputFormat":{ + "shape":"OutputFormat", + "documentation":"

The format in which the returned output will be encoded. For audio stream, this will be mp3, ogg_vorbis, or pcm. For speech marks, this will be json.

" + }, + "OutputS3BucketName":{ + "shape":"OutputS3BucketName", + "documentation":"

Amazon S3 bucket name to which the output file will be saved.

" + }, + "OutputS3KeyPrefix":{ + "shape":"OutputS3KeyPrefix", + "documentation":"

The Amazon S3 key prefix for the output speech file.

" + }, + "SampleRate":{ + "shape":"SampleRate", + "documentation":"

The audio frequency specified in Hz.

The valid values for mp3 and ogg_vorbis are \"8000\", \"16000\", and \"22050\". The default value is \"22050\".

Valid values for pcm are \"8000\" and \"16000\" The default value is \"16000\".

" + }, + "SnsTopicArn":{ + "shape":"SnsTopicArn", + "documentation":"

ARN for the SNS topic optionally used for providing status notification for a speech synthesis task.

" + }, + "SpeechMarkTypes":{ + "shape":"SpeechMarkTypeList", + "documentation":"

The type of speech marks returned for the input text.

" + }, + "Text":{ + "shape":"Text", + "documentation":"

The input text to synthesize. If you specify ssml as the TextType, follow the SSML format for the input text.

" + }, + "TextType":{ + "shape":"TextType", + "documentation":"

Specifies whether the input text is plain text or SSML. The default value is plain text.

" + }, + "VoiceId":{ + "shape":"VoiceId", + "documentation":"

Voice ID to use for the synthesis.

" + }, + "LanguageCode":{ + "shape":"LanguageCode", + "documentation":"

Optional language code for the Speech Synthesis request. This is only necessary if using a bilingual voice, such as Aditi, which can be used for either Indian English (en-IN) or Hindi (hi-IN).

If a bilingual voice is used and no language code is specified, Amazon Polly will use the default language of the bilingual voice. The default language for any voice is the one returned by the DescribeVoices operation for the LanguageCode parameter. For example, if no language code is specified, Aditi will use Indian English rather than Hindi.

" + } + } + }, + "StartSpeechSynthesisTaskOutput":{ + "type":"structure", + "members":{ + "SynthesisTask":{ + "shape":"SynthesisTask", + "documentation":"

SynthesisTask object that provides information and attributes about a newly submitted speech synthesis task.

" + } + } + }, + "SynthesisTask":{ + "type":"structure", + "members":{ + "TaskId":{ + "shape":"TaskId", + "documentation":"

The Amazon Polly generated identifier for a speech synthesis task.

" + }, + "TaskStatus":{ + "shape":"TaskStatus", + "documentation":"

Current status of the individual speech synthesis task.

" + }, + "TaskStatusReason":{ + "shape":"TaskStatusReason", + "documentation":"

Reason for the current status of a specific speech synthesis task, including errors if the task has failed.

" + }, + "OutputUri":{ + "shape":"OutputUri", + "documentation":"

Pathway for the output speech file.

" + }, + "CreationTime":{ + "shape":"DateTime", + "documentation":"

Timestamp for the time the synthesis task was started.

" + }, + "RequestCharacters":{ + "shape":"RequestCharacters", + "documentation":"

Number of billable characters synthesized.

" + }, + "SnsTopicArn":{ + "shape":"SnsTopicArn", + "documentation":"

ARN for the SNS topic optionally used for providing status notification for a speech synthesis task.

" + }, + "LexiconNames":{ + "shape":"LexiconNameList", + "documentation":"

List of one or more pronunciation lexicon names you want the service to apply during synthesis. Lexicons are applied only if the language of the lexicon is the same as the language of the voice.

" + }, + "OutputFormat":{ + "shape":"OutputFormat", + "documentation":"

The format in which the returned output will be encoded. For audio stream, this will be mp3, ogg_vorbis, or pcm. For speech marks, this will be json.

" + }, + "SampleRate":{ + "shape":"SampleRate", + "documentation":"

The audio frequency specified in Hz.

The valid values for mp3 and ogg_vorbis are \"8000\", \"16000\", and \"22050\". The default value is \"22050\".

Valid values for pcm are \"8000\" and \"16000\" The default value is \"16000\".

" + }, + "SpeechMarkTypes":{ + "shape":"SpeechMarkTypeList", + "documentation":"

The type of speech marks returned for the input text.

" + }, + "TextType":{ + "shape":"TextType", + "documentation":"

Specifies whether the input text is plain text or SSML. The default value is plain text.

" + }, + "VoiceId":{ + "shape":"VoiceId", + "documentation":"

Voice ID to use for the synthesis.

" + }, + "LanguageCode":{ + "shape":"LanguageCode", + "documentation":"

Optional language code for a synthesis task. This is only necessary if using a bilingual voice, such as Aditi, which can be used for either Indian English (en-IN) or Hindi (hi-IN).

If a bilingual voice is used and no language code is specified, Amazon Polly will use the default language of the bilingual voice. The default language for any voice is the one returned by the DescribeVoices operation for the LanguageCode parameter. For example, if no language code is specified, Aditi will use Indian English rather than Hindi.

" + } + }, + "documentation":"

SynthesisTask object that provides information about a speech synthesis task.

" + }, + "SynthesisTaskNotFoundException":{ + "type":"structure", + "members":{ + "message":{"shape":"ErrorMessage"} + }, + "documentation":"

The Speech Synthesis task with requested Task ID cannot be found.

", + "error":{"httpStatusCode":400}, + "exception":true + }, + "SynthesisTasks":{ + "type":"list", + "member":{"shape":"SynthesisTask"} + }, + "SynthesizeSpeechInput":{ + "type":"structure", + "required":[ + "OutputFormat", + "Text", + "VoiceId" + ], + "members":{ + "LexiconNames":{ + "shape":"LexiconNameList", + "documentation":"

List of one or more pronunciation lexicon names you want the service to apply during synthesis. Lexicons are applied only if the language of the lexicon is the same as the language of the voice. For information about storing lexicons, see PutLexicon.

" + }, + "OutputFormat":{ + "shape":"OutputFormat", + "documentation":"

The format in which the returned output will be encoded. For audio stream, this will be mp3, ogg_vorbis, or pcm. For speech marks, this will be json.

When pcm is used, the content returned is audio/pcm in a signed 16-bit, 1 channel (mono), little-endian format.

" + }, + "SampleRate":{ + "shape":"SampleRate", + "documentation":"

The audio frequency specified in Hz.

The valid values for mp3 and ogg_vorbis are \"8000\", \"16000\", and \"22050\". The default value is \"22050\".

Valid values for pcm are \"8000\" and \"16000\" The default value is \"16000\".

" + }, + "SpeechMarkTypes":{ + "shape":"SpeechMarkTypeList", + "documentation":"

The type of speech marks returned for the input text.

" + }, + "Text":{ + "shape":"Text", + "documentation":"

Input text to synthesize. If you specify ssml as the TextType, follow the SSML format for the input text.

" + }, + "TextType":{ + "shape":"TextType", + "documentation":"

Specifies whether the input text is plain text or SSML. The default value is plain text. For more information, see Using SSML.

" + }, + "VoiceId":{ + "shape":"VoiceId", + "documentation":"

Voice ID to use for the synthesis. You can get a list of available voice IDs by calling the DescribeVoices operation.

" + }, + "LanguageCode":{ + "shape":"LanguageCode", + "documentation":"

Optional language code for the Synthesize Speech request. This is only necessary if using a bilingual voice, such as Aditi, which can be used for either Indian English (en-IN) or Hindi (hi-IN).

If a bilingual voice is used and no language code is specified, Amazon Polly will use the default language of the bilingual voice. The default language for any voice is the one returned by the DescribeVoices operation for the LanguageCode parameter. For example, if no language code is specified, Aditi will use Indian English rather than Hindi.

" + } + } + }, + "SynthesizeSpeechOutput":{ + "type":"structure", + "members":{ + "AudioStream":{ + "shape":"AudioStream", + "documentation":"

Stream containing the synthesized speech.

" + }, + "ContentType":{ + "shape":"ContentType", + "documentation":"

Specifies the type audio stream. This should reflect the OutputFormat parameter in your request.

  • If you request mp3 as the OutputFormat, the ContentType returned is audio/mpeg.

  • If you request ogg_vorbis as the OutputFormat, the ContentType returned is audio/ogg.

  • If you request pcm as the OutputFormat, the ContentType returned is audio/pcm in a signed 16-bit, 1 channel (mono), little-endian format.

  • If you request json as the OutputFormat, the ContentType returned is audio/json.

", + "location":"header", + "locationName":"Content-Type" + }, + "RequestCharacters":{ + "shape":"RequestCharacters", + "documentation":"

Number of characters synthesized.

", + "location":"header", + "locationName":"x-amzn-RequestCharacters" + } + }, + "payload":"AudioStream" + }, + "TaskId":{ + "type":"string", + "max":128, + "min":1 + }, + "TaskStatus":{ + "type":"string", + "enum":[ + "scheduled", + "inProgress", + "completed", + "failed" + ] + }, + "TaskStatusReason":{"type":"string"}, + "Text":{"type":"string"}, + "TextLengthExceededException":{ + "type":"structure", + "members":{ + "message":{"shape":"ErrorMessage"} + }, + "documentation":"

The value of the \"Text\" parameter is longer than the accepted limits. For the SynthesizeSpeech API, the limit for input text is a maximum of 6000 characters total, of which no more than 3000 can be billed characters. For the StartSpeechSynthesisTask API, the maximum is 200,000 characters, of which no more than 100,000 can be billed characters. SSML tags are not counted as billed characters.

", + "error":{"httpStatusCode":400}, + "exception":true + }, + "TextType":{ + "type":"string", + "enum":[ + "ssml", + "text" + ] + }, + "UnsupportedPlsAlphabetException":{ + "type":"structure", + "members":{ + "message":{"shape":"ErrorMessage"} + }, + "documentation":"

The alphabet specified by the lexicon is not a supported alphabet. Valid values are x-sampa and ipa.

", + "error":{"httpStatusCode":400}, + "exception":true + }, + "UnsupportedPlsLanguageException":{ + "type":"structure", + "members":{ + "message":{"shape":"ErrorMessage"} + }, + "documentation":"

The language specified in the lexicon is unsupported. For a list of supported languages, see Lexicon Attributes.

", + "error":{"httpStatusCode":400}, + "exception":true + }, + "Voice":{ + "type":"structure", + "members":{ + "Gender":{ + "shape":"Gender", + "documentation":"

Gender of the voice.

" + }, + "Id":{ + "shape":"VoiceId", + "documentation":"

Amazon Polly assigned voice ID. This is the ID that you specify when calling the SynthesizeSpeech operation.

" + }, + "LanguageCode":{ + "shape":"LanguageCode", + "documentation":"

Language code of the voice.

" + }, + "LanguageName":{ + "shape":"LanguageName", + "documentation":"

Human readable name of the language in English.

" + }, + "Name":{ + "shape":"VoiceName", + "documentation":"

Name of the voice (for example, Salli, Kendra, etc.). This provides a human readable voice name that you might display in your application.

" + }, + "AdditionalLanguageCodes":{ + "shape":"LanguageCodeList", + "documentation":"

Additional codes for languages available for the specified voice in addition to its default language.

For example, the default language for Aditi is Indian English (en-IN) because it was first used for that language. Since Aditi is bilingual and fluent in both Indian English and Hindi, this parameter would show the code hi-IN.

" + } + }, + "documentation":"

Description of the voice.

" + }, + "VoiceId":{ + "type":"string", + "enum":[ + "Geraint", + "Gwyneth", + "Mads", + "Naja", + "Hans", + "Marlene", + "Nicole", + "Russell", + "Amy", + "Brian", + "Emma", + "Raveena", + "Ivy", + "Joanna", + "Joey", + "Justin", + "Kendra", + "Kimberly", + "Matthew", + "Salli", + "Conchita", + "Enrique", + "Miguel", + "Penelope", + "Chantal", + "Celine", + "Lea", + "Mathieu", + "Dora", + "Karl", + "Carla", + "Giorgio", + "Mizuki", + "Liv", + "Lotte", + "Ruben", + "Ewa", + "Jacek", + "Jan", + "Maja", + "Ricardo", + "Vitoria", + "Cristiano", + "Ines", + "Carmen", + "Maxim", + "Tatyana", + "Astrid", + "Filiz", + "Vicki", + "Takumi", + "Seoyeon", + "Aditi", + "Zhiyu" + ] + }, + "VoiceList":{ + "type":"list", + "member":{"shape":"Voice"} + }, + "VoiceName":{"type":"string"} + }, + "documentation":"

Amazon Polly is a web service that makes it easy to synthesize speech from text.

The Amazon Polly service provides API operations for synthesizing high-quality speech from plain text and Speech Synthesis Markup Language (SSML), along with managing pronunciations lexicons that enable you to get the best results for your application domain.

" +} diff --git a/tts/src/tts/synthesizer.py b/tts/src/tts/synthesizer.py new file mode 100755 index 0000000..91b6e07 --- /dev/null +++ b/tts/src/tts/synthesizer.py @@ -0,0 +1,206 @@ +#!/usr/bin/env python + +# Copyright (c) 2018, Amazon.com, Inc. or its affiliates. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"). +# You may not use this file except in compliance with the License. +# A copy of the License is located at +# +# http://aws.amazon.com/apache2.0 +# +# or in the "license" file accompanying this file. This file is distributed +# on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +# express or implied. See the License for the specific language governing +# permissions and limitations under the License. + +import os +import time +import json +import rospy +import hashlib +from optparse import OptionParser +from tts.srv import Synthesizer, SynthesizerResponse + + +class SpeechSynthesizer: + """This class serves as a ROS service node that should be an entry point of a TTS task. + + Although the current implementation uses Amazon Polly as the synthesis engine, it is not hard to let it support + more heterogeneous engines while keeping the API the same. + + In order to support a variety of engines, the SynthesizerRequest was designed with flexibility in mind. It + has two fields: text and metadata. Both are strings. In most cases, a user can ignore the metadata and call + the service with some plain text. If the use case needs any control or engine-specific feature, the extra + information can be put into the JSON-form metadata. This class will use the information when calling the engine. + + The decoupling of the synthesizer and the actual synthesis engine will benefit the users in many ways. + + First, a user will be able to use a unified interface to do the TTS job and have the freedom to use different + engines available with no or very little change from the client side. + + Second, by applying some design patterns, the synthesizer can choose an engine dynamically. For example, a user + may prefer to use Amazon Polly but is also OK with an offline solution when network is not reliable. + + Third, engines can be complicated, thus difficult to use. As an example, Amazon Polly supports dozens of parameters + and is able to accomplish nontrivial synthesis jobs, but majority of the users never need those features. This + class provides a clean interface with two parameters only, so that it is much easier and pleasant to use. If by + any chance the advanced features are required, the user can always leverage the metadata field or even go to the + backend engine directly. + + Also, from an engineering perspective, simple and decoupled modules are easier to maintain. + + This class supports two modes of using polly. It can either call a service node or use AmazonPolly as a library. + + Start the service node:: + + $ rosrun tts synthesizer_node.py # use default configuration + $ rosrun tts synthesizer_node.py -e POLLY_LIBRARY # will not call polly service node + + Call the service:: + + $ rosservice call /synthesizer 'hello' '' + $ rosservice call /synthesizer 'hello' '"{\"text_type\":\"ssml\"}"' + """ + + class PollyViaNode: + def __init__(self, polly_service_name='polly'): + self.service_name = polly_service_name + + def __call__(self, **kwargs): + rospy.loginfo('will call service {}'.format(self.service_name)) + from tts.srv import Polly + rospy.wait_for_service(self.service_name) + polly = rospy.ServiceProxy(self.service_name, Polly) + return polly(polly_action='SynthesizeSpeech', **kwargs) + + class PollyDirect: + def __init__(self): + pass + + def __call__(self, **kwargs): + rospy.loginfo('will import amazonpolly.AmazonPolly') + from tts.amazonpolly import AmazonPolly + node = AmazonPolly() + return node.synthesize(**kwargs) + + ENGINES = { + 'POLLY_SERVICE': PollyViaNode, + 'POLLY_LIBRARY': PollyDirect, + } + + class BadEngineError(NameError): + pass + + def __init__(self, engine='POLLY_SERVICE', polly_service_name='polly'): + if engine not in self.ENGINES: + msg = 'bad engine {} which is not one of {}'.format(engine, ', '.join(SpeechSynthesizer.ENGINES.keys())) + raise SpeechSynthesizer.BadEngineError(msg) + + engine_kwargs = {'polly_service_name': polly_service_name} if engine == 'POLLY_SERVICE' else {} + self.engine = self.ENGINES[engine](**engine_kwargs) + + self.default_text_type = 'text' + self.default_voice_id = 'Joanna' + self.default_output_format = 'ogg_vorbis' + + def _call_engine(self, **kw): + """Call engine to do the job. + + If no output path is found from input, the audio file will be put into /tmp and the file name will have + a prefix of the md5 hash of the text. + + :param kw: what AmazonPolly needs to synthesize + :return: response from AmazonPolly + """ + if 'output_path' not in kw: + tmp_filename = hashlib.md5(kw['text']).hexdigest() + tmp_filepath = os.path.join(os.sep, 'tmp', 'voice_{}_{}'.format(tmp_filename, str(time.time()))) + kw['output_path'] = os.path.abspath(tmp_filepath) + rospy.loginfo('audio will be saved as {}'.format(kw['output_path'])) + + return self.engine(**kw) + + def _parse_request_or_raise(self, request): + """It will raise if request is malformed. + + :param request: an instance of SynthesizerRequest + :return: a dict + """ + md = json.loads(request.metadata) if request.metadata else {} + + md['output_format'] = md.get('output_format', self.default_output_format) + md['voice_id'] = md.get('voice_id', self.default_voice_id) + md['sample_rate'] = md.get('sample_rate', '16000' if md['output_format'].lower() == 'pcm' else '22050') + md['text_type'] = md.get('text_type', self.default_text_type) + md['text'] = request.text + + return md + + def _node_request_handler(self, request): + """The callback function for processing service request. + + It never raises. If anything unexpected happens, it will return a SynthesizerResponse with the exception. + + :param request: an instance of SynthesizerRequest + :return: a SynthesizerResponse + """ + rospy.loginfo(request) + try: + kws = self._parse_request_or_raise(request) + res = self._call_engine(**kws).result + + return SynthesizerResponse(res) + except Exception as e: + return SynthesizerResponse('Exception: {}'.format(e)) + + def start(self, node_name='synthesizer_node', service_name='synthesizer'): + """The entry point of a ROS service node. + + :param node_name: name of ROS node + :param service_name: name of ROS service + :return: it doesn't return + """ + rospy.init_node(node_name) + + service = rospy.Service(service_name, Synthesizer, self._node_request_handler) + + rospy.loginfo('{} running: {}'.format(node_name, service.uri)) + + rospy.spin() + + +def main(): + usage = '''usage: %prog [options] + ''' + + parser = OptionParser(usage) + + parser.add_option("-n", "--node-name", dest="node_name", default='synthesizer_node', + help="name of the ROS node", + metavar="NODE_NAME") + parser.add_option("-s", "--service-name", dest="service_name", default='synthesizer', + help="name of the ROS service", + metavar="SERVICE_NAME") + parser.add_option("-e", "--engine", dest="engine", default='POLLY_SERVICE', + help="name of the synthesis engine", + metavar="ENGINE") + parser.add_option("-p", "--polly-service-name", dest="polly_service_name", default='polly', + help="name of the polly service", + metavar="POLLY_SERVICE_NAME") + + (options, args) = parser.parse_args() + + node_name = options.node_name + service_name = options.service_name + engine = options.engine + polly_service_name = options.polly_service_name + + if engine == 'POLLY_SERVICE': + synthesizer = SpeechSynthesizer(engine=engine, polly_service_name=polly_service_name) + else: + synthesizer = SpeechSynthesizer(engine=engine) + synthesizer.start(node_name=node_name, service_name=service_name) + + +if __name__ == "__main__": + main() diff --git a/tts/srv/Polly.srv b/tts/srv/Polly.srv new file mode 100644 index 0000000..02ac7ad --- /dev/null +++ b/tts/srv/Polly.srv @@ -0,0 +1,22 @@ +string polly_action +string text +string text_type +string language_code +string voice_id +string output_format +string output_path +string sample_rate +string lexicon_content +string lexicon_name +string[] lexicon_names +string[] speech_mark_types +uint32 max_results +string next_token +string sns_topic_arn +string task_id +string task_status +string output_s3_bucket_name +string output_s3_key_prefix +bool include_additional_language_codes +--- +string result diff --git a/tts/srv/Synthesizer.srv b/tts/srv/Synthesizer.srv new file mode 100644 index 0000000..d623bb2 --- /dev/null +++ b/tts/srv/Synthesizer.srv @@ -0,0 +1,4 @@ +string text +string metadata +--- +string result diff --git a/tts/test/integration_tests.test b/tts/test/integration_tests.test new file mode 100644 index 0000000..4f662be --- /dev/null +++ b/tts/test/integration_tests.test @@ -0,0 +1,7 @@ + + + + + + + diff --git a/tts/test/test_integration.py b/tts/test/test_integration.py new file mode 100755 index 0000000..3f798f1 --- /dev/null +++ b/tts/test/test_integration.py @@ -0,0 +1,214 @@ +#!/usr/bin/env python + +# Copyright (c) 2018, Amazon.com, Inc. or its affiliates. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"). +# You may not use this file except in compliance with the License. +# A copy of the License is located at +# +# http://aws.amazon.com/apache2.0 +# +# or in the "license" file accompanying this file. This file is distributed +# on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +# express or implied. See the License for the specific language governing +# permissions and limitations under the License. + +from __future__ import print_function + +import sys +import json +import unittest + +import rospy +import rostest + +from tts.srv import Polly +from tts.srv import PollyResponse +from tts.srv import Synthesizer +from tts.srv import SynthesizerResponse + +# import tts which is a relay package, otherwise things don't work +# +# devel/lib/python2.7/dist-packages/ +# +-- tts +# | +-- __init__.py +# +-- ... +# +# per http://docs.ros.org/api/catkin/html/user_guide/setup_dot_py.html: +# +# A relay package is a folder with an __init__.py folder and nothing else. +# Importing this folder in python will execute the contents of __init__.py, +# which will in turn import the original python modules in the folder in +# the sourcespace using the python exec() function. + + +PKG = 'tts' +NAME = 'amazonpolly' + + +class TestPlainText(unittest.TestCase): + + def test_plain_text_to_wav_via_polly_node(self): + rospy.wait_for_service('polly') + polly = rospy.ServiceProxy('polly', Polly) + + test_text = 'Mary has a little lamb, little lamb, little lamb.' + res = polly(polly_action='SynthesizeSpeech', text=test_text) + self.assertIsNotNone(res) + self.assertTrue(type(res) is PollyResponse) + + r = json.loads(res.result) + self.assertIn('Audio Type', r, 'result should contain audio type') + self.assertIn('Audio File', r, 'result should contain file path') + self.assertIn('Amazon Polly Response Metadata', r, 'result should contain metadata') + + audio_type = r['Audio Type'] + audio_file = r['Audio File'] + md = r['Amazon Polly Response Metadata'] + self.assertTrue("'HTTPStatusCode': 200," in md) + self.assertEqual('audio/ogg', audio_type) + self.assertTrue(audio_file.endswith('.ogg')) + + import subprocess + o = subprocess.check_output(['file', audio_file], stderr=subprocess.STDOUT) + import re + m = re.search(r'.*Ogg data, Vorbis audi.*', o, flags=re.MULTILINE) + self.assertIsNotNone(m) + + def test_plain_text_using_polly_class(self): + from tts.amazonpolly import AmazonPolly + polly = AmazonPolly() + test_text = 'Mary has a little lamb, little lamb, little lamb.' + res = polly.synthesize(text=test_text) + self.assertIsNotNone(res) + self.assertTrue(type(res) is PollyResponse) + + r = json.loads(res.result) + self.assertIn('Audio Type', r, 'result should contain audio type') + self.assertIn('Audio File', r, 'result should contain file path') + self.assertIn('Amazon Polly Response Metadata', r, 'result should contain metadata') + + audio_type = r['Audio Type'] + audio_file = r['Audio File'] + md = r['Amazon Polly Response Metadata'] + self.assertTrue("'HTTPStatusCode': 200," in md) + self.assertEqual('audio/ogg', audio_type) + self.assertTrue(audio_file.endswith('.ogg')) + + import subprocess + o = subprocess.check_output(['file', audio_file], stderr=subprocess.STDOUT) + import re + m = re.search(r'.*Ogg data, Vorbis audi.*', o, flags=re.MULTILINE) + self.assertIsNotNone(m) + + def test_plain_text_via_synthesizer_node(self): + rospy.wait_for_service('synthesizer') + speech_synthesizer = rospy.ServiceProxy('synthesizer', Synthesizer) + + text = 'Mary has a little lamb, little lamb, little lamb.' + res = speech_synthesizer(text=text) + self.assertIsNotNone(res) + self.assertTrue(type(res) is SynthesizerResponse) + + r = json.loads(res.result) + self.assertIn('Audio Type', r, 'result should contain audio type') + self.assertIn('Audio File', r, 'result should contain file path') + self.assertIn('Amazon Polly Response Metadata', r, 'result should contain metadata') + + audio_type = r['Audio Type'] + audio_file = r['Audio File'] + md = r['Amazon Polly Response Metadata'] + self.assertTrue("'HTTPStatusCode': 200," in md) + self.assertEqual('audio/ogg', audio_type) + self.assertTrue(audio_file.endswith('.ogg')) + + import subprocess + o = subprocess.check_output(['file', audio_file], stderr=subprocess.STDOUT) + import re + m = re.search(r'.*Ogg data, Vorbis audi.*', o, flags=re.MULTILINE) + self.assertIsNotNone(m) + + def test_plain_text_to_mp3_via_polly_node(self): + rospy.wait_for_service('polly') + polly = rospy.ServiceProxy('polly', Polly) + + test_text = 'Mary has a little lamb, little lamb, little lamb.' + res = polly(polly_action='SynthesizeSpeech', text=test_text, output_format='mp3') + self.assertIsNotNone(res) + self.assertTrue(type(res) is PollyResponse) + + r = json.loads(res.result) + self.assertIn('Audio Type', r, 'result should contain audio type') + self.assertIn('Audio File', r, 'result should contain file path') + self.assertIn('Amazon Polly Response Metadata', r, 'result should contain metadata') + + audio_type = r['Audio Type'] + audio_file = r['Audio File'] + md = r['Amazon Polly Response Metadata'] + self.assertTrue("'HTTPStatusCode': 200," in md) + self.assertEqual('audio/mpeg', audio_type) + self.assertTrue(audio_file.endswith('.mp3')) + + import subprocess + o = subprocess.check_output(['file', audio_file], stderr=subprocess.STDOUT) + import re + m = re.search(r'.*MPEG.*layer III.*', o, flags=re.MULTILINE) + self.assertIsNotNone(m) + + def test_simple_ssml_via_polly_node(self): + rospy.wait_for_service('polly') + polly = rospy.ServiceProxy('polly', Polly) + + text = 'Mary has a little lamb, little lamb, little lamb.' + res = polly(polly_action='SynthesizeSpeech', text=text, text_type='ssml') + self.assertIsNotNone(res) + self.assertTrue(type(res) is PollyResponse) + + r = json.loads(res.result) + self.assertIn('Audio Type', r, 'result should contain audio type') + self.assertIn('Audio File', r, 'result should contain file path') + self.assertIn('Amazon Polly Response Metadata', r, 'result should contain metadata') + + audio_type = r['Audio Type'] + audio_file = r['Audio File'] + md = r['Amazon Polly Response Metadata'] + self.assertTrue("'HTTPStatusCode': 200," in md) + self.assertEqual('audio/ogg', audio_type) + self.assertTrue(audio_file.endswith('.ogg')) + + import subprocess + o = subprocess.check_output(['file', audio_file], stderr=subprocess.STDOUT) + import re + m = re.search(r'.*Ogg data, Vorbis audi.*', o, flags=re.MULTILINE) + self.assertIsNotNone(m) + + def test_simple_ssml_via_synthesizer_node(self): + rospy.wait_for_service('synthesizer') + speech_synthesizer = rospy.ServiceProxy('synthesizer', Synthesizer) + + text = 'Mary has a little lamb, little lamb, little lamb.' + res = speech_synthesizer(text=text, metadata='''{"text_type":"ssml"}''') + self.assertIsNotNone(res) + self.assertTrue(type(res) is SynthesizerResponse) + + r = json.loads(res.result) + self.assertIn('Audio Type', r, 'result should contain audio type') + self.assertIn('Audio File', r, 'result should contain file path') + self.assertIn('Amazon Polly Response Metadata', r, 'result should contain metadata') + + audio_type = r['Audio Type'] + audio_file = r['Audio File'] + md = r['Amazon Polly Response Metadata'] + self.assertTrue("'HTTPStatusCode': 200," in md) + self.assertEqual('audio/ogg', audio_type) + self.assertTrue(audio_file.endswith('.ogg')) + + import subprocess + o = subprocess.check_output(['file', audio_file], stderr=subprocess.STDOUT) + import re + m = re.search(r'.*Ogg data, Vorbis audi.*', o, flags=re.MULTILINE) + self.assertIsNotNone(m) + + +if __name__ == '__main__': + rostest.rosrun(PKG, NAME, TestPlainText, sys.argv) diff --git a/tts/test/test_unit_polly.py b/tts/test/test_unit_polly.py new file mode 100755 index 0000000..98d18a2 --- /dev/null +++ b/tts/test/test_unit_polly.py @@ -0,0 +1,178 @@ +#!/usr/bin/env python + +# Copyright (c) 2018, Amazon.com, Inc. or its affiliates. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"). +# You may not use this file except in compliance with the License. +# A copy of the License is located at +# +# http://aws.amazon.com/apache2.0 +# +# or in the "license" file accompanying this file. This file is distributed +# on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +# express or implied. See the License for the specific language governing +# permissions and limitations under the License. + +from __future__ import print_function + + +from mock import patch, MagicMock # python2 uses backport of unittest.mock(docs.python.org/3/library/unittest.mock.html) +import unittest + + +class TestPolly(unittest.TestCase): + + def setUp(self): + """important: import tts which is a relay package:: + + devel/lib/python2.7/dist-packages/ + +-- tts + | +-- __init__.py + +-- ... + + per http://docs.ros.org/api/catkin/html/user_guide/setup_dot_py.html: + + A relay package is a folder with an __init__.py folder and nothing else. + Importing this folder in python will execute the contents of __init__.py, + which will in turn import the original python modules in the folder in + the sourcespace using the python exec() function. + """ + import tts + self.assertIsNotNone(tts) + + @patch('tts.amazonpolly.Session') + def test_init(self, boto3_session_class_mock): + from tts.amazonpolly import AmazonPolly + AmazonPolly() + + boto3_session_class_mock.assert_called() + boto3_session_class_mock.return_value.client.assert_called_with('polly') + + @patch('tts.amazonpolly.Session') + def test_defaults(self, boto3_session_class_mock): + from tts.amazonpolly import AmazonPolly + polly = AmazonPolly() + + boto3_session_class_mock.assert_called() + boto3_session_class_mock.return_value.client.assert_called_with('polly') + + self.assertEqual('text', polly.default_text_type) + self.assertEqual('ogg_vorbis', polly.default_output_format) + self.assertEqual('Joanna', polly.default_voice_id) + self.assertEqual('.', polly.default_output_folder) + self.assertEqual('output', polly.default_output_file_basename) + + @patch('tts.amazonpolly.Session') + def test_good_synthesis_with_default_args(self, boto3_session_class_mock): + boto3_session_obj_mock = MagicMock() + boto3_polly_obj_mock = MagicMock() + boto3_polly_response_mock = MagicMock() + audio_stream_mock = MagicMock() + fake_audio_stream_data = 'I am audio.' + fake_audio_content_type = 'super tts' + fake_boto3_polly_response_metadata = {'foo': 'bar'} + + boto3_session_class_mock.return_value = boto3_session_obj_mock + boto3_session_obj_mock.client.return_value = boto3_polly_obj_mock + boto3_polly_obj_mock.synthesize_speech.return_value = boto3_polly_response_mock + audio_stream_mock.read.return_value = fake_audio_stream_data + d = { + 'AudioStream': audio_stream_mock, + 'ContentType': fake_audio_content_type, + 'ResponseMetadata': fake_boto3_polly_response_metadata + } + boto3_polly_response_mock.__contains__.side_effect = d.__contains__ + boto3_polly_response_mock.__getitem__.side_effect = d.__getitem__ + + from tts.amazonpolly import AmazonPolly + polly_under_test = AmazonPolly() + + boto3_session_class_mock.assert_called() + boto3_session_obj_mock.client.assert_called_with('polly') + + res = polly_under_test.synthesize(text='hello') + + expected_synthesize_speech_kwargs = { + 'LexiconNames': [], + 'OutputFormat': 'ogg_vorbis', + 'SampleRate': '22050', + 'SpeechMarkTypes': [], + 'Text': 'hello', + 'TextType': 'text', + 'VoiceId': 'Joanna', + } + boto3_polly_obj_mock.synthesize_speech.assert_called_with(**expected_synthesize_speech_kwargs) + + from tts.srv import PollyResponse + self.assertTrue(isinstance(res, PollyResponse)) + + import json + j = json.loads(res.result) + observed_audio_file_content = open(j['Audio File']).read() + self.assertEqual(fake_audio_stream_data, observed_audio_file_content) + + self.assertEqual(fake_audio_content_type, j['Audio Type']) + self.assertEqual(str(fake_boto3_polly_response_metadata), j['Amazon Polly Response Metadata']) + + @patch('tts.amazonpolly.Session') + def test_polly_raises(self, boto3_session_class_mock): + boto3_session_obj_mock = MagicMock() + boto3_polly_obj_mock = MagicMock() + boto3_polly_response_mock = MagicMock() + audio_stream_mock = MagicMock() + fake_audio_stream_data = 'I am audio.' + fake_audio_content_type = 'super voice' + fake_boto3_polly_response_metadata = {'foo': 'bar'} + + boto3_session_class_mock.return_value = boto3_session_obj_mock + boto3_session_obj_mock.client.return_value = boto3_polly_obj_mock + boto3_polly_obj_mock.synthesize_speech.side_effect = RuntimeError('Amazon Polly Exception') + audio_stream_mock.read.return_value = fake_audio_stream_data + d = { + 'AudioStream': audio_stream_mock, + 'ContentType': fake_audio_content_type, + 'ResponseMetadata': fake_boto3_polly_response_metadata + } + boto3_polly_response_mock.__contains__.side_effect = d.__contains__ + boto3_polly_response_mock.__getitem__.side_effect = d.__getitem__ + + from tts.amazonpolly import AmazonPolly + polly_under_test = AmazonPolly() + + boto3_session_class_mock.assert_called() + boto3_session_obj_mock.client.assert_called_with('polly') + + res = polly_under_test.synthesize(text='hello') + + expected_synthesize_speech_kwargs = { + 'LexiconNames': [], + 'OutputFormat': 'ogg_vorbis', + 'SampleRate': '22050', + 'SpeechMarkTypes': [], + 'Text': 'hello', + 'TextType': 'text', + 'VoiceId': 'Joanna', + } + boto3_polly_obj_mock.synthesize_speech.assert_called_with(**expected_synthesize_speech_kwargs) + + from tts.srv import PollyResponse + self.assertTrue(isinstance(res, PollyResponse)) + + import json + j = json.loads(res.result) + self.assertTrue('Exception' in j) + self.assertTrue('Traceback' in j) + + @patch('tts.amazonpolly.AmazonPolly') + def test_cli(self, amazon_polly_class_mock): + import sys + with patch.object(sys, 'argv', ['polly_node.py', '-n', 'polly-node']): + from tts import amazonpolly + amazonpolly.main() + amazon_polly_class_mock.assert_called() + amazon_polly_class_mock.return_value.start.assert_called_with(node_name='polly-node', service_name='polly') + + +if __name__ == '__main__': + import rosunit + rosunit.unitrun('tts', 'unittest-polly', TestPolly) diff --git a/tts/test/test_unit_synthesizer.py b/tts/test/test_unit_synthesizer.py new file mode 100755 index 0000000..0148906 --- /dev/null +++ b/tts/test/test_unit_synthesizer.py @@ -0,0 +1,148 @@ +#!/usr/bin/env python + +# Copyright (c) 2018, Amazon.com, Inc. or its affiliates. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"). +# You may not use this file except in compliance with the License. +# A copy of the License is located at +# +# http://aws.amazon.com/apache2.0 +# +# or in the "license" file accompanying this file. This file is distributed +# on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +# express or implied. See the License for the specific language governing +# permissions and limitations under the License. + +from __future__ import print_function + +from mock import patch, MagicMock # python2 uses backport of unittest.mock(docs.python.org/3/library/unittest.mock.html) +import unittest + + +class TestSynthesizer(unittest.TestCase): + + def setUp(self): + """important: import tts which is a relay package:: + + devel/lib/python2.7/dist-packages/ + +-- tts + | +-- __init__.py + +-- ... + + per http://docs.ros.org/api/catkin/html/user_guide/setup_dot_py.html: + + A relay package is a folder with an __init__.py folder and nothing else. + Importing this folder in python will execute the contents of __init__.py, + which will in turn import the original python modules in the folder in + the sourcespace using the python exec() function. + """ + import tts + self.assertIsNotNone(tts) + + def test_init(self): + from tts.synthesizer import SpeechSynthesizer + speech_synthesizer = SpeechSynthesizer() + self.assertEqual('text', speech_synthesizer.default_text_type) + + @patch('tts.amazonpolly.AmazonPolly') + def test_good_synthesis_with_mostly_default_args_using_polly_lib(self, polly_class_mock): + polly_obj_mock = MagicMock() + polly_class_mock.return_value = polly_obj_mock + + test_text = 'hello' + test_metadata = ''' + { + "output_path": "/tmp/test" + } + ''' + expected_polly_synthesize_args = { + 'output_format': 'ogg_vorbis', + 'voice_id': 'Joanna', + 'sample_rate': '22050', + 'text_type': 'text', + 'text': test_text, + 'output_path': "/tmp/test" + } + + from tts.synthesizer import SpeechSynthesizer + from tts.srv import SynthesizerRequest + speech_synthesizer = SpeechSynthesizer(engine='POLLY_LIBRARY') + request = SynthesizerRequest(text=test_text, metadata=test_metadata) + response = speech_synthesizer._node_request_handler(request) + + polly_class_mock.assert_called() + polly_obj_mock.synthesize.assert_called_with(**expected_polly_synthesize_args) + + self.assertEqual(response.result, polly_obj_mock.synthesize.return_value.result) + + @patch('tts.amazonpolly.AmazonPolly') + def test_synthesis_with_bad_metadata_using_polly_lib(self, polly_class_mock): + polly_obj_mock = MagicMock() + polly_class_mock.return_value = polly_obj_mock + + test_text = 'hello' + test_metadata = '''I am no JSON''' + + from tts.synthesizer import SpeechSynthesizer + from tts.srv import SynthesizerRequest + speech_synthesizer = SpeechSynthesizer(engine='POLLY_LIBRARY') + request = SynthesizerRequest(text=test_text, metadata=test_metadata) + response = speech_synthesizer._node_request_handler(request) + + self.assertTrue(response.result.startswith('Exception: ')) + + @patch('tts.amazonpolly.AmazonPolly') + def test_bad_engine(self, polly_class_mock): + polly_obj_mock = MagicMock() + polly_class_mock.return_value = polly_obj_mock + + ex = None + + from tts.synthesizer import SpeechSynthesizer + try: + SpeechSynthesizer(engine='NON-EXIST ENGINE') + except Exception as e: + ex = e + + self.assertTrue(isinstance(ex, SpeechSynthesizer.BadEngineError)) + + def test_cli_help_message(self): + import os + source_file_dir = os.path.dirname(os.path.abspath(__file__)) + synthersizer_path = os.path.join(source_file_dir, '..', 'scripts', 'synthesizer_node.py') + import subprocess + o = subprocess.check_output(['python', synthersizer_path, '-h']) + self.assertTrue(str(o).startswith('Usage: ')) + + @patch('tts.synthesizer.SpeechSynthesizer') + def test_cli_engine_dispatching_1(self, speech_synthesizer_class_mock): + import sys + with patch.object(sys, 'argv', ['synthesizer_node.py']): + import tts.synthesizer + tts.synthesizer.main() + speech_synthesizer_class_mock.assert_called_with(engine='POLLY_SERVICE', polly_service_name='polly') + speech_synthesizer_class_mock.return_value.start.assert_called_with(node_name='synthesizer_node', + service_name='synthesizer') + + @patch('tts.synthesizer.SpeechSynthesizer') + def test_cli_engine_dispatching_2(self, speech_synthesizer_class_mock): + import sys + with patch.object(sys, 'argv', ['synthesizer_node.py', '-e', 'POLLY_LIBRARY']): + from tts import synthesizer + synthesizer.main() + speech_synthesizer_class_mock.assert_called_with(engine='POLLY_LIBRARY') + speech_synthesizer_class_mock.return_value.start.assert_called() + + @patch('tts.synthesizer.SpeechSynthesizer') + def test_cli_engine_dispatching_3(self, speech_synthesizer_class_mock): + import sys + with patch.object(sys, 'argv', ['synthesizer_node.py', '-p', 'apolly']): + from tts import synthesizer + synthesizer.main() + speech_synthesizer_class_mock.assert_called_with(engine='POLLY_SERVICE', polly_service_name='apolly') + speech_synthesizer_class_mock.return_value.start.assert_called() + + +if __name__ == '__main__': + import rosunit + rosunit.unitrun('tts', 'unittest-synthesizer', TestSynthesizer) diff --git a/wiki/images/cpu.svg b/wiki/images/cpu.svg new file mode 100644 index 0000000..54b4080 --- /dev/null +++ b/wiki/images/cpu.svg @@ -0,0 +1,4 @@ + +CPU %44668810101212141416161818202022220.0000.0000.0000.0000.0006.0896.0896.0896.0896.0896.08912.18012.18012.18012.18012.18012.18018.26818.26818.26818.26818.26818.26824.35124.35124.35124.35124.35124.35130.44730.44730.44730.44730.44730.44736.53936.53936.53936.53936.53936.53942.63142.63142.63142.63142.63142.63148.71648.71648.71648.71648.71648.71654.79954.79954.79954.79954.79954.79960.86260.86260.86260.86260.86260.86266.91766.91766.91766.91766.91766.91772.98572.98572.98572.98572.98572.98572.98579.05479.05479.05479.05479.05479.05485.10485.10485.10485.10485.10485.10491.15491.15491.15491.15491.15491.15497.23397.23397.23397.23397.23397.233103.317103.317103.317103.317103.317103.317109.365109.365109.365109.365109.365109.365115.472115.472115.472115.472115.472115.472121.523121.523121.523121.523121.523121.523127.567127.567127.567127.567127.567127.567133.620133.620133.620133.620133.620133.620139.701139.701139.701139.701139.701139.701145.750145.750145.750145.750145.750145.750151.804151.804151.804151.804151.804151.804157.857157.857157.857157.857157.857157.857163.949163.949163.949163.949163.949163.949163.949170.020170.020170.020170.020170.020170.020176.095176.095176.095176.095176.095176.095182.164182.164182.164182.164182.164182.164188.260188.260188.260188.260188.260188.260194.350194.350194.350194.350194.350194.350200.439200.439200.439200.439200.439200.439206.527206.527206.527206.527206.527206.527212.613212.613212.613212.613212.613212.613218.709218.709218.709218.709218.709218.709224.795224.795224.795224.795224.795224.795230.881230.881230.881230.881230.881230.881236.970236.970236.970236.970236.970236.970236.970243.056243.056243.056243.056243.056243.056249.150249.150249.150249.150249.150249.150255.244255.244255.244255.244255.244255.244261.330261.330261.330261.330261.330261.330267.416267.416267.416267.416267.416267.416273.502273.502273.502273.502273.502273.502279.589279.589279.589279.589279.589279.589285.675285.675285.675285.675285.675285.675291.761291.761291.761291.761291.761291.761297.847297.847297.847297.847297.847297.847303.942303.942303.942303.942303.942303.942303.942310.029310.029310.029310.029310.029310.029316.116316.116316.116316.116316.116316.116322.208322.208322.208322.208322.208322.208328.293328.293328.293328.293328.293328.293334.383334.383334.383334.383334.383334.383340.468340.468340.468340.468340.468340.468346.552346.552346.552346.552346.552346.552352.638352.638352.638352.638352.638352.638358.724358.724358.724358.724358.724358.724364.809364.809364.809364.809364.809364.809370.898370.898370.898370.898370.898370.898376.990376.990376.990376.990376.990376.990376.990383.080383.080383.080383.080383.080383.080389.165389.165389.165389.165389.165389.165395.249395.249395.249395.249395.249395.249401.333401.333CPU %time16.7514.330769230769231125.18982473222980.00016.7516.117648187224248125.18982473222980.00016.7517.904527143679264125.18982473222980.00016.7519.69140610013428125.18982473222980.00016.7521.478285056589296125.18982473222980.00015.523.265164013044316151.735589094449846.08915.525.052042969499333151.735589094449846.08915.526.838921925954345151.735589094449846.08915.528.62580088240936151.735589094449846.08915.530.412679838864378151.735589094449846.08915.532.1995587953194151.735589094449846.0891333.98643775177442204.8271178188899712.1801335.77331670822943204.8271178188899712.1801337.56019566468444204.8271178188899712.1801339.347074621139456204.8271178188899712.1801341.13395357759448204.8271178188899712.1801342.920832534049495204.8271178188899712.1801244.70771149050451226.06372930866618.2681246.49459044695952226.06372930866618.2681248.28146940341454226.06372930866618.2681250.06834835986957226.06372930866618.2681251.85522731632457226.06372930866618.2681253.642106272779586226.06372930866618.2681155.428985229234605247.3003407984420524.3511157.21586418568962247.3003407984420524.3511159.002743142144645247.3003407984420524.3511160.78962209859966247.3003407984420524.3511162.57650105505467247.3003407984420524.3511164.36338001150969247.3003407984420524.35110.2566.15025896796472263.227799415774130.44710.2567.93713792441973263.227799415774130.44710.2569.72401688087474263.227799415774130.44710.2571.51089583732976263.227799415774130.44710.2573.29777479378477263.227799415774130.44710.2575.0846537502398263.227799415774130.4478.576.87153270669481300.391869522882236.5398.578.65841166314982300.391869522882236.5398.580.44529061960485300.391869522882236.5398.582.23216957605985300.391869522882236.5398.584.01904853251487300.391869522882236.5398.585.80592748896989300.391869522882236.5397.7587.5928064454249316.319328140214242.6317.7589.37968540187993316.319328140214242.6317.7591.16656435833492316.319328140214242.6317.7592.95344331478994316.319328140214242.6317.7594.74032227124496316.319328140214242.6317.7596.52720122769999316.319328140214242.6317.2598.31408018415499326.9376338851022348.7167.25100.10095914061002326.9376338851022348.7167.25101.88783809706501326.9376338851022348.7167.25103.67471705352006326.9376338851022348.7167.25105.46159600997504326.9376338851022348.7167.25107.24847496643008326.9376338851022348.7166.75109.03535392288511337.5559396299902354.7996.75110.8222328793401337.5559396299902354.7996.75112.60911183579513337.5559396299902354.7996.75114.39599079225013337.5559396299902354.7996.75116.18286974870516337.5559396299902354.7996.75117.96974870516019337.5559396299902354.7996119.75662766161518353.4833982473222760.8626121.54350661807021353.4833982473222760.8626123.33038557452521353.4833982473222760.8626125.11726453098022353.4833982473222760.8626126.90414348743528353.4833982473222760.8626128.69102244389026353.4833982473222760.8628.75130.4779014003453295.082716650438266.9178.75132.2647803568003295.082716650438266.9178.75134.05165931325533295.082716650438266.9178.75135.83853826971034295.082716650438266.9178.75137.62541722616535295.082716650438266.9178.75139.41229618262037295.082716650438266.91710.25141.19917513907538263.227799415774172.98510.25142.98605409553042263.227799415774172.98510.25144.77293305198543263.227799415774172.98510.25146.55981200844042263.227799415774172.98510.25148.34669096489546263.227799415774172.98510.25150.13356992135047263.227799415774172.98510.25151.92044887780548263.227799415774172.98511.25153.7073278342605241.9911879259980579.05411.25155.4942067907155241.9911879259980579.05411.25157.28108574717052241.9911879259980579.05411.25159.06796470362556241.9911879259980579.05411.25160.85484366008058241.9911879259980579.05411.25162.64172261653556241.9911879259980579.05410.5164.42860157299057257.9186465433300685.10410.5166.2154805294456257.9186465433300685.10410.5168.00235948590063257.9186465433300685.10410.5169.78923844235564257.9186465433300685.10410.5171.57611739881065257.9186465433300685.10410.5173.36299635526566257.9186465433300685.10411.5175.1498753117207236.6820350535540291.15411.5176.93675426817572236.6820350535540291.15411.5178.72363322463073236.6820350535540291.15411.5180.51051218108574236.6820350535540291.15411.5182.29739113754079236.6820350535540291.15411.5184.0842700939958236.6820350535540291.15417.25185.87114905045078114.5715189873417397.23317.25187.65802800690582114.5715189873417397.23317.25189.44490696336084114.5715189873417397.23317.25191.23178591981585114.5715189873417397.23317.25193.01866487627086114.5715189873417397.23317.25194.80554383272593114.5715189873417397.23320196.592422789180956.17083739045762103.31720198.379301745635956.17083739045762103.31720200.1661807020909456.17083739045762103.31720201.9530596585459856.17083739045762103.31720203.73993861500156.17083739045762103.31720205.5268175714559856.17083739045762103.31722.25207.3136965279118.388461538461513109.36522.25209.100575484366038.388461538461513109.36522.25210.887454440821078.388461538461513109.36522.25212.67433339727618.388461538461513109.36522.25214.461212353731048.388461538461513109.36522.25216.24809131018618.388461538461513109.36520.5218.0349702666411245.552531645569616115.47220.5219.8218492230961445.552531645569616115.47220.5221.6087281795511545.552531645569616115.47220.5223.3956071360061645.552531645569616115.47220.5225.1824860924611845.552531645569616115.47220.5226.969365048916245.552531645569616115.47219.25228.7562440053712372.09829600778966121.52319.25230.5431229618262472.09829600778966121.52319.25232.3300019182812372.09829600778966121.52319.25234.1168808747362772.09829600778966121.52319.25235.9037598311912872.09829600778966121.52319.25237.690638787646372.09829600778966121.52319.75239.4775177441013361.47999026290165127.56719.75241.2643967005563261.47999026290165127.56719.75243.0512756570113361.47999026290165127.56719.75244.8381546134663761.47999026290165127.56719.75246.625033569921461.47999026290165127.56719.75248.4119125263764361.47999026290165127.56720.25250.1987914828313850.86168451801365133.62020.25251.9856704392864250.86168451801365133.62020.25253.7725493957414450.86168451801365133.62020.25255.5594283521964550.86168451801365133.62020.25257.346307308651550.86168451801365133.62020.25259.133186265106550.86168451801365133.62020.5260.9200652215614645.552531645569616139.70120.5262.7069441780165645.552531645569616139.70120.5264.4938231344715445.552531645569616139.70120.5266.280702090926645.552531645569616139.70120.5268.0675810473815745.552531645569616139.70120.5269.8544600038365545.552531645569616139.70119271.641338960291677.40744888023369145.75019273.4282179167466377.40744888023369145.75019275.215096873201677.40744888023369145.75019277.0019758296566677.40744888023369145.75019278.788854786111777.40744888023369145.75019280.575733742566777.40744888023369145.75021.75282.362612699021719.006767283349575151.80421.75284.149491655476719.006767283349575151.80421.75285.936370611931719.006767283349575151.80421.75287.7232495683867319.006767283349575151.80421.75289.510128524841819.006767283349575151.80421.75291.2970074812967619.006767283349575151.80420293.083886437751856.17083739045762157.85720294.8707653942068456.17083739045762157.85720296.657644350661856.17083739045762157.85720298.4445233071168756.17083739045762157.85720300.231402263571956.17083739045762157.85720302.0182812200268456.17083739045762157.85720.25303.805160176481950.86168451801365163.94920.25305.592039132936950.86168451801365163.94920.25307.378918089391950.86168451801365163.94920.25309.1657970458469450.86168451801365163.94920.25310.95267600230250.86168451801365163.94920.25312.7395549587569750.86168451801365163.94920.25314.52643391521250.86168451801365163.94918.75316.3133128716670582.71660175267766170.02018.75318.1001918281220482.71660175267766170.02018.75319.88707078457782.71660175267766170.02018.75321.67394974103282.71660175267766170.02018.75323.4608286974870582.71660175267766170.02018.75325.247707653942182.71660175267766170.02017.25327.03458661039707114.57151898734173176.09517.25328.8214655668521114.57151898734173176.09517.25330.60834452330715114.57151898734173176.09517.25332.39522347976214114.57151898734173176.09517.25334.1821024362172114.57151898734173176.09517.25335.9689813926722114.57151898734173176.09514.5337.75586034912715172.9722005842259182.16414.5339.5427393055822172.9722005842259182.16414.5341.32961826203723172.9722005842259182.16414.5343.1164972184922172.9722005842259182.16414.5344.9033761749473172.9722005842259182.16414.5346.6902551314023172.9722005842259182.16413.5348.4771340878573194.20881207400194188.26013.5350.2640130443123194.20881207400194188.26013.5352.05089200076736194.20881207400194188.26013.5353.83777095722235194.20881207400194188.26013.5355.62464991367733194.20881207400194188.26013.5357.4115288701324194.20881207400194188.26014.25359.19840782658736178.28135345666993194.35014.25360.9852867830424178.28135345666993194.35014.25362.7721657394975178.28135345666993194.35014.25364.5590446959524178.28135345666993194.35014.25366.3459236524074178.28135345666993194.35014.25368.1328026088625178.28135345666993194.35013.25369.91968156531743199.51796494644594200.43913.25371.70656052177253199.51796494644594200.43913.25373.4934394782275199.51796494644594200.43913.25375.28031843468256199.51796494644594200.43913.25377.0671973911376199.51796494644594200.43913.25378.8540763475926199.51796494644594200.43912380.6409553040476226.063729308666206.52712382.4278342605026226.063729308666206.52712384.21471321695765226.063729308666206.52712386.00159217341263226.063729308666206.52712387.7884711298676226.063729308666206.52712389.57535008632266226.063729308666206.52710.25391.3622290427777263.2277994157741212.61310.25393.14910799923274263.2277994157741212.61310.25394.9359869556877263.2277994157741212.61310.25396.7228659121427263.2277994157741212.61310.25398.5097448685978263.2277994157741212.61310.25400.29662382505273263.2277994157741212.6139.5402.08350278150783279.1552580331061218.7099.5403.8703817379628279.1552580331061218.7099.5405.6572606944178279.1552580331061218.7099.5407.44413965087284279.1552580331061218.7099.5409.2310186073279279.1552580331061218.7099.5411.01789756378287279.1552580331061218.70914.75412.8047765202379167.66304771178187224.79514.75414.5916554766929167.66304771178187224.79514.75416.37853443314793167.66304771178187224.79514.75418.1654133896029167.66304771178187224.79514.75419.952292346058167.66304771178187224.79514.75421.73917130251294167.66304771178187224.79513.5423.526050258968194.20881207400194230.88113.5425.312929215423194.20881207400194230.88113.5427.099808171878194.20881207400194230.88113.5428.8866871283331194.20881207400194230.88113.5430.6735660847881194.20881207400194230.88113.5432.460445041243194.20881207400194230.88111.5434.2473239976981236.68203505355402236.97011.5436.0342029541531236.68203505355402236.97011.5437.82108191060814236.68203505355402236.97011.5439.6079608670631236.68203505355402236.97011.5441.3948398235181236.68203505355402236.97011.5443.1817187799732236.68203505355402236.97011.5444.9685977364282236.68203505355402236.97010.5446.75547669288324257.91864654333006243.05610.5448.5423556493382257.91864654333006243.05610.5450.3292346057932257.91864654333006243.05610.5452.11611356224824257.91864654333006243.05610.5453.90299251870323257.91864654333006243.05610.5455.6898714751583257.91864654333006243.0569.75457.47675043161325273.8461051606621249.1509.75459.2636293880683273.8461051606621249.1509.75461.0505083445234273.8461051606621249.1509.75462.8373873009783273.8461051606621249.1509.75464.6242662574334273.8461051606621249.1509.75466.4111452138884273.8461051606621249.1508.75468.19802417034333295.0827166504382255.2448.75469.98490312679843295.0827166504382255.2448.75471.7717820832534295.0827166504382255.2448.75473.55866103970845295.0827166504382255.2448.75475.3455399961635295.0827166504382255.2448.75477.1324189526185295.0827166504382255.24410.25478.9192979090735263.2277994157741261.33010.25480.7061768655285263.2277994157741261.33010.25482.4930558219836263.2277994157741261.33010.25484.27993477843853263.2277994157741261.33010.25486.0668137348935263.2277994157741261.33010.25487.8536926913486263.2277994157741261.3308.5489.6405716478036300.3918695228822267.4168.5491.42745060425864300.3918695228822267.4168.5493.2143295607136300.3918695228822267.4168.5495.0012085171686300.3918695228822267.4168.5496.7880874736237300.3918695228822267.4168.5498.57496643007863300.3918695228822267.4167.75500.36184538653373316.3193281402142273.5027.75502.1487243429887316.3193281402142273.5027.75503.93560329944364316.3193281402142273.5027.75505.72248225589874316.3193281402142273.5027.75507.5093612123537316.3193281402142273.5027.75509.29624016880877316.3193281402142273.5027.25511.08311912526375326.93763388510223279.5897.25512.8699980817188326.93763388510223279.5897.25514.6568770381738326.93763388510223279.5897.25516.4437559946289326.93763388510223279.5897.25518.2306349510839326.93763388510223279.5897.25520.017513907539326.93763388510223279.5896.75521.8043928639938337.55593962999023285.6756.75523.5912718204489337.55593962999023285.6756.75525.3781507769039337.55593962999023285.6756.75527.165029733359337.55593962999023285.6756.75528.951908689814337.55593962999023285.6756.75530.738787646269337.55593962999023285.6755.5532.525666602724364.10170399221033291.7615.5534.312545559179364.10170399221033291.7615.5536.099424515634364.10170399221033291.7615.5537.886303472089364.10170399221033291.7615.5539.673182428544364.10170399221033291.7615.5541.4600613849991364.10170399221033291.7615.25543.246940341454369.4108568646543297.8475.25545.0338192979091369.4108568646543297.8475.25546.8206982543641369.4108568646543297.8475.25548.6075772108192369.4108568646543297.8475.25550.3944561672743369.4108568646543297.8475.25552.1813351237292369.4108568646543297.8474.75553.9682140801841380.02916260954237303.9424.75555.7550930366392380.02916260954237303.9424.75557.5419719930942380.02916260954237303.9424.75559.3288509495493380.02916260954237303.9424.75561.1157299060043380.02916260954237303.9424.75562.9026088624593380.02916260954237303.9424.75564.6894878189142380.02916260954237303.9424.25566.4763667753692390.6474683544304310.0294.25568.2632457318243390.6474683544304310.0294.25570.0501246882793390.6474683544304310.0294.25571.8370036447343390.6474683544304310.0294.25573.6238826011894390.6474683544304310.0294.25575.4107615576443390.6474683544304310.0294577.1976405140994395.9566212268744316.1164578.9845194705545395.9566212268744316.1164580.7713984270094395.9566212268744316.1164582.5582773834645395.9566212268744316.1164584.3451563399194395.9566212268744316.1164586.1320352963745395.9566212268744316.1163.25587.9189142528295411.88407984420644322.2083.25589.7057932092845411.88407984420644322.2083.25591.4926721657396411.88407984420644322.2083.25593.2795511221946411.88407984420644322.2083.25595.0664300786495411.88407984420644322.2083.25596.8533090351045411.88407984420644322.2083598.6401879915595417.1932327166504328.2933600.4270669480146417.1932327166504328.2933602.2139459044696417.1932327166504328.2933604.0008248609247417.1932327166504328.2933605.7877038173796417.1932327166504328.2933607.5745827738345417.1932327166504328.2932.75609.3614617302896422.50238558909444334.3832.75611.1483406867447422.50238558909444334.3832.75612.9352196431997422.50238558909444334.3832.75614.7220985996548422.50238558909444334.3832.75616.5089775561097422.50238558909444334.3832.75618.2958565125648422.50238558909444334.3832.5620.0827354690198427.8115384615385340.4682.5621.8696144254749427.8115384615385340.4682.5623.6564933819299427.8115384615385340.4682.5625.4433723383848427.8115384615385340.4682.5627.2302512948398427.8115384615385340.4682.5629.0171302512948427.8115384615385340.4686.5630.8040092077499342.86509250243427346.5526.5632.5908881642049342.86509250243427346.5526.5634.3777671206599342.86509250243427346.5526.5636.164646077115342.86509250243427346.5526.5637.9515250335699342.86509250243427346.5526.5639.738403990025342.86509250243427346.5525.5641.5252829464799364.10170399221033352.6385.5643.312161902935364.10170399221033352.6385.5645.09904085939364.10170399221033352.6385.5646.885919815845364.10170399221033352.6385.5648.6727987723001364.10170399221033352.6385.5650.4596777287551364.10170399221033352.6385652.2465566852101374.72000973709834358.7245654.0334356416652374.72000973709834358.7245655.8203145981201374.72000973709834358.7245657.6071935545751374.72000973709834358.7245659.3940725110301374.72000973709834358.7245661.1809514674851374.72000973709834358.7244.5662.9678304239402385.33831548198634364.8094.5664.7547093803952385.33831548198634364.8094.5666.5415883368503385.33831548198634364.8094.5668.3284672933052385.33831548198634364.8094.5670.1153462497601385.33831548198634364.8094.5671.9022252062152385.33831548198634364.8094.25673.6891041626702390.6474683544304370.8984.25675.4759831191253390.6474683544304370.8984.25677.2628620755804390.6474683544304370.8984.25679.0497410320353390.6474683544304370.8984.25680.8366199884904390.6474683544304370.8984.25682.6234989449454390.6474683544304370.8983.5684.4103779014005406.5749269717624376.9903.5686.1972568578555406.5749269717624376.9903.5687.9841358143104406.5749269717624376.9903.5689.7710147707654406.5749269717624376.9903.5691.5578937272204406.5749269717624376.9903.5693.3447726836755406.5749269717624376.9903.5695.1316516401305406.5749269717624376.9903.25696.9185305965855411.88407984420644383.0803.25698.7054095530405411.88407984420644383.0803.25700.4922885094954411.88407984420644383.0803.25702.2791674659505411.88407984420644383.0803.25704.0660464224055411.88407984420644383.0803.25705.8529253788606411.88407984420644383.0803707.6398043353156417.1932327166504389.1653709.4266832917706417.1932327166504389.1653711.2135622482256417.1932327166504389.1653713.0004412046807417.1932327166504389.1653714.7873201611357417.1932327166504389.1653716.5741991175906417.1932327166504389.1652.75718.3610780740456422.50238558909444395.2492.75720.1479570305007422.50238558909444395.2492.75721.9348359869557422.50238558909444395.2492.75723.7217149434107422.50238558909444395.2492.75725.5085938998657422.50238558909444395.2492.75727.2954728563207422.50238558909444395.2492.5729.0823518127759427.8115384615385401.3332.5730.8692307692307427.8115384615385401.33310.7514.330769230769231252.609493670886080.00010.7516.117648187224248252.609493670886080.00010.7517.904527143679264252.609493670886080.00010.7519.69140610013428252.609493670886080.00010.7521.478285056589296252.609493670886080.00010.523.265164013044316257.918646543330066.08910.525.052042969499333257.918646543330066.08910.526.838921925954345257.918646543330066.08910.528.62580088240936257.918646543330066.08910.530.412679838864378257.918646543330066.08910.532.1995587953194257.918646543330066.08910.2533.98643775177442263.227799415774112.18010.2535.77331670822943263.227799415774112.18010.2537.56019566468444263.227799415774112.18010.2539.347074621139456263.227799415774112.18010.2541.13395357759448263.227799415774112.18010.2542.920832534049495263.227799415774112.1801044.70771149050451268.536952288218118.2681046.49459044695952268.536952288218118.2681048.28146940341454268.536952288218118.2681050.06834835986957268.536952288218118.2681051.85522731632457268.536952288218118.2681053.642106272779586268.536952288218118.2689.7555.428985229234605273.846105160662124.3519.7557.21586418568962273.846105160662124.3519.7559.002743142144645273.846105160662124.3519.7560.78962209859966273.846105160662124.3519.7562.57650105505467273.846105160662124.3519.7564.36338001150969273.846105160662124.3519.7566.15025896796472273.846105160662130.4479.7567.93713792441973273.846105160662130.4479.7569.72401688087474273.846105160662130.4479.7571.51089583732976273.846105160662130.4479.7573.29777479378477273.846105160662130.4479.7575.0846537502398273.846105160662130.4479.2576.87153270669481284.4644109055501536.5399.2578.65841166314982284.4644109055501536.5399.2580.44529061960485284.4644109055501536.5399.2582.23216957605985284.4644109055501536.5399.2584.01904853251487284.4644109055501536.5399.2585.80592748896989284.4644109055501536.5399.2587.5928064454249284.4644109055501542.6319.2589.37968540187993284.4644109055501542.6319.2591.16656435833492284.4644109055501542.6319.2592.95344331478994284.4644109055501542.6319.2594.74032227124496284.4644109055501542.6319.2596.52720122769999284.4644109055501542.631998.31408018415499289.773563777994148.7169100.10095914061002289.773563777994148.7169101.88783809706501289.773563777994148.7169103.67471705352006289.773563777994148.7169105.46159600997504289.773563777994148.7169107.24847496643008289.773563777994148.7169109.03535392288511289.773563777994154.7999110.8222328793401289.773563777994154.7999112.60911183579513289.773563777994154.7999114.39599079225013289.773563777994154.7999116.18286974870516289.773563777994154.7999117.96974870516019289.773563777994154.7998.75119.75662766161518295.082716650438260.8628.75121.54350661807021295.082716650438260.8628.75123.33038557452521295.082716650438260.8628.75125.11726453098022295.082716650438260.8628.75126.90414348743528295.082716650438260.8628.75128.69102244389026295.082716650438260.8629.25130.4779014003453284.4644109055501566.9179.25132.2647803568003284.4644109055501566.9179.25134.05165931325533284.4644109055501566.9179.25135.83853826971034284.4644109055501566.9179.25137.62541722616535284.4644109055501566.9179.25139.41229618262037284.4644109055501566.9179.5141.19917513907538279.155258033106172.9859.5142.98605409553042279.155258033106172.9859.5144.77293305198543279.155258033106172.9859.5146.55981200844042279.155258033106172.9859.5148.34669096489546279.155258033106172.9859.5150.13356992135047279.155258033106172.9859.5151.92044887780548279.155258033106172.9859.75153.7073278342605273.846105160662179.0549.75155.4942067907155273.846105160662179.0549.75157.28108574717052273.846105160662179.0549.75159.06796470362556273.846105160662179.0549.75160.85484366008058273.846105160662179.0549.75162.64172261653556273.846105160662179.0549.75164.42860157299057273.846105160662185.1049.75166.2154805294456273.846105160662185.1049.75168.00235948590063273.846105160662185.1049.75169.78923844235564273.846105160662185.1049.75171.57611739881065273.846105160662185.1049.75173.36299635526566273.846105160662185.10410175.1498753117207268.536952288218191.15410176.93675426817572268.536952288218191.15410178.72363322463073268.536952288218191.15410180.51051218108574268.536952288218191.15410182.29739113754079268.536952288218191.15410184.0842700939958268.536952288218191.15411.25185.87114905045078241.9911879259980597.23311.25187.65802800690582241.9911879259980597.23311.25189.44490696336084241.9911879259980597.23311.25191.23178591981585241.9911879259980597.23311.25193.01866487627086241.9911879259980597.23311.25194.80554383272593241.9911879259980597.23311.75196.5924227891809231.37288218111004103.31711.75198.3793017456359231.37288218111004103.31711.75200.16618070209094231.37288218111004103.31711.75201.95305965854598231.37288218111004103.31711.75203.739938615001231.37288218111004103.31711.75205.52681757145598231.37288218111004103.31712.5207.313696527911215.44542356377798109.36512.5209.10057548436603215.44542356377798109.36512.5210.88745444082107215.44542356377798109.36512.5212.6743333972761215.44542356377798109.36512.5214.46121235373104215.44542356377798109.36512.5216.2480913101861215.44542356377798109.36512.25218.03497026664112220.75457643622198115.47212.25219.82184922309614220.75457643622198115.47212.25221.60872817955115220.75457643622198115.47212.25223.39560713600616220.75457643622198115.47212.25225.18248609246118220.75457643622198115.47212.25226.9693650489162220.75457643622198115.47212.25228.75624400537123220.75457643622198121.52312.25230.54312296182624220.75457643622198121.52312.25232.33000191828123220.75457643622198121.52312.25234.11688087473627220.75457643622198121.52312.25235.90375983119128220.75457643622198121.52312.25237.6906387876463220.75457643622198121.52312.5239.47751774410133215.44542356377798127.56712.5241.26439670055632215.44542356377798127.56712.5243.05127565701133215.44542356377798127.56712.5244.83815461346637215.44542356377798127.56712.5246.6250335699214215.44542356377798127.56712.5248.41191252637643215.44542356377798127.56712.75250.19879148283138210.136270691334133.62012.75251.98567043928642210.136270691334133.62012.75253.77254939574144210.136270691334133.62012.75255.55942835219645210.136270691334133.62012.75257.3463073086515210.136270691334133.62012.75259.1331862651065210.136270691334133.62013260.92006522156146204.82711781888997139.70113262.70694417801656204.82711781888997139.70113264.49382313447154204.82711781888997139.70113266.2807020909266204.82711781888997139.70113268.06758104738157204.82711781888997139.70113269.85446000383655204.82711781888997139.70112.75271.6413389602916210.136270691334145.75012.75273.42821791674663210.136270691334145.75012.75275.2150968732016210.136270691334145.75012.75277.00197582965666210.136270691334145.75012.75278.7888547861117210.136270691334145.75012.75280.5757337425667210.136270691334145.75013.5282.3626126990217194.20881207400194151.80413.5284.1494916554767194.20881207400194151.80413.5285.9363706119317194.20881207400194151.80413.5287.72324956838673194.20881207400194151.80413.5289.5101285248418194.20881207400194151.80413.5291.29700748129676194.20881207400194151.80413.25293.0838864377518199.51796494644594157.85713.25294.87076539420684199.51796494644594157.85713.25296.6576443506618199.51796494644594157.85713.25298.44452330711687199.51796494644594157.85713.25300.2314022635719199.51796494644594157.85713.25302.01828122002684199.51796494644594157.85713.5303.8051601764819194.20881207400194163.94913.5305.5920391329369194.20881207400194163.94913.5307.3789180893919194.20881207400194163.94913.5309.16579704584694194.20881207400194163.94913.5310.952676002302194.20881207400194163.94913.5312.73955495875697194.20881207400194163.94913.5314.526433915212194.20881207400194163.94913.25316.31331287166705199.51796494644594170.02013.25318.10019182812204199.51796494644594170.02013.25319.887070784577199.51796494644594170.02013.25321.673949741032199.51796494644594170.02013.25323.46082869748705199.51796494644594170.02013.25325.2477076539421199.51796494644594170.02013327.03458661039707204.82711781888997176.09513328.8214655668521204.82711781888997176.09513330.60834452330715204.82711781888997176.09513332.39522347976214204.82711781888997176.09513334.1821024362172204.82711781888997176.09513335.9689813926722204.82711781888997176.09512.5337.75586034912715215.44542356377798182.16412.5339.5427393055822215.44542356377798182.16412.5341.32961826203723215.44542356377798182.16412.5343.1164972184922215.44542356377798182.16412.5344.9033761749473215.44542356377798182.16412.5346.6902551314023215.44542356377798182.16412.25348.4771340878573220.75457643622198188.26012.25350.2640130443123220.75457643622198188.26012.25352.05089200076736220.75457643622198188.26012.25353.83777095722235220.75457643622198188.26012.25355.62464991367733220.75457643622198188.26012.25357.4115288701324220.75457643622198188.26012.5359.19840782658736215.44542356377798194.35012.5360.9852867830424215.44542356377798194.35012.5362.7721657394975215.44542356377798194.35012.5364.5590446959524215.44542356377798194.35012.5366.3459236524074215.44542356377798194.35012.5368.1328026088625215.44542356377798194.35012.25369.91968156531743220.75457643622198200.43912.25371.70656052177253220.75457643622198200.43912.25373.4934394782275220.75457643622198200.43912.25375.28031843468256220.75457643622198200.43912.25377.0671973911376220.75457643622198200.43912.25378.8540763475926220.75457643622198200.43912.25380.6409553040476220.75457643622198206.52712.25382.4278342605026220.75457643622198206.52712.25384.21471321695765220.75457643622198206.52712.25386.00159217341263220.75457643622198206.52712.25387.7884711298676220.75457643622198206.52712.25389.57535008632266220.75457643622198206.52711.75391.3622290427777231.37288218111004212.61311.75393.14910799923274231.37288218111004212.61311.75394.9359869556877231.37288218111004212.61311.75396.7228659121427231.37288218111004212.61311.75398.5097448685978231.37288218111004212.61311.75400.29662382505273231.37288218111004212.61311.5402.08350278150783236.68203505355402218.70911.5403.8703817379628236.68203505355402218.70911.5405.6572606944178236.68203505355402218.70911.5407.44413965087284236.68203505355402218.70911.5409.2310186073279236.68203505355402218.70911.5411.01789756378287236.68203505355402218.70912.5412.8047765202379215.44542356377798224.79512.5414.5916554766929215.44542356377798224.79512.5416.37853443314793215.44542356377798224.79512.5418.1654133896029215.44542356377798224.79512.5419.952292346058215.44542356377798224.79512.5421.73917130251294215.44542356377798224.79512.5423.526050258968215.44542356377798230.88112.5425.312929215423215.44542356377798230.88112.5427.099808171878215.44542356377798230.88112.5428.8866871283331215.44542356377798230.88112.5430.6735660847881215.44542356377798230.88112.5432.460445041243215.44542356377798230.88112434.2473239976981226.063729308666236.97012436.0342029541531226.063729308666236.97012437.82108191060814226.063729308666236.97012439.6079608670631226.063729308666236.97012441.3948398235181226.063729308666236.97012443.1817187799732226.063729308666236.97012444.9685977364282226.063729308666236.97011.75446.75547669288324231.37288218111004243.05611.75448.5423556493382231.37288218111004243.05611.75450.3292346057932231.37288218111004243.05611.75452.11611356224824231.37288218111004243.05611.75453.90299251870323231.37288218111004243.05611.75455.6898714751583231.37288218111004243.05611.5457.47675043161325236.68203505355402249.15011.5459.2636293880683236.68203505355402249.15011.5461.0505083445234236.68203505355402249.15011.5462.8373873009783236.68203505355402249.15011.5464.6242662574334236.68203505355402249.15011.5466.4111452138884236.68203505355402249.15011.25468.19802417034333241.99118792599805255.24411.25469.98490312679843241.99118792599805255.24411.25471.7717820832534241.99118792599805255.24411.25473.55866103970845241.99118792599805255.24411.25475.3455399961635241.99118792599805255.24411.25477.1324189526185241.99118792599805255.24411.5478.9192979090735236.68203505355402261.33011.5480.7061768655285236.68203505355402261.33011.5482.4930558219836236.68203505355402261.33011.5484.27993477843853236.68203505355402261.33011.5486.0668137348935236.68203505355402261.33011.5487.8536926913486236.68203505355402261.33011.25489.6405716478036241.99118792599805267.41611.25491.42745060425864241.99118792599805267.41611.25493.2143295607136241.99118792599805267.41611.25495.0012085171686241.99118792599805267.41611.25496.7880874736237241.99118792599805267.41611.25498.57496643007863241.99118792599805267.41611500.36184538653373247.30034079844205273.50211502.1487243429887247.30034079844205273.50211503.93560329944364247.30034079844205273.50211505.72248225589874247.30034079844205273.50211507.5093612123537247.30034079844205273.50211509.29624016880877247.30034079844205273.50210.75511.08311912526375252.60949367088608279.58910.75512.8699980817188252.60949367088608279.58910.75514.6568770381738252.60949367088608279.58910.75516.4437559946289252.60949367088608279.58910.75518.2306349510839252.60949367088608279.58910.75520.017513907539252.60949367088608279.58910.75521.8043928639938252.60949367088608285.67510.75523.5912718204489252.60949367088608285.67510.75525.3781507769039252.60949367088608285.67510.75527.165029733359252.60949367088608285.67510.75528.951908689814252.60949367088608285.67510.75530.738787646269252.60949367088608285.67510.25532.525666602724263.2277994157741291.76110.25534.312545559179263.2277994157741291.76110.25536.099424515634263.2277994157741291.76110.25537.886303472089263.2277994157741291.76110.25539.673182428544263.2277994157741291.76110.25541.4600613849991263.2277994157741291.76110543.246940341454268.5369522882181297.84710545.0338192979091268.5369522882181297.84710546.8206982543641268.5369522882181297.84710548.6075772108192268.5369522882181297.84710550.3944561672743268.5369522882181297.84710552.1813351237292268.5369522882181297.84710553.9682140801841268.5369522882181303.94210555.7550930366392268.5369522882181303.94210557.5419719930942268.5369522882181303.94210559.3288509495493268.5369522882181303.94210561.1157299060043268.5369522882181303.94210562.9026088624593268.5369522882181303.94210564.6894878189142268.5369522882181303.9429.75566.4763667753692273.8461051606621310.0299.75568.2632457318243273.8461051606621310.0299.75570.0501246882793273.8461051606621310.0299.75571.8370036447343273.8461051606621310.0299.75573.6238826011894273.8461051606621310.0299.75575.4107615576443273.8461051606621310.0299.5577.1976405140994279.1552580331061316.1169.5578.9845194705545279.1552580331061316.1169.5580.7713984270094279.1552580331061316.1169.5582.5582773834645279.1552580331061316.1169.5584.3451563399194279.1552580331061316.1169.5586.1320352963745279.1552580331061316.1169.25587.9189142528295284.46441090555015322.2089.25589.7057932092845284.46441090555015322.2089.25591.4926721657396284.46441090555015322.2089.25593.2795511221946284.46441090555015322.2089.25595.0664300786495284.46441090555015322.2089.25596.8533090351045284.46441090555015322.2089598.6401879915595289.7735637779941328.2939600.4270669480146289.7735637779941328.2939602.2139459044696289.7735637779941328.2939604.0008248609247289.7735637779941328.2939605.7877038173796289.7735637779941328.2939607.5745827738345289.7735637779941328.2939609.3614617302896289.7735637779941334.3839611.1483406867447289.7735637779941334.3839612.9352196431997289.7735637779941334.3839614.7220985996548289.7735637779941334.3839616.5089775561097289.7735637779941334.3839618.2958565125648289.7735637779941334.3838.75620.0827354690198295.0827166504382340.4688.75621.8696144254749295.0827166504382340.4688.75623.6564933819299295.0827166504382340.4688.75625.4433723383848295.0827166504382340.4688.75627.2302512948398295.0827166504382340.4688.75629.0171302512948295.0827166504382340.4689.5630.8040092077499279.1552580331061346.5529.5632.5908881642049279.1552580331061346.5529.5634.3777671206599279.1552580331061346.5529.5636.164646077115279.1552580331061346.5529.5637.9515250335699279.1552580331061346.5529.5639.738403990025279.1552580331061346.5529.25641.5252829464799284.46441090555015352.6389.25643.312161902935284.46441090555015352.6389.25645.09904085939284.46441090555015352.6389.25646.885919815845284.46441090555015352.6389.25648.6727987723001284.46441090555015352.6389.25650.4596777287551284.46441090555015352.6389652.2465566852101289.7735637779941358.7249654.0334356416652289.7735637779941358.7249655.8203145981201289.7735637779941358.7249657.6071935545751289.7735637779941358.7249659.3940725110301289.7735637779941358.7249661.1809514674851289.7735637779941358.7248.75662.9678304239402295.0827166504382364.8098.75664.7547093803952295.0827166504382364.8098.75666.5415883368503295.0827166504382364.8098.75668.3284672933052295.0827166504382364.8098.75670.1153462497601295.0827166504382364.8098.75671.9022252062152295.0827166504382364.8098.75673.6891041626702295.0827166504382370.8988.75675.4759831191253295.0827166504382370.8988.75677.2628620755804295.0827166504382370.8988.75679.0497410320353295.0827166504382370.8988.75680.8366199884904295.0827166504382370.8988.75682.6234989449454295.0827166504382370.8988.5684.4103779014005300.3918695228822376.9908.5686.1972568578555300.3918695228822376.9908.5687.9841358143104300.3918695228822376.9908.5689.7710147707654300.3918695228822376.9908.5691.5578937272204300.3918695228822376.9908.5693.3447726836755300.3918695228822376.9908.5695.1316516401305300.3918695228822376.9908.25696.9185305965855305.70102239532616383.0808.25698.7054095530405305.70102239532616383.0808.25700.4922885094954305.70102239532616383.0808.25702.2791674659505305.70102239532616383.0808.25704.0660464224055305.70102239532616383.0808.25705.8529253788606305.70102239532616383.0808707.6398043353156311.0101752677702389.1658709.4266832917706311.0101752677702389.1658711.2135622482256311.0101752677702389.1658713.0004412046807311.0101752677702389.1658714.7873201611357311.0101752677702389.1658716.5741991175906311.0101752677702389.1658718.3610780740456311.0101752677702395.2498720.1479570305007311.0101752677702395.2498721.9348359869557311.0101752677702395.2498723.7217149434107311.0101752677702395.2498725.5085938998657311.0101752677702395.2498727.2954728563207311.0101752677702395.2497.75729.0823518127759316.3193281402142401.3337.75730.8692307692307316.3193281402142401.3336.2514.330769230769231348.17424537487830.0006.2516.117648187224248348.17424537487830.0006.2517.904527143679264348.17424537487830.0006.2519.69140610013428348.17424537487830.0006.2521.478285056589296348.17424537487830.0006.2523.265164013044316348.17424537487836.0896.2525.052042969499333348.17424537487836.0896.2526.838921925954345348.17424537487836.0896.2528.62580088240936348.17424537487836.0896.2530.412679838864378348.17424537487836.0896.2532.1995587953194348.17424537487836.089633.98643775177442353.4833982473222712.180635.77331670822943353.4833982473222712.180637.56019566468444353.4833982473222712.180639.347074621139456353.4833982473222712.180641.13395357759448353.4833982473222712.180642.920832534049495353.4833982473222712.180644.70771149050451353.4833982473222718.268646.49459044695952353.4833982473222718.268648.28146940341454353.4833982473222718.268650.06834835986957353.4833982473222718.268651.85522731632457353.4833982473222718.268653.642106272779586353.4833982473222718.268655.428985229234605353.4833982473222724.351657.21586418568962353.4833982473222724.351659.002743142144645353.4833982473222724.351660.78962209859966353.4833982473222724.351662.57650105505467353.4833982473222724.351664.36338001150969353.4833982473222724.351666.15025896796472353.4833982473222730.447667.93713792441973353.4833982473222730.447669.72401688087474353.4833982473222730.447671.51089583732976353.4833982473222730.447673.29777479378477353.4833982473222730.447675.0846537502398353.4833982473222730.447676.87153270669481353.4833982473222736.539678.65841166314982353.4833982473222736.539680.44529061960485353.4833982473222736.539682.23216957605985353.4833982473222736.539684.01904853251487353.4833982473222736.539685.80592748896989353.4833982473222736.5395.7587.5928064454249358.792551119766342.6315.7589.37968540187993358.792551119766342.6315.7591.16656435833492358.792551119766342.6315.7592.95344331478994358.792551119766342.6315.7594.74032227124496358.792551119766342.6315.7596.52720122769999358.792551119766342.6315.7598.31408018415499358.792551119766348.7165.75100.10095914061002358.792551119766348.7165.75101.88783809706501358.792551119766348.7165.75103.67471705352006358.792551119766348.7165.75105.46159600997504358.792551119766348.7165.75107.24847496643008358.792551119766348.7165.75109.03535392288511358.792551119766354.7995.75110.8222328793401358.792551119766354.7995.75112.60911183579513358.792551119766354.7995.75114.39599079225013358.792551119766354.7995.75116.18286974870516358.792551119766354.7995.75117.96974870516019358.792551119766354.7995.75119.75662766161518358.792551119766360.8625.75121.54350661807021358.792551119766360.8625.75123.33038557452521358.792551119766360.8625.75125.11726453098022358.792551119766360.8625.75126.90414348743528358.792551119766360.8625.75128.69102244389026358.792551119766360.8626130.4779014003453353.4833982473222766.9176132.2647803568003353.4833982473222766.9176134.05165931325533353.4833982473222766.9176135.83853826971034353.4833982473222766.9176137.62541722616535353.4833982473222766.9176139.41229618262037353.4833982473222766.9176141.19917513907538353.4833982473222772.9856142.98605409553042353.4833982473222772.9856144.77293305198543353.4833982473222772.9856146.55981200844042353.4833982473222772.9856148.34669096489546353.4833982473222772.9856150.13356992135047353.4833982473222772.9856151.92044887780548353.4833982473222772.9856.25153.7073278342605348.174245374878379.0546.25155.4942067907155348.174245374878379.0546.25157.28108574717052348.174245374878379.0546.25159.06796470362556348.174245374878379.0546.25160.85484366008058348.174245374878379.0546.25162.64172261653556348.174245374878379.0546.25164.42860157299057348.174245374878385.1046.25166.2154805294456348.174245374878385.1046.25168.00235948590063348.174245374878385.1046.25169.78923844235564348.174245374878385.1046.25171.57611739881065348.174245374878385.1046.25173.36299635526566348.174245374878385.1046.25175.1498753117207348.174245374878391.1546.25176.93675426817572348.174245374878391.1546.25178.72363322463073348.174245374878391.1546.25180.51051218108574348.174245374878391.1546.25182.29739113754079348.174245374878391.1546.25184.0842700939958348.174245374878391.1546.75185.87114905045078337.5559396299902397.2336.75187.65802800690582337.5559396299902397.2336.75189.44490696336084337.5559396299902397.2336.75191.23178591981585337.5559396299902397.2336.75193.01866487627086337.5559396299902397.2336.75194.80554383272593337.5559396299902397.2337196.5924227891809332.24678675754626103.3177198.3793017456359332.24678675754626103.3177200.16618070209094332.24678675754626103.3177201.95305965854598332.24678675754626103.3177203.739938615001332.24678675754626103.3177205.52681757145598332.24678675754626103.3177.25207.313696527911326.93763388510223109.3657.25209.10057548436603326.93763388510223109.3657.25210.88745444082107326.93763388510223109.3657.25212.6743333972761326.93763388510223109.3657.25214.46121235373104326.93763388510223109.3657.25216.2480913101861326.93763388510223109.3657.25218.03497026664112326.93763388510223115.4727.25219.82184922309614326.93763388510223115.4727.25221.60872817955115326.93763388510223115.4727.25223.39560713600616326.93763388510223115.4727.25225.18248609246118326.93763388510223115.4727.25226.9693650489162326.93763388510223115.4727.25228.75624400537123326.93763388510223121.5237.25230.54312296182624326.93763388510223121.5237.25232.33000191828123326.93763388510223121.5237.25234.11688087473627326.93763388510223121.5237.25235.90375983119128326.93763388510223121.5237.25237.6906387876463326.93763388510223121.5237.25239.47751774410133326.93763388510223127.5677.25241.26439670055632326.93763388510223127.5677.25243.05127565701133326.93763388510223127.5677.25244.83815461346637326.93763388510223127.5677.25246.6250335699214326.93763388510223127.5677.25248.41191252637643326.93763388510223127.5677.5250.19879148283138321.6284810126582133.6207.5251.98567043928642321.6284810126582133.6207.5253.77254939574144321.6284810126582133.6207.5255.55942835219645321.6284810126582133.6207.5257.3463073086515321.6284810126582133.6207.5259.1331862651065321.6284810126582133.6207.5260.92006522156146321.6284810126582139.7017.5262.70694417801656321.6284810126582139.7017.5264.49382313447154321.6284810126582139.7017.5266.2807020909266321.6284810126582139.7017.5268.06758104738157321.6284810126582139.7017.5269.85446000383655321.6284810126582139.7017.5271.6413389602916321.6284810126582145.7507.5273.42821791674663321.6284810126582145.7507.5275.2150968732016321.6284810126582145.7507.5277.00197582965666321.6284810126582145.7507.5278.7888547861117321.6284810126582145.7507.5280.5757337425667321.6284810126582145.7507.75282.3626126990217316.3193281402142151.8047.75284.1494916554767316.3193281402142151.8047.75285.9363706119317316.3193281402142151.8047.75287.72324956838673316.3193281402142151.8047.75289.5101285248418316.3193281402142151.8047.75291.29700748129676316.3193281402142151.8047.75293.0838864377518316.3193281402142157.8577.75294.87076539420684316.3193281402142157.8577.75296.6576443506618316.3193281402142157.8577.75298.44452330711687316.3193281402142157.8577.75300.2314022635719316.3193281402142157.8577.75302.01828122002684316.3193281402142157.8577.75303.8051601764819316.3193281402142163.9497.75305.5920391329369316.3193281402142163.9497.75307.3789180893919316.3193281402142163.9497.75309.16579704584694316.3193281402142163.9497.75310.952676002302316.3193281402142163.9497.75312.73955495875697316.3193281402142163.9497.75314.526433915212316.3193281402142163.9497.75316.31331287166705316.3193281402142170.0207.75318.10019182812204316.3193281402142170.0207.75319.887070784577316.3193281402142170.0207.75321.673949741032316.3193281402142170.0207.75323.46082869748705316.3193281402142170.0207.75325.2477076539421316.3193281402142170.0207.75327.03458661039707316.3193281402142176.0957.75328.8214655668521316.3193281402142176.0957.75330.60834452330715316.3193281402142176.0957.75332.39522347976214316.3193281402142176.0957.75334.1821024362172316.3193281402142176.0957.75335.9689813926722316.3193281402142176.0957.75337.75586034912715316.3193281402142182.1647.75339.5427393055822316.3193281402142182.1647.75341.32961826203723316.3193281402142182.1647.75343.1164972184922316.3193281402142182.1647.75344.9033761749473316.3193281402142182.1647.75346.6902551314023316.3193281402142182.1647.5348.4771340878573321.6284810126582188.2607.5350.2640130443123321.6284810126582188.2607.5352.05089200076736321.6284810126582188.2607.5353.83777095722235321.6284810126582188.2607.5355.62464991367733321.6284810126582188.2607.5357.4115288701324321.6284810126582188.2607.75359.19840782658736316.3193281402142194.3507.75360.9852867830424316.3193281402142194.3507.75362.7721657394975316.3193281402142194.3507.75364.5590446959524316.3193281402142194.3507.75366.3459236524074316.3193281402142194.3507.75368.1328026088625316.3193281402142194.3507.75369.91968156531743316.3193281402142200.4397.75371.70656052177253316.3193281402142200.4397.75373.4934394782275316.3193281402142200.4397.75375.28031843468256316.3193281402142200.4397.75377.0671973911376316.3193281402142200.4397.75378.8540763475926316.3193281402142200.4397.5380.6409553040476321.6284810126582206.5277.5382.4278342605026321.6284810126582206.5277.5384.21471321695765321.6284810126582206.5277.5386.00159217341263321.6284810126582206.5277.5387.7884711298676321.6284810126582206.5277.5389.57535008632266321.6284810126582206.5277.5391.3622290427777321.6284810126582212.6137.5393.14910799923274321.6284810126582212.6137.5394.9359869556877321.6284810126582212.6137.5396.7228659121427321.6284810126582212.6137.5398.5097448685978321.6284810126582212.6137.5400.29662382505273321.6284810126582212.6137.5402.08350278150783321.6284810126582218.7097.5403.8703817379628321.6284810126582218.7097.5405.6572606944178321.6284810126582218.7097.5407.44413965087284321.6284810126582218.7097.5409.2310186073279321.6284810126582218.7097.5411.01789756378287321.6284810126582218.7097.75412.8047765202379316.3193281402142224.7957.75414.5916554766929316.3193281402142224.7957.75416.37853443314793316.3193281402142224.7957.75418.1654133896029316.3193281402142224.7957.75419.952292346058316.3193281402142224.7957.75421.73917130251294316.3193281402142224.7957.75423.526050258968316.3193281402142230.8817.75425.312929215423316.3193281402142230.8817.75427.099808171878316.3193281402142230.8817.75428.8866871283331316.3193281402142230.8817.75430.6735660847881316.3193281402142230.8817.75432.460445041243316.3193281402142230.8817.75434.2473239976981316.3193281402142236.9707.75436.0342029541531316.3193281402142236.9707.75437.82108191060814316.3193281402142236.9707.75439.6079608670631316.3193281402142236.9707.75441.3948398235181316.3193281402142236.9707.75443.1817187799732316.3193281402142236.9707.75444.9685977364282316.3193281402142236.9707.5446.75547669288324321.6284810126582243.0567.5448.5423556493382321.6284810126582243.0567.5450.3292346057932321.6284810126582243.0567.5452.11611356224824321.6284810126582243.0567.5453.90299251870323321.6284810126582243.0567.5455.6898714751583321.6284810126582243.0567.5457.47675043161325321.6284810126582249.1507.5459.2636293880683321.6284810126582249.1507.5461.0505083445234321.6284810126582249.1507.5462.8373873009783321.6284810126582249.1507.5464.6242662574334321.6284810126582249.1507.5466.4111452138884321.6284810126582249.1507.5468.19802417034333321.6284810126582255.2447.5469.98490312679843321.6284810126582255.2447.5471.7717820832534321.6284810126582255.2447.5473.55866103970845321.6284810126582255.2447.5475.3455399961635321.6284810126582255.2447.5477.1324189526185321.6284810126582255.2447.5478.9192979090735321.6284810126582261.3307.5480.7061768655285321.6284810126582261.3307.5482.4930558219836321.6284810126582261.3307.5484.27993477843853321.6284810126582261.3307.5486.0668137348935321.6284810126582261.3307.5487.8536926913486321.6284810126582261.3307.5489.6405716478036321.6284810126582267.4167.5491.42745060425864321.6284810126582267.4167.5493.2143295607136321.6284810126582267.4167.5495.0012085171686321.6284810126582267.4167.5496.7880874736237321.6284810126582267.4167.5498.57496643007863321.6284810126582267.4167.5500.36184538653373321.6284810126582273.5027.5502.1487243429887321.6284810126582273.5027.5503.93560329944364321.6284810126582273.5027.5505.72248225589874321.6284810126582273.5027.5507.5093612123537321.6284810126582273.5027.5509.29624016880877321.6284810126582273.5027.5511.08311912526375321.6284810126582279.5897.5512.8699980817188321.6284810126582279.5897.5514.6568770381738321.6284810126582279.5897.5516.4437559946289321.6284810126582279.5897.5518.2306349510839321.6284810126582279.5897.5520.017513907539321.6284810126582279.5897.25521.8043928639938326.93763388510223285.6757.25523.5912718204489326.93763388510223285.6757.25525.3781507769039326.93763388510223285.6757.25527.165029733359326.93763388510223285.6757.25528.951908689814326.93763388510223285.6757.25530.738787646269326.93763388510223285.6757.25532.525666602724326.93763388510223291.7617.25534.312545559179326.93763388510223291.7617.25536.099424515634326.93763388510223291.7617.25537.886303472089326.93763388510223291.7617.25539.673182428544326.93763388510223291.7617.25541.4600613849991326.93763388510223291.7617.25543.246940341454326.93763388510223297.8477.25545.0338192979091326.93763388510223297.8477.25546.8206982543641326.93763388510223297.8477.25548.6075772108192326.93763388510223297.8477.25550.3944561672743326.93763388510223297.8477.25552.1813351237292326.93763388510223297.8477.25553.9682140801841326.93763388510223303.9427.25555.7550930366392326.93763388510223303.9427.25557.5419719930942326.93763388510223303.9427.25559.3288509495493326.93763388510223303.9427.25561.1157299060043326.93763388510223303.9427.25562.9026088624593326.93763388510223303.9427.25564.6894878189142326.93763388510223303.9427.25566.4763667753692326.93763388510223310.0297.25568.2632457318243326.93763388510223310.0297.25570.0501246882793326.93763388510223310.0297.25571.8370036447343326.93763388510223310.0297.25573.6238826011894326.93763388510223310.0297.25575.4107615576443326.93763388510223310.0297577.1976405140994332.24678675754626316.1167578.9845194705545332.24678675754626316.1167580.7713984270094332.24678675754626316.1167582.5582773834645332.24678675754626316.1167584.3451563399194332.24678675754626316.1167586.1320352963745332.24678675754626316.1167587.9189142528295332.24678675754626322.2087589.7057932092845332.24678675754626322.2087591.4926721657396332.24678675754626322.2087593.2795511221946332.24678675754626322.2087595.0664300786495332.24678675754626322.2087596.8533090351045332.24678675754626322.2087598.6401879915595332.24678675754626328.2937600.4270669480146332.24678675754626328.2937602.2139459044696332.24678675754626328.2937604.0008248609247332.24678675754626328.2937605.7877038173796332.24678675754626328.2937607.5745827738345332.24678675754626328.2937609.3614617302896332.24678675754626334.3837611.1483406867447332.24678675754626334.3837612.9352196431997332.24678675754626334.3837614.7220985996548332.24678675754626334.3837616.5089775561097332.24678675754626334.3837618.2958565125648332.24678675754626334.3836.75620.0827354690198337.55593962999023340.4686.75621.8696144254749337.55593962999023340.4686.75623.6564933819299337.55593962999023340.4686.75625.4433723383848337.55593962999023340.4686.75627.2302512948398337.55593962999023340.4686.75629.0171302512948337.55593962999023340.4687630.8040092077499332.24678675754626346.5527632.5908881642049332.24678675754626346.5527634.3777671206599332.24678675754626346.5527636.164646077115332.24678675754626346.5527637.9515250335699332.24678675754626346.5527639.738403990025332.24678675754626346.5527641.5252829464799332.24678675754626352.6387643.312161902935332.24678675754626352.6387645.09904085939332.24678675754626352.6387646.885919815845332.24678675754626352.6387648.6727987723001332.24678675754626352.6387650.4596777287551332.24678675754626352.6387652.2465566852101332.24678675754626358.7247654.0334356416652332.24678675754626358.7247655.8203145981201332.24678675754626358.7247657.6071935545751332.24678675754626358.7247659.3940725110301332.24678675754626358.7247661.1809514674851332.24678675754626358.7246.75662.9678304239402337.55593962999023364.8096.75664.7547093803952337.55593962999023364.8096.75666.5415883368503337.55593962999023364.8096.75668.3284672933052337.55593962999023364.8096.75670.1153462497601337.55593962999023364.8096.75671.9022252062152337.55593962999023364.8096.75673.6891041626702337.55593962999023370.8986.75675.4759831191253337.55593962999023370.8986.75677.2628620755804337.55593962999023370.8986.75679.0497410320353337.55593962999023370.8986.75680.8366199884904337.55593962999023370.8986.75682.6234989449454337.55593962999023370.8986.75684.4103779014005337.55593962999023376.9906.75686.1972568578555337.55593962999023376.9906.75687.9841358143104337.55593962999023376.9906.75689.7710147707654337.55593962999023376.9906.75691.5578937272204337.55593962999023376.9906.75693.3447726836755337.55593962999023376.9906.75695.1316516401305337.55593962999023376.9906.75696.9185305965855337.55593962999023383.0806.75698.7054095530405337.55593962999023383.0806.75700.4922885094954337.55593962999023383.0806.75702.2791674659505337.55593962999023383.0806.75704.0660464224055337.55593962999023383.0806.75705.8529253788606337.55593962999023383.0806.75707.6398043353156337.55593962999023389.1656.75709.4266832917706337.55593962999023389.1656.75711.2135622482256337.55593962999023389.1656.75713.0004412046807337.55593962999023389.1656.75714.7873201611357337.55593962999023389.1656.75716.5741991175906337.55593962999023389.1656.75718.3610780740456337.55593962999023395.2496.75720.1479570305007337.55593962999023395.2496.75721.9348359869557337.55593962999023395.2496.75723.7217149434107337.55593962999023395.2496.75725.5085938998657337.55593962999023395.2496.75727.2954728563207337.55593962999023395.2496.5729.0823518127759342.86509250243427401.3336.5730.8692307692307342.86509250243427401.333Load Average (1min)Load Average (5min)Load Average (15min) \ No newline at end of file diff --git a/wiki/images/memory.svg b/wiki/images/memory.svg new file mode 100644 index 0000000..da9f3fd --- /dev/null +++ b/wiki/images/memory.svg @@ -0,0 +1,4 @@ + +Memory (MB)2102102202202302302402402502502602602702702802802902903003003103103203203303303403403503503603600.0000.0000.0000.0005.0375.0375.0375.0375.03710.06710.06710.06710.06710.06715.09615.09615.09615.09615.09620.12620.12620.12620.12620.12625.15625.15625.15625.15625.15630.18630.18630.18630.18630.18635.21935.21935.21935.21935.21940.24840.24840.24840.24840.24845.27845.27845.27845.27845.27850.30850.30850.30850.30850.30855.33855.33855.33855.33855.33860.37060.37060.37060.37060.37065.40365.40365.40365.40365.40370.42170.42170.42170.42170.42175.45475.45475.45475.45475.45480.47380.47380.47380.47380.47385.49085.49085.49085.49085.49090.51390.51390.51390.51390.51395.54595.54595.54595.54595.545100.569100.569100.569100.569100.569105.587105.587105.587105.587105.587110.602110.602110.602110.602110.602115.619115.619115.619115.619115.619120.635120.635120.635120.635120.635125.655125.655125.655125.655125.655130.671130.671130.671130.671130.671135.688135.688135.688135.688135.688140.722140.722140.722140.722140.722145.738145.738145.738145.738145.738150.754150.754150.754150.754150.754155.771155.771155.771155.771155.771160.789160.789160.789160.789160.789165.819165.819165.819165.819165.819170.837170.837170.837170.837170.837175.853175.853175.853175.853175.853180.883180.883180.883180.883180.883185.913185.913185.913185.913185.913190.943190.943190.943190.943190.943195.974195.974195.974195.974195.974200.991200.991200.991200.991200.991200.991206.023206.023206.023206.023206.023211.054211.054211.054211.054211.054216.084216.084216.084216.084216.084221.115221.115221.115221.115221.115226.146226.146226.146226.146226.146231.176231.176231.176231.176231.176236.192236.192236.192236.192236.192241.221241.221241.221241.221241.221246.252246.252246.252246.252246.252251.282251.282251.282251.282251.282256.313256.313256.313256.313256.313261.343261.343261.343261.343261.343266.373266.373266.373266.373266.373271.403271.403271.403271.403271.403276.433276.433276.433276.433276.433281.464281.464281.464281.464281.464286.494286.494286.494286.494286.494291.525291.525291.525291.525291.525296.556296.556296.556296.556296.556301.586301.586301.586301.586301.586306.617306.617306.617306.617306.617311.647311.647311.647311.647311.647316.677316.677316.677316.677316.677321.708321.708321.708321.708321.708326.738326.738326.738326.738326.738331.768331.768331.768331.768331.768336.799336.799336.799336.799336.799341.830341.830341.830341.830341.830346.860346.860346.860346.860346.860351.891351.891351.891351.891351.891356.907356.907356.907356.907356.907361.937361.937361.937361.937361.937366.967366.967366.967366.967366.967371.998371.998371.998371.998371.998371.998377.039377.039377.039377.039377.039382.068382.068382.068382.068382.068387.098387.098387.098387.098387.098392.129392.129392.129392.129392.129397.160397.160397.160397.160397.160402.190402.190Memory (MB)time24414.284615384615384324.985235732010.00024416.061308840413314324.985235732010.00024417.83800229621125324.985235732010.00024419.614695752009183324.985235732010.00022721.391389207807116370.9864764267995.03722723.168082663605052370.9864764267995.03722724.94477611940298370.9864764267995.03722726.721469575200917370.9864764267995.03722728.49816303099885370.9864764267995.03722730.274856486796782370.98647642679910.06722732.05154994259471370.98647642679910.06722733.82824339839265370.98647642679910.06722735.604936854190576370.98647642679910.06722737.38163030998851370.98647642679910.06722639.15832376578644373.692431761786615.09622640.93501722158438373.692431761786615.09622642.711710677382314373.692431761786615.09622644.48840413318025373.692431761786615.09622646.26509758897818373.692431761786615.09622648.04179104477612373.692431761786620.12622649.81848450057405373.692431761786620.12622651.595177956371984373.692431761786620.12622653.371871412169924373.692431761786620.12622655.148564867967856373.692431761786620.12622756.92525832376578370.98647642679925.15622758.701951779563714370.98647642679925.15622760.47864523536165370.98647642679925.15622762.25533869115959370.98647642679925.15622764.03203214695752370.98647642679925.15622765.80872560275544370.98647642679930.18622767.58541905855337370.98647642679930.18622769.36211251435131370.98647642679930.18622771.13880597014924370.98647642679930.18622772.91549942594717370.98647642679930.18622774.69219288174511370.98647642679935.21922776.46888633754305370.98647642679935.21922778.24557979334098370.98647642679935.21922780.02227324913892370.98647642679935.21922781.79896670493686370.98647642679935.21922783.57566016073478370.98647642679940.24822785.35235361653272370.98647642679940.24822787.12904707233065370.98647642679940.24822788.90574052812859370.98647642679940.24822790.68243398392651370.98647642679940.24822792.45912743972444370.98647642679945.27822794.2358208955224370.98647642679945.27822796.01251435132032370.98647642679945.27822797.78920780711825370.98647642679945.27822799.56590126291619370.98647642679945.278226101.34259471871411373.692431761786650.308226103.11928817451205373.692431761786650.308226104.89598163030998373.692431761786650.308226106.6726750861079373.692431761786650.308226108.44936854190586373.692431761786650.308227110.22606199770378370.98647642679955.338227112.00275545350169370.98647642679955.338227113.77944890929965370.98647642679955.338227115.55614236509757370.98647642679955.338227117.33283582089551370.98647642679955.338228119.10952927669344368.280521091811460.370228120.88622273249136368.280521091811460.370228122.6629161882893368.280521091811460.370228124.43960964408723368.280521091811460.370228126.21630309988517368.280521091811460.370250127.9929965556831308.749503722084465.403250129.76969001148103308.749503722084465.403250131.546383467279308.749503722084465.403250133.32307692307688308.749503722084465.403250135.09977037887484308.749503722084465.403228136.87646383467276368.280521091811470.421228138.65315729047072368.280521091811470.421228140.42985074626864368.280521091811470.421228142.20654420206657368.280521091811470.421228143.98323765786452368.280521091811470.421228145.75993111366242368.280521091811475.454228147.5366245694604368.280521091811475.454228149.3133180252583368.280521091811475.454228151.09001148105625368.280521091811475.454228152.86670493685418368.280521091811475.454229154.6433983926521365.5745657568238680.473229156.42009184845003365.5745657568238680.473229158.19678530424798365.5745657568238680.473229159.97347876004588365.5745657568238680.473229161.75017221584386365.5745657568238680.473228163.52686567164176368.280521091811485.490228165.3035591274397368.280521091811485.490228167.08025258323764368.280521091811485.490228168.85694603903556368.280521091811485.490228170.6336394948335368.280521091811485.490307172.41033295063144154.510049627791690.513307174.18702640642937154.510049627791690.513307175.96371986222732154.510049627791690.513307177.74041331802525154.510049627791690.513307179.5171067738232154.510049627791690.513336181.293800229621176.0373449131514695.545336183.0704936854190576.0373449131514695.545336184.8471871412169576.0373449131514695.545336186.6238805970149376.0373449131514695.545336188.4005740528128676.0373449131514695.545334190.1772675086107881.44925558312661100.569334191.953960964408781.44925558312661100.569334193.730654420206781.44925558312661100.569334195.507347876004681.44925558312661100.569334197.2840413318025481.44925558312661100.569335199.0607347876004478.74330024813901105.587335200.8374282433983678.74330024813901105.587335202.6141216991963278.74330024813901105.587335204.3908151549942778.74330024813901105.587335206.1675086107921778.74330024813901105.587333207.9442020665901284.15521091811422110.602333209.7208955223880284.15521091811422110.602333211.49758897818684.15521091811422110.602333213.2742824339839384.15521091811422110.602333215.0509758897818584.15521091811422110.602334216.8276693455797881.44925558312661115.619334218.604362801377781.44925558312661115.619334220.3810562571756681.44925558312661115.619334222.1577497129735881.44925558312661115.619334223.934443168771581.44925558312661115.619335225.7111366245694378.74330024813901120.635335227.4878300803673678.74330024813901120.635335229.2645235361653478.74330024813901120.635335231.0412169919632478.74330024813901120.635335232.817910447761278.74330024813901120.635335234.594603903559178.74330024813901125.655335236.3712973593570478.74330024813901125.655335238.14799081515578.74330024813901125.655335239.9246842709529278.74330024813901125.655335241.7013777267508578.74330024813901125.655335243.4780711825487778.74330024813901130.671335245.2547646383467378.74330024813901130.671335247.0314580941446878.74330024813901130.671335248.8081515499425878.74330024813901130.671335250.584845005740578.74330024813901130.671336252.361538461538476.03734491315146135.688336254.1382319173363876.03734491315146135.688336255.9149253731343476.03734491315146135.688336257.6916188289322376.03734491315146135.688336259.468312284730276.03734491315146135.688335261.245005740528178.74330024813901140.722335263.0216991963260478.74330024813901140.722335264.79839265212478.74330024813901140.722335266.5750861079219578.74330024813901140.722335268.3517795637198478.74330024813901140.722335270.1284730195177478.74330024813901145.738335271.905166475315778.74330024813901145.738335273.6818599311136578.74330024813901145.738335275.458553386911678.74330024813901145.738335277.235246842709578.74330024813901145.738333279.0119402985074584.15521091811422150.754333280.788633754305484.15521091811422150.754333282.565327210103384.15521091811422150.754333284.3420206659012684.15521091811422150.754333286.118714121699284.15521091811422150.754334287.895407577497181.44925558312661155.771334289.6721010332950681.44925558312661155.771334291.4487944890929681.44925558312661155.771334293.225487944890981.44925558312661155.771334295.0021814006888781.44925558312661155.771335296.7788748564867778.74330024813901160.789335298.555568312284778.74330024813901160.789335300.332261768082778.74330024813901160.789335302.1089552238805778.74330024813901160.789335303.885648679678578.74330024813901160.789359305.662342135476413.800372208436784165.819359307.4390355912744313.800372208436784165.819359309.2157290470723313.800372208436784165.819359310.992422502870213.800372208436784165.819359312.769115958668113.800372208436784165.819359314.5458094144661313.800372208436784170.837359316.322502870264113.800372208436784170.837359318.09919632606213.800372208436784170.837359319.875889781859913.800372208436784170.837359321.6525832376578413.800372208436784170.837358323.429276693455816.50632754342439175.853358325.2059701492537416.50632754342439175.853358326.9826636050516416.50632754342439175.853358328.759357060849616.50632754342439175.853358330.536050516647516.50632754342439175.853360332.3127439724454511.094416873449234180.883360334.0894374282433411.094416873449234180.883360335.8661308840413511.094416873449234180.883360337.6428243398392511.094416873449234180.883360339.4195177956371511.094416873449234180.883360341.196211251435111.094416873449234185.913360342.9729047072330611.094416873449234185.913360344.74959816303111.094416873449234185.913360346.526291618828911.094416873449234185.913360348.302985074626811.094416873449234185.913360350.079678530424811.094416873449234190.943360351.856371986222711.094416873449234190.943360353.6330654420206711.094416873449234190.943360355.4097588978185611.094416873449234190.943360357.186452353616511.094416873449234190.943361358.963145809414478.38846153846157195.974361360.73983926521238.38846153846157195.974361362.516532721010268.38846153846157195.974361364.29322617680828.38846153846157195.974361366.06991963260628.38846153846157195.974355367.846613088404124.62419354838721200.991355369.6233065442019724.62419354838721200.991355371.424.62419354838721200.991355373.1766934557979324.62419354838721200.991355374.953386911595824.62419354838721200.991355376.730080367393824.62419354838721200.991340378.506773823191765.21352357320103206.023340380.2834672789896365.21352357320103206.023340382.060160734787665.21352357320103206.023340383.836854190585565.21352357320103206.023340385.613547646383565.21352357320103206.023339387.3902411021813467.91947890818864211.054339389.166934557979367.91947890818864211.054339390.9436280137772467.91947890818864211.054339392.720321469575267.91947890818864211.054339394.4970149253731567.91947890818864211.054339396.27370838117167.91947890818864216.084339398.0504018369689467.91947890818864216.084339399.8270952927669667.91947890818864216.084339401.603788748564867.91947890818864216.084339403.3804822043627567.91947890818864216.084339405.157175660160767.91947890818864221.115339406.9338691159586667.91947890818864221.115339408.710562571756667.91947890818864221.115339410.4872560275544567.91947890818864221.115339412.2639494833524667.91947890818864221.115338414.0406429391503670.62543424317624226.146338415.817336394948370.62543424317624226.146338417.5940298507462770.62543424317624226.146338419.3707233065441670.62543424317624226.146338421.147416762342170.62543424317624226.146339422.9241102181467.91947890818864231.176339424.7008036739379767.91947890818864231.176339426.47749712973667.91947890818864231.176339428.254190585533867.91947890818864231.176339430.030884041331867.91947890818864231.176339431.8075774971296767.91947890818864236.192339433.584270952927767.91947890818864236.192339435.3609644087256467.91947890818864236.192339437.137657864523567.91947890818864236.192339438.9143513203214367.91947890818864236.192339440.691044776119467.91947890818864241.221339442.4677382319173467.91947890818864241.221339444.2444316877152367.91947890818864241.221339446.0211251435131367.91947890818864241.221339447.7978185993111467.91947890818864241.221338449.57451205510970.62543424317624246.252338451.3512055109069470.62543424317624246.252338453.127898966704970.62543424317624246.252338454.9045924225028470.62543424317624246.252338456.681285878300870.62543424317624246.252338458.4579793340986470.62543424317624251.282338460.234672789896670.62543424317624251.282338462.011366245694670.62543424317624251.282338463.788059701492570.62543424317624251.282338465.5647531572904570.62543424317624251.282339467.341446613088467.91947890818864256.313339469.118140068886367.91947890818864256.313339470.8948335246842667.91947890818864256.313339472.6715269804821667.91947890818864256.313339474.448220436280167.91947890818864256.313339476.224913892078167.91947890818864261.343339478.0016073478759667.91947890818864261.343339479.778300803673967.91947890818864261.343339481.554994259471867.91947890818864261.343339483.331687715269867.91947890818864261.343339485.108381171067867.91947890818864266.373339486.885074626865667.91947890818864266.373339488.6617680826635767.91947890818864266.373339490.4384615384614767.91947890818864266.373339492.215154994259467.91947890818864266.373338493.991848450057470.62543424317624271.403338495.768541905855270.62543424317624271.403338497.545235361653270.62543424317624271.403338499.321928817451270.62543424317624271.403338501.0986222732491370.62543424317624271.403339502.875315729047167.91947890818864276.433339504.65200918484567.91947890818864276.433339506.4287026406429467.91947890818864276.433339508.205396096440867.91947890818864276.433339509.9820895522387367.91947890818864276.433339511.7587830080367467.91947890818864281.464339513.535476463834667.91947890818864281.464339515.312169919632567.91947890818864281.464339517.088863375430567.91947890818864281.464339518.865556831228467.91947890818864281.464339520.642250287026467.91947890818864286.494339522.418943742824467.91947890818864286.494339524.195637198622367.91947890818864286.494339525.972330654420167.91947890818864286.494339527.749024110218167.91947890818864286.494339529.52571756601667.91947890818864291.525339531.302411021813967.91947890818864291.525339533.079104477611867.91947890818864291.525339534.855797933409867.91947890818864291.525339536.632491389207867.91947890818864291.525339538.409184845005767.91947890818864296.556339540.185878300803767.91947890818864296.556339541.962571756601667.91947890818864296.556339543.739265212399567.91947890818864296.556339545.515958668197467.91947890818864296.556338547.292652123995470.62543424317624301.586338549.069345579793370.62543424317624301.586338550.846039035591370.62543424317624301.586338552.622732491389170.62543424317624301.586338554.399425947187170.62543424317624301.586338556.17611940298570.62543424317624306.617338557.95281285878370.62543424317624306.617338559.729506314580970.62543424317624306.617338561.506199770378870.62543424317624306.617338563.282893226176870.62543424317624306.617339565.059586681974867.91947890818864311.647339566.836280137772667.91947890818864311.647339568.612973593570667.91947890818864311.647339570.389667049368467.91947890818864311.647339572.166360505166467.91947890818864311.647339573.943053960964367.91947890818864316.677339575.719747416762367.91947890818864316.677339577.496440872560267.91947890818864316.677339579.273134328358267.91947890818864316.677339581.049827784156267.91947890818864316.677339582.826521239954167.91947890818864321.708339584.60321469575267.91947890818864321.708339586.379908151549967.91947890818864321.708339588.156601607347767.91947890818864321.708339589.933295063145767.91947890818864321.708339591.709988518943867.91947890818864326.738339593.486681974741667.91947890818864326.738339595.263375430539667.91947890818864326.738339597.040068886337567.91947890818864326.738339598.816762342135567.91947890818864326.738339600.593455797933467.91947890818864331.768339602.370149253731367.91947890818864331.768339604.146842709529267.91947890818864331.768339605.923536165327267.91947890818864331.768339607.700229621125167.91947890818864331.768338609.476923076923170.62543424317624336.799338611.253616532720970.62543424317624336.799338613.030309988518970.62543424317624336.799338614.807003444316870.62543424317624336.799338616.583696900114870.62543424317624336.799339618.360390355912767.91947890818864341.830339620.137083811710767.91947890818864341.830339621.913777267508667.91947890818864341.830339623.690470723306567.91947890818864341.830339625.467164179104467.91947890818864341.830227627.2438576349024370.986476426799346.860227629.0205510907002370.986476426799346.860227630.7972445464982370.986476426799346.860227632.5739380022961370.986476426799346.860227634.3506314580941370.986476426799346.860228636.127324913892368.2805210918114351.891228637.90401836969368.2805210918114351.891228639.680711825488368.2805210918114351.891228641.4574052812859368.2805210918114351.891228643.2340987370837368.2805210918114351.891228645.0107921928817368.2805210918114356.907228646.7874856486795368.2805210918114356.907228648.5641791044776368.2805210918114356.907228650.3408725602756368.2805210918114356.907228652.1175660160734368.2805210918114356.907227653.8942594718714370.986476426799361.937227655.6709529276693370.986476426799361.937227657.4476463834673370.986476426799361.937227659.2243398392652370.986476426799361.937227661.001033295063370.986476426799361.937228662.7777267508611368.2805210918114366.967228664.554420206659368.2805210918114366.967228666.3311136624569368.2805210918114366.967228668.1078071182549368.2805210918114366.967228669.8845005740527368.2805210918114366.967228671.6611940298507368.2805210918114371.998228673.4378874856485368.2805210918114371.998228675.2145809414466368.2805210918114371.998228676.9912743972445368.2805210918114371.998228678.7679678530425368.2805210918114371.998228680.5446613088404368.2805210918114371.998228682.3213547646383368.2805210918114377.039228684.0980482204362368.2805210918114377.039228685.8747416762342368.2805210918114377.039228687.651435132032368.2805210918114377.039228689.4281285878301368.2805210918114377.039228691.2048220436279368.2805210918114382.068228692.9815154994259368.2805210918114382.068228694.7582089552238368.2805210918114382.068228696.5349024110218368.2805210918114382.068228698.3115958668197368.2805210918114382.068227700.0882893226176370.986476426799387.098227701.8649827784155370.986476426799387.098227703.6416762342136370.986476426799387.098227705.4183696900114370.986476426799387.098227707.1950631458094370.986476426799387.098227708.9717566016072370.986476426799392.129227710.7484500574052370.986476426799392.129227712.5251435132031370.986476426799392.129227714.301836969001370.986476426799392.129227716.0785304247989370.986476426799392.129228717.855223880597368.2805210918114397.160228719.631917336395368.2805210918114397.160228721.4086107921929368.2805210918114397.160228723.1853042479906368.2805210918114397.160228724.9619977037886368.2805210918114397.160228726.7386911595866368.2805210918114402.190228728.5153846153845368.2805210918114402.19032414.284615384615384108.508808933002510.00032416.061308840413314108.508808933002510.00032417.83800229621125108.508808933002510.00032419.614695752009183108.508808933002510.00034221.39138920780711659.801612903225875.03734223.16808266360505259.801612903225875.03734224.9447761194029859.801612903225875.03734226.72146957520091759.801612903225875.03734228.4981630309988559.801612903225875.03734230.27485648679678259.8016129032258710.06734232.0515499425947159.8016129032258710.06734233.8282433983926559.8016129032258710.06734235.60493685419057659.8016129032258710.06734237.3816303099885159.8016129032258710.06734239.1583237657864459.8016129032258715.09634240.9350172215843859.8016129032258715.09634242.71171067738231459.8016129032258715.09634244.4884041331802559.8016129032258715.09634246.2650975889781859.8016129032258715.09634248.0417910447761259.8016129032258720.12634249.8184845005740559.8016129032258720.12634251.59517795637198459.8016129032258720.12634253.37187141216992459.8016129032258720.12634255.14856486796785659.8016129032258720.12634256.9252583237657859.8016129032258725.15634258.70195177956371459.8016129032258725.15634260.4786452353616559.8016129032258725.15634262.2553386911595959.8016129032258725.15634264.0320321469575259.8016129032258725.15634265.8087256027554459.8016129032258730.18634267.5854190585533759.8016129032258730.18634269.3621125143513159.8016129032258730.18634271.1388059701492459.8016129032258730.18634272.9154994259471759.8016129032258730.18634174.6921928817451162.5075682382134835.21934176.4688863375430562.5075682382134835.21934178.2455797933409862.5075682382134835.21934180.0222732491389262.5075682382134835.21934181.7989667049368662.5075682382134835.21934183.5756601607347862.5075682382134840.24834185.3523536165327262.5075682382134840.24834187.1290470723306562.5075682382134840.24834188.9057405281285962.5075682382134840.24834190.6824339839265162.5075682382134840.24834292.4591274397244459.8016129032258745.27834294.235820895522459.8016129032258745.27834296.0125143513203259.8016129032258745.27834297.7892078071182559.8016129032258745.27834299.5659012629161959.8016129032258745.278342101.3425947187141159.8016129032258750.308342103.1192881745120559.8016129032258750.308342104.8959816303099859.8016129032258750.308342106.672675086107959.8016129032258750.308342108.4493685419058659.8016129032258750.308342110.2260619977037859.8016129032258755.338342112.0027554535016959.8016129032258755.338342113.7794489092996559.8016129032258755.338342115.5561423650975759.8016129032258755.338342117.3328358208955159.8016129032258755.338340119.1095292766934465.2135235732010360.370340120.8862227324913665.2135235732010360.370340122.662916188289365.2135235732010360.370340124.4396096440872365.2135235732010360.370340126.2163030998851765.2135235732010360.370318127.9929965556831124.744540942928165.403318129.76969001148103124.744540942928165.403318131.546383467279124.744540942928165.403318133.32307692307688124.744540942928165.403318135.09977037887484124.744540942928165.403341136.8764638346727662.5075682382134870.421341138.6531572904707262.5075682382134870.421341140.4298507462686462.5075682382134870.421341142.2065442020665762.5075682382134870.421341143.9832376578645262.5075682382134870.421340145.7599311136624265.2135235732010375.454340147.536624569460465.2135235732010375.454340149.313318025258365.2135235732010375.454340151.0900114810562565.2135235732010375.454340152.8667049368541865.2135235732010375.454339154.643398392652167.9194789081886480.473339156.4200918484500367.9194789081886480.473339158.1967853042479867.9194789081886480.473339159.9734787600458867.9194789081886480.473339161.7501722158438667.9194789081886480.473340163.5268656716417665.2135235732010385.490340165.303559127439765.2135235732010385.490340167.0802525832376465.2135235732010385.490340168.8569460390355665.2135235732010385.490340170.633639494833565.2135235732010385.490261172.41033295063144278.983995037220990.513261174.18702640642937278.983995037220990.513261175.96371986222732278.983995037220990.513261177.74041331802525278.983995037220990.513261179.5171067738232278.983995037220990.513232181.2938002296211357.4566997518610495.545232183.07049368541905357.4566997518610495.545232184.84718714121695357.4566997518610495.545232186.62388059701493357.4566997518610495.545232188.40057405281286357.4566997518610495.545234190.17726750861078352.0447890818859100.569234191.9539609644087352.0447890818859100.569234193.7306544202067352.0447890818859100.569234195.5073478760046352.0447890818859100.569234197.28404133180254352.0447890818859100.569233199.06073478760044354.75074441687343105.587233200.83742824339836354.75074441687343105.587233202.61412169919632354.75074441687343105.587233204.39081515499427354.75074441687343105.587233206.16750861079217354.75074441687343105.587235207.94420206659012349.3388337468983110.602235209.72089552238802349.3388337468983110.602235211.497588978186349.3388337468983110.602235213.27428243398393349.3388337468983110.602235215.05097588978185349.3388337468983110.602234216.82766934557978352.0447890818859115.619234218.6043628013777352.0447890818859115.619234220.38105625717566352.0447890818859115.619234222.15774971297358352.0447890818859115.619234223.9344431687715352.0447890818859115.619233225.71113662456943354.75074441687343120.635233227.48783008036736354.75074441687343120.635233229.26452353616534354.75074441687343120.635233231.04121699196324354.75074441687343120.635233232.8179104477612354.75074441687343120.635233234.5946039035591354.75074441687343125.655233236.37129735935704354.75074441687343125.655233238.147990815155354.75074441687343125.655233239.92468427095292354.75074441687343125.655233241.70137772675085354.75074441687343125.655232243.47807118254877357.45669975186104130.671232245.25476463834673357.45669975186104130.671232247.03145809414468357.45669975186104130.671232248.80815154994258357.45669975186104130.671232250.5848450057405357.45669975186104130.671232252.3615384615384357.45669975186104135.688232254.13823191733638357.45669975186104135.688232255.91492537313434357.45669975186104135.688232257.69161882893223357.45669975186104135.688232259.4683122847302357.45669975186104135.688233261.2450057405281354.75074441687343140.722233263.02169919632604354.75074441687343140.722233264.798392652124354.75074441687343140.722233266.57508610792195354.75074441687343140.722233268.35177956371984354.75074441687343140.722232270.12847301951774357.45669975186104145.738232271.9051664753157357.45669975186104145.738232273.68185993111365357.45669975186104145.738232275.4585533869116357.45669975186104145.738232277.2352468427095357.45669975186104145.738234279.01194029850745352.0447890818859150.754234280.7886337543054352.0447890818859150.754234282.5653272101033352.0447890818859150.754234284.34202066590126352.0447890818859150.754234286.1187141216992352.0447890818859150.754234287.8954075774971352.0447890818859155.771234289.67210103329506352.0447890818859155.771234291.44879448909296352.0447890818859155.771234293.2254879448909352.0447890818859155.771234295.00218140068887352.0447890818859155.771232296.77887485648677357.45669975186104160.789232298.5555683122847357.45669975186104160.789232300.3322617680827357.45669975186104160.789232302.10895522388057357.45669975186104160.789232303.8856486796785357.45669975186104160.789208305.6623421354764422.39962779156326165.819208307.43903559127443422.39962779156326165.819208309.21572904707233422.39962779156326165.819208310.9924225028702422.39962779156326165.819208312.7691159586681422.39962779156326165.819208314.54580941446613422.39962779156326170.837208316.3225028702641422.39962779156326170.837208318.099196326062422.39962779156326170.837208319.8758897818599422.39962779156326170.837208321.65258323765784422.39962779156326170.837209323.4292766934558419.6936724565757175.853209325.20597014925374419.6936724565757175.853209326.98266360505164419.6936724565757175.853209328.7593570608496419.6936724565757175.853209330.5360505166475419.6936724565757175.853207332.31274397244545425.10558312655087180.883207334.08943742824334425.10558312655087180.883207335.86613088404135425.10558312655087180.883207337.64282433983925425.10558312655087180.883207339.41951779563715425.10558312655087180.883207341.1962112514351425.10558312655087185.913207342.97290470723306425.10558312655087185.913207344.749598163031425.10558312655087185.913207346.5262916188289425.10558312655087185.913207348.3029850746268425.10558312655087185.913206350.0796785304248427.8115384615385190.943206351.8563719862227427.8115384615385190.943206353.63306544202067427.8115384615385190.943206355.40975889781856427.8115384615385190.943206357.1864523536165427.8115384615385190.943206358.96314580941447427.8115384615385195.974206360.7398392652123427.8115384615385195.974206362.51653272101026427.8115384615385195.974206364.2932261768082427.8115384615385195.974206366.0699196326062427.8115384615385195.974211367.8466130884041414.2817617866005200.991211369.62330654420197414.2817617866005200.991211371.4414.2817617866005200.991211373.17669345579793414.2817617866005200.991211374.9533869115958414.2817617866005200.991211376.7300803673938414.2817617866005200.991226378.5067738231917373.6924317617866206.023226380.28346727898963373.6924317617866206.023226382.0601607347876373.6924317617866206.023226383.8368541905855373.6924317617866206.023226385.6135476463835373.6924317617866206.023228387.39024110218134368.2805210918114211.054228389.1669345579793368.2805210918114211.054228390.94362801377724368.2805210918114211.054228392.7203214695752368.2805210918114211.054228394.49701492537315368.2805210918114211.054228396.273708381171368.2805210918114216.084228398.05040183696894368.2805210918114216.084228399.82709529276696368.2805210918114216.084228401.6037887485648368.2805210918114216.084228403.38048220436275368.2805210918114216.084228405.1571756601607368.2805210918114221.115228406.93386911595866368.2805210918114221.115228408.7105625717566368.2805210918114221.115228410.48725602755445368.2805210918114221.115228412.26394948335246368.2805210918114221.115228414.04064293915036368.2805210918114226.146228415.8173363949483368.2805210918114226.146228417.59402985074627368.2805210918114226.146228419.37072330654416368.2805210918114226.146228421.1474167623421368.2805210918114226.146228422.92411021814368.2805210918114231.176228424.70080367393797368.2805210918114231.176228426.477497129736368.2805210918114231.176228428.2541905855338368.2805210918114231.176228430.0308840413318368.2805210918114231.176228431.80757749712967368.2805210918114236.192228433.5842709529277368.2805210918114236.192228435.36096440872564368.2805210918114236.192228437.1376578645235368.2805210918114236.192228438.91435132032143368.2805210918114236.192228440.6910447761194368.2805210918114241.221228442.46773823191734368.2805210918114241.221228444.24443168771523368.2805210918114241.221228446.02112514351313368.2805210918114241.221228447.79781859931114368.2805210918114241.221228449.574512055109368.2805210918114246.252228451.35120551090694368.2805210918114246.252228453.1278989667049368.2805210918114246.252228454.90459242250284368.2805210918114246.252228456.6812858783008368.2805210918114246.252228458.45797933409864368.2805210918114251.282228460.2346727898966368.2805210918114251.282228462.0113662456946368.2805210918114251.282228463.7880597014925368.2805210918114251.282228465.56475315729045368.2805210918114251.282227467.3414466130884370.986476426799256.313227469.1181400688863370.986476426799256.313227470.89483352468426370.986476426799256.313227472.67152698048216370.986476426799256.313227474.4482204362801370.986476426799256.313227476.2249138920781370.986476426799261.343227478.00160734787596370.986476426799261.343227479.7783008036739370.986476426799261.343227481.5549942594718370.986476426799261.343227483.3316877152698370.986476426799261.343228485.1083811710678368.2805210918114266.373228486.8850746268656368.2805210918114266.373228488.66176808266357368.2805210918114266.373228490.43846153846147368.2805210918114266.373228492.2151549942594368.2805210918114266.373228493.9918484500574368.2805210918114271.403228495.7685419058552368.2805210918114271.403228497.5452353616532368.2805210918114271.403228499.3219288174512368.2805210918114271.403228501.09862227324913368.2805210918114271.403227502.8753157290471370.986476426799276.433227504.652009184845370.986476426799276.433227506.42870264064294370.986476426799276.433227508.2053960964408370.986476426799276.433227509.98208955223873370.986476426799276.433227511.75878300803674370.986476426799281.464227513.5354764638346370.986476426799281.464227515.3121699196325370.986476426799281.464227517.0888633754305370.986476426799281.464227518.8655568312284370.986476426799281.464227520.6422502870264370.986476426799286.494227522.4189437428244370.986476426799286.494227524.1956371986223370.986476426799286.494227525.9723306544201370.986476426799286.494227527.7490241102181370.986476426799286.494228529.525717566016368.2805210918114291.525228531.3024110218139368.2805210918114291.525228533.0791044776118368.2805210918114291.525228534.8557979334098368.2805210918114291.525228536.6324913892078368.2805210918114291.525227538.4091848450057370.986476426799296.556227540.1858783008037370.986476426799296.556227541.9625717566016370.986476426799296.556227543.7392652123995370.986476426799296.556227545.5159586681974370.986476426799296.556228547.2926521239954368.2805210918114301.586228549.0693455797933368.2805210918114301.586228550.8460390355913368.2805210918114301.586228552.6227324913891368.2805210918114301.586228554.3994259471871368.2805210918114301.586228556.176119402985368.2805210918114306.617228557.952812858783368.2805210918114306.617228559.7295063145809368.2805210918114306.617228561.5061997703788368.2805210918114306.617228563.2828932261768368.2805210918114306.617227565.0595866819748370.986476426799311.647227566.8362801377726370.986476426799311.647227568.6129735935706370.986476426799311.647227570.3896670493684370.986476426799311.647227572.1663605051664370.986476426799311.647227573.9430539609643370.986476426799316.677227575.7197474167623370.986476426799316.677227577.4964408725602370.986476426799316.677227579.2731343283582370.986476426799316.677227581.0498277841562370.986476426799316.677227582.8265212399541370.986476426799321.708227584.603214695752370.986476426799321.708227586.3799081515499370.986476426799321.708227588.1566016073477370.986476426799321.708227589.9332950631457370.986476426799321.708227591.7099885189438370.986476426799326.738227593.4866819747416370.986476426799326.738227595.2633754305396370.986476426799326.738227597.0400688863375370.986476426799326.738227598.8167623421355370.986476426799326.738227600.5934557979334370.986476426799331.768227602.3701492537313370.986476426799331.768227604.1468427095292370.986476426799331.768227605.9235361653272370.986476426799331.768227607.7002296211251370.986476426799331.768227609.4769230769231370.986476426799336.799227611.2536165327209370.986476426799336.799227613.0303099885189370.986476426799336.799227614.8070034443168370.986476426799336.799227616.5836969001148370.986476426799336.799227618.3603903559127370.986476426799341.830227620.1370838117107370.986476426799341.830227621.9137772675086370.986476426799341.830227623.6904707233065370.986476426799341.830227625.4671641791044370.986476426799341.830339627.243857634902467.91947890818864346.860339629.020551090700267.91947890818864346.860339630.797244546498267.91947890818864346.860339632.573938002296167.91947890818864346.860339634.350631458094167.91947890818864346.860338636.12732491389270.62543424317624351.891338637.9040183696970.62543424317624351.891338639.68071182548870.62543424317624351.891338641.457405281285970.62543424317624351.891338643.234098737083770.62543424317624351.891338645.010792192881770.62543424317624356.907338646.787485648679570.62543424317624356.907338648.564179104477670.62543424317624356.907338650.340872560275670.62543424317624356.907338652.117566016073470.62543424317624356.907338653.894259471871470.62543424317624361.937338655.670952927669370.62543424317624361.937338657.447646383467370.62543424317624361.937338659.224339839265270.62543424317624361.937338661.00103329506370.62543424317624361.937338662.777726750861170.62543424317624366.967338664.55442020665970.62543424317624366.967338666.331113662456970.62543424317624366.967338668.107807118254970.62543424317624366.967338669.884500574052770.62543424317624366.967338671.661194029850770.62543424317624371.998338673.437887485648570.62543424317624371.998338675.214580941446670.62543424317624371.998338676.991274397244570.62543424317624371.998338678.767967853042570.62543424317624371.998338680.544661308840470.62543424317624371.998338682.321354764638370.62543424317624377.039338684.098048220436270.62543424317624377.039338685.874741676234270.62543424317624377.039338687.65143513203270.62543424317624377.039338689.428128587830170.62543424317624377.039338691.204822043627970.62543424317624382.068338692.981515499425970.62543424317624382.068338694.758208955223870.62543424317624382.068338696.534902411021870.62543424317624382.068338698.311595866819770.62543424317624382.068338700.088289322617670.62543424317624387.098338701.864982778415570.62543424317624387.098338703.641676234213670.62543424317624387.098338705.418369690011470.62543424317624387.098338707.195063145809470.62543424317624387.098338708.971756601607270.62543424317624392.129338710.748450057405270.62543424317624392.129338712.525143513203170.62543424317624392.129338714.30183696900170.62543424317624392.129338716.078530424798970.62543424317624392.129338717.85522388059770.62543424317624397.160338719.63191733639570.62543424317624397.160338721.408610792192970.62543424317624397.160338723.185304247990670.62543424317624397.160338724.961997703788670.62543424317624397.160338726.738691159586670.62543424317624402.190338728.515384615384570.62543424317624402.190Used MemoryFree Memory \ No newline at end of file