[
  {
    "path": ".github/FUNDING.yml",
    "content": "# These are supported funding model platforms\n\ngithub: #'wzpan'\npatreon: # Replace with a single Patreon username\nopen_collective: wukong-robot\nko_fi: # Replace with a single Ko-fi username\ntidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel\ncommunity_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry\nliberapay: # Replace with a single Liberapay username\nissuehunt: # Replace with a single IssueHunt username\notechie: # Replace with a single Otechie username\ncustom: ['https://wukong.hahack.com/#/donate']\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/----.md",
    "content": "---\nname: 使用求助\nabout: 使用遇到问题，请求帮助\ntitle: ''\nlabels: operation problem\nassignees: wzpan\n\n---\n\n**确认已寻找过答案**\n\n我已确认在 [Github issue](https://github.com/wzpan/wukong-robot/issues) 页、[常见问题](https://github.com/wzpan/wukong-robot/wiki/troubleshooting)页、[文档](http://wukong.hahack.com) 中都查找过，没有找到类似问题和资料。我也没有 google / bing/ 百度 / duckduckgo 到相关解答。\n\n**安装方式**\n\n手动安装/docker安装\n\n**操作系统**\n\n（例如 Raspbian Stretch、Ubuntu 16.04）\n\n**离线唤醒相关**\n\n如果是离线唤醒相关的问题，是否已确保 `arecord temp.wav`、`aplay temp.wav` (Linux) 或 `rec temp.wav`、`play temp.wav` （Mac）已正常工作？（注意要求不能带任何其他参数）如果不能，请先配置好麦克风和音响再尝试。\n\n—— 我已确保录音、播放都正常工作才尝试 wukong-robot 。\n\n**问题描述**\n\n具体说明下问题\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug---.md",
    "content": "---\nname: Bug 反馈\nabout: 反馈一个bug，帮助改进 wukong-robot\ntitle: ''\nlabels: bug\nassignees: wzpan\n\n---\n\n**确认已寻找过答案**\n\n我已确认在 [Github issue](https://github.com/wzpan/wukong-robot/issues) 页、[常见问题](https://github.com/wzpan/wukong-robot/wiki/troubleshooting)页、[文档](http://wukong.hahack.com) 中都查找过，没有找到类似问题和资料。我也没有 google / bing/ 百度 / duckduckgo 到相关解答。\n\n**安装方式**\n\n手动安装/docker安装\n\n**操作系统**\n\n（例如 Raspbian Stretch、Ubuntu 16.04）\n\n**离线唤醒相关**\n\n如果是离线唤醒相关的问题，是否已确保 `arecord temp.wav`、`aplay temp.wav` (Linux) 或 `rec temp.wav`、`play temp.wav` （Mac）已正常工作？（注意要求不能带任何其他参数）如果不能，请先配置好麦克风和音响再尝试。\n\n—— 我已确保录音、播放都正常工作才尝试 wukong-robot 。\n\n**问题描述**\n\n具体说明下问题\n\n**复现步骤**\n\n具体描述下复现步骤\n"
  },
  {
    "path": ".github/stale.yml",
    "content": "# Number of days of inactivity before an issue becomes stale\ndaysUntilStale: 7\n# Number of days of inactivity before a stale issue is closed\ndaysUntilClose: 3\n# Issues with these labels will never be considered stale\nexemptLabels:\n  - pinned\n  - security\n  - bug\n# Label to use when marking an issue as stale\nstaleLabel: wontfix\n# Comment to post when marking an issue as stale. Set to `false` to disable\nmarkComment: >\n  由于久无进展，这个 issue 已被标为过期。如果还没有后续进展，这个 issue 将被关闭。谢谢你的反馈！\n# Comment to post when closing a stale issue. Set to `false` to disable\ncloseComment: false\n"
  },
  {
    "path": ".github/workflows/dockerimage.yml",
    "content": "name: Docker Image CI\n\non:\n  push:\n    branches:\n    - master\n\njobs:\n\n  build:\n \n    runs-on: ubuntu-latest\n \n    steps:\n    - uses: actions/checkout@master\n    - name: Publish to Docker Hub Registry\n      uses: elgohr/Publish-Docker-Github-Action@master\n      with:\n        name: wzpan/wukong-robot\n        username: ${{ secrets.DOCKER_GITHUB_USERNAME }}\n        password: ${{ secrets.DOCKER_PASSWORD }}\n        dockerfile: docker/Dockerfile\n    - name: Publish to Github Package Registry\n      uses: elgohr/Publish-Docker-Github-Action@master\n      with:\n        name: docker.pkg.github.com/wzpan/wukong-robot/wukong\n        username: ${{ secrets.DOCKER_GITHUB_USERNAME }}\n        password: ${{ secrets.DOCKER_GITHUB_PASSWORD }}\n        registry: docker.pkg.github.com\n        dockerfile: docker/Dockerfile    \n\n\n"
  },
  {
    "path": ".gitignore",
    "content": "# Generic files to ignore\n*~\n*.lock\n*.DS_Store\n*.swp\n*.out\n\n# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n\n# C extensions\n*.so\n\n# Distribution / packaging\n.Python\nenv/\nbuild/\ndevelop-eggs/\ndist/\ndownloads/\neggs/\nlib/\nlib64/\nparts/\nsdist/\nvar/\n*.egg-info/\n.installed.cfg\n*.egg\n\n# PyInstaller\n#  Usually these files are written by a python script from a template\n#  before PyInstaller builds the exe, so as to inject date/other infos into it.\n*.manifest\n*.spec\n\n# Installer logs\npip-log.txt\npip-delete-this-directory.txt\n\n# Unit test / coverage reports\nhtmlcov/\n.tox/\n.coverage\n.cache\nnosetests.xml\ncoverage.xml\n\n# Translations\n*.mo\n*.pot\n\n# Django stuff/Logfiles\n*.log\n\n# Sphinx documentation\ndocs/_build/\n\n# PyBuilder\ntarget/\n\n# Coverage reports for a specific version\n.coverage\n\n# SublimeLinter config file\n.sublimelinterrc\n\n# temp folder\ntemp/*\n\n# temp file\n#*.*#\n#*#\n\\#*#\n*~\n.#*.*\n\n# NetEase music account info\nuserInfo\n\n# wget log\nwget-log*\n\n# some thirdparty libs\nclient/mic_array\nlogin/wxqr.png\n.idea/\nsftp-config.json\n__pycache__\n\n"
  },
  {
    "path": ".travis.yml",
    "content": "env:\n    - ARCH=x86\nlanguage: python\nsudo: false\npython:\n    - \"3.5\"\ncache:\n  directories:\n    - \"$HOME/.pip-cache/\"\n    - \"/home/travis/virtualenv/python3.8\"\ninstall: \n    - \"pip3 install pyflakes --cache-dir $HOME/.pip-cache\"\nscript:\n    - \"pyflakes .\"\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2016 - present Weizhou Pan\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# wukong-robot\n\n<p align=\"center\">\n  <a href=\"https://wukong.hahack.com\" target=\"_blank\">\n    <img width=\"128\" src=\"http://hahack-1253537070.file.myqcloud.com/images/wukong-icons/256_256.png\" alt=\"wukong-robot\">\n  </a>\n</p>\n\n<p align=\"center\">\n  wukong-robot 是一个简单、灵活、优雅的中文语音对话机器人/智能音箱项目，目的是让中国的 Maker 和 Haker 们也能快速打造个性化的智能音箱。wukong-robot 还可能是第一个开源的脑机唤醒智能音箱。  \n</p>\n<p align=\"center\">\n  截至 2023 年 3 月 31 日，wukong-robot 的安装设备数已超过 13,000 台，唤醒次数累积超过了 700,000 次。\n</p>\n\n<p align=\"center\">\n  <a href=\"https://github.com/users/wzpan/projects/2/views/1\"><img alt=\"wukong-project\" src=\"https://img.shields.io/badge/project-wukong-informational.svg?style=flat-square\"></a>\n  <a href=\"https://wukong.hahack.com/#/donate\"><img alt=\"捐赠\" src=\"https://img.shields.io/badge/%EF%BF%A5-donate-green.svg?style=flat-square\"></a>\n  <a href=\"#\"><img alt=\"Python3.7+\" src=\"https://img.shields.io/badge/Python->=3.7-blue.svg?style=flat-square\"></a>\n  <a href=\"https://hub.docker.com/r/wzpan/wukong-robot\"><img alt=\"docker-pulls\" src=\"https://img.shields.io/docker/pulls/wzpan/wukong-robot.svg?style=flat-square&colorB=success\"></a>\n  <a href=\"https://github1s.com/wzpan/wukong-robot\"><img alt=\"browse-code\" src=\"https://img.shields.io/badge/browse-code-purple.svg?style=flat-square\"></a>\n</p>\n\n<p align=\"center\">\n  <a href=\"https://opencollective.com/wukong-robot/contribute/tier/8131-sponsor\" target=\"_blank\"><img src=\"https://opencollective.com/wukong-robot/sponsors.svg?avatarHeight=36\"></a>\n</p>\n\n## Table of Contents\n\n* [特性](#特性)\n* [Demo](#demo)\n* [环境要求](#环境要求)\n* [安装](#安装)\n* [升级](#升级)\n* [运行](#运行)\n* [配置](#配置)\n* [技能插件](#插件)\n* [API接口](#api-接口)\n* [捐赠](#捐赠)\n* [贡献](#贡献)\n* [引用](#引用)\n* [联系](#联系)\n* [感谢](#感谢)\n* [FAQ](#faq)\n* [免责声明](#免责声明)\n\n## 特性\n\n<p align=\"center\">\n  <img src=\"https://wzpan-1253537070.cos.ap-guangzhou.myqcloud.com/wukong/wukong-robot-3.3.0.png\" alt=\"wukong-robot\">\n</p>\n\n* 模块化。功能插件、语音识别、语音合成、对话机器人都做到了高度模块化，第三方插件单独维护，方便继承和开发自己的插件。\n* 中文支持。集成百度、科大讯飞、阿里、腾讯、OpenAI Whisper、Apple、微软Edge、VITS声音克隆TTS 等多家中文语音识别和语音合成技术，且可以继续扩展。\n* 对话机器人支持。支持基于 [AnyQ](https://wukong.hahack.com/#/anyq) 的本地对话机器人，并支持接入图灵机器人、ChatGPT 等在线对话机器人。\n* 全局监听，离线唤醒。支持 [Porcupine](https://github.com/Picovoice/porcupine) 和 [snowboy](https://github.com/Kitt-AI/snowboy) 两套离线语音指令唤醒引擎，并支持 Muse [脑机唤醒](https://wukong.hahack.com/#/bci) 以及行空板摇一摇唤醒等其他唤醒方式。\n* 灵活可配置。支持定制机器人名字，支持选择语音识别和合成的插件。\n* 智能家居。支持和 [小爱音箱](https://wukong.hahack.com/#/linkage)、[Siri](https://wukong.hahack.com/#/linkage)、mqtt、[HomeAssistant](https://wukong.hahack.com/#/smarthome) 等智能家居协议联动，支持语音控制智能家电。\n* 后台配套支持。提供配套后台，可实现远程操控、修改配置和日志查看等功能。\n* 开放API。可利用后端开放的API，实现更丰富的功能。\n* 安装简单，支持更多平台。相比 dingdang-robot ，舍弃了 PocketSphinx 的离线唤醒方案，安装变得更加简单，代码量更少，更易于维护并且能在 Mac 以及更多 Linux 系统中运行。\n\nwukong-robot 的功能还在不断更新迭代中，详见 [更新说明](https://github.com/wzpan/wukong-robot/wiki/update-notes) 。\n\nwukong-robot 的工作模式：\n\n<p align=\"center\">\n  <img src=\"https://wzpan-1253537070.cos.ap-guangzhou.myqcloud.com/wukong/wukong-robot-workflow.png\" alt=\"wukong-robot 的工作模式\">\n</p>\n\nwukong-robot 被唤醒后，用户的语音指令先经过 ASR 引擎进行 ASR 识别成文本，然后对识别到的文本进行 NLU 解析，再将解析结果进行技能匹配，交给适合处理该指令的技能插件去处理。插件处理完成后，得到的结果再交给 TTS 引擎合成成语音，播放给用户。\n\n虽然一次交互可能包含多次网络请求，不过带来的好处是：每一个环节都可以被修改和定制。而且我认为，到了 5G 时代，音箱的响应速度将不再成为体验问题。可定制和个性化才是未来的主流，而届时 wukong-robot 将会是更好的选择！\n\n## Demo\n\n<p align=\"center\">\n  <img src=\"https://wzpan-1253537070.cos.ap-guangzhou.myqcloud.com/wukong/user-demo.jpg\" alt=\"demo\">\n</p>\n\n* Demo视频：\n  - [wukong-robot + ChatGPT 实现支持流式对话的智能音箱（一分半钟）](https://www.bilibili.com/video/BV1Bh411g7t2)\n  - [粉丝向定制版，演示对话+音乐+开放API+智能家居（五分钟）](https://www.bilibili.com/video/av50685517/)\n  - [使用脑机唤醒 wukong-robot](https://www.bilibili.com/video/av76739580/)\n  - [Google AIY Voice Kit + wukong-robot](https://www.bilibili.com/video/av81173082/)\n  - [Siri 联动 wukong-robot + ChatGPT](https://www.bilibili.com/video/BV1yY4y1y7oW)\n  - [小爱同学联动 wukong-robot](https://www.bilibili.com/video/BV1eg4y1b75Y)\n  - [教程：基于树莓派&wukong-robot&VITS的AI泠鸢开源智能音箱的初步实现（by @二维环状无限深势阱）](https://www.bilibili.com/video/BV1Sc411K7dv)\n  - [教程：实现一个虚拟管家：贾维斯(by @Echo）](https://zhuanlan.zhihu.com/p/655865035)\n* 后台管理端 Demo\n  - 体验地址：https://bot.hahack.com  （体验用户名：wukong；体验密码：wukong@2019）\n\n## 环境要求 ##\n\n### Python 版本 ###\n\nwukong-robot 只支持 Python >= 3.7 且 < 3.10 ，不支持 Python 2.x 。\n\n### 设备要求 ###\n\nwukong-robot 支持运行在以下的设备和系统中：\n\n* Intel Chip Mac (不支持 M1 芯片)\n* 64bit Ubuntu（12.04 and 14.04）\n* 全系列的树莓派（Raspbian 系统）\n* Pine 64 with Debian Jessie 8.5（3.10.102）\n* Intel Edison with Ubilinux （Debian Wheezy 7.8）\n* 装有 WSL（Windows Subsystem for Linux） 的 Windows\n\n## 安装 ##\n\n见 [wukong-robot 安装教程](https://wukong.hahack.com/#/install) 。\n\n## 升级\n\n``` bash\npython3 wukong.py update\n```\n\n如果提示升级失败，可以尝试在 wukong-robot 的根目录手动执行以下命令，看看问题出在哪。\n\n``` sh\ngit pull\npip3 install -r requirements.txt\n```\n\n## 运行 ##\n\n``` bash\npython3 wukong.py\n```\n\n建议在 [tmux](http://blog.jobbole.com/87278/) 或 supervisor 中执行。\n\n第一次启动时将提示你是否要到用户目录下创建一个配置文件，输入 `y` 即可。\n\n然后通过唤醒词 “snowboy” 唤醒 wukong-robot 进行交互（该唤醒词可自定义）。\n\n此外，wukong-robot 默认在运行期间还会启动一个后台管理端，提供了远程对话、查看修改配置、查看 log 等能力。\n\n- 默认地址：http://localhost:5001\n- 默认账户名：wukong\n- 默认密码：wukong@2019\n\n建议正式使用时修改用户名和密码，以免泄漏隐私。\n\n## 配置 ##\n\n参考[配置文件的注释](https://github.com/wzpan/wukong-robot/blob/master/static/default.yml)进行配置即可。注意不建议直接修改 default.yml 里的内容，否则会给后续通过 `git pull` 更新带来麻烦。你应该拷贝一份放到 `$HOME/.wukong/config.yml` 中，或者在运行的时候按照提示让 wukong-robot 为你完成这件事。\n\n> tips：不论使用哪个厂商的API，都建议注册并填上自己注册的应用信息，而不要用默认的配置。这是因为这些API都有使用频率和并发数限制，过多人同时使用会影响服务质量。\n\n## 技能插件 ##\n\n* [官方插件列表](https://wukong.hahack.com/#/official)\n* [用户贡献插件](https://wukong.hahack.com/#/contrib)\n\n## API 接口 ##\n\nwukong-robot 的后台接口是开放 Web API 的，可以使用 Restful 方式调用，见 [后台API](https://wukong.hahack.com/#/api)。\n\n## 捐赠\n\n您的捐赠将鼓励我继续完善 wukong-robot。\n\n* 对于个人用户，可以使用支付宝或者微信进行捐赠，单笔超过 100 元的捐赠者，您的 ID 将可以出现在 wukong-robot 后台管理端的捐赠页面中。\n\n \n| 支付宝 | 微信支付 |\n| ------ | --------- |\n| <img src=\"http://hahack.com/images/misc/alipay.png\" height=\"248px\" width=\"164px\" title=\"支付宝\" style=\"display:inherit;\"/> | <img src=\"http://hahack.com/images/misc/wechatpay.jpeg\" height=\"248px\" width=\"164px\" title=\"微信支付\" style=\"display:inherit;\"/> |\n\n如果以上的图裂了，可以下载图片（[支付宝](http://hahack.com/images/misc/alipay.png) | [微信](http://hahack.com/images/misc/wechatpay.jpeg)）到本地进行扫描。\n\n* 对于企业用户，建议[成为这个项目的 backer](https://opencollective.com/wukong-robot/contribute/tier/8131-sponsor)，您将可以把一个带链接的 logo 放在 wukong-robot 后台管理端的首页、捐赠页面以及 Github 项目首页中。\n\n<p>\n  <a href=\"https://opencollective.com/wukong-robot/sponsor/0/website\" target=\"_blank\"><img src=\"https://opencollective.com/wukong-robot/sponsor/0/avatar.svg\"></a>\n<a href=\"https://opencollective.com/wukong-robot/sponsor/1/website\" target=\"_blank\"><img src=\"https://opencollective.com/wukong-robot/sponsor/1/avatar.svg\"></a>\n<a href=\"https://opencollective.com/wukong-robot/sponsor/2/website\" target=\"_blank\"><img src=\"https://opencollective.com/wukong-robot/sponsor/2/avatar.svg\"></a>\n<a href=\"https://opencollective.com/wukong-robot/sponsor/3/website\" target=\"_blank\"><img src=\"https://opencollective.com/wukong-robot/sponsor/3/avatar.svg\"></a>\n<a href=\"https://opencollective.com/wukong-robot/sponsor/4/website\" target=\"_blank\"><img src=\"https://opencollective.com/wukong-robot/sponsor/4/avatar.svg\"></a>\n<a href=\"https://opencollective.com/wukong-robot/sponsor/5/website\" target=\"_blank\"><img src=\"https://opencollective.com/wukong-robot/sponsor/5/avatar.svg\"></a>\n<a href=\"https://opencollective.com/wukong-robot/sponsor/6/website\" target=\"_blank\"><img src=\"https://opencollective.com/wukong-robot/sponsor/6/avatar.svg\"></a>\n<a href=\"https://opencollective.com/wukong-robot/sponsor/7/website\" target=\"_blank\"><img src=\"https://opencollective.com/wukong-robot/sponsor/7/avatar.svg\"></a>\n<a href=\"https://opencollective.com/wukong-robot/sponsor/8/website\" target=\"_blank\"><img src=\"https://opencollective.com/wukong-robot/sponsor/8/avatar.svg\"></a>\n<a href=\"https://opencollective.com/wukong-robot/sponsor/9/website\" target=\"_blank\"><img src=\"https://opencollective.com/wukong-robot/sponsor/9/avatar.svg\"></a>\n</p>\n\n## 贡献\n\n* 喜欢本项目请先打一颗星；\n* 提 bug 请到 [issue 页面](https://github.com/wzpan/wukong-robot/issues)；\n* 要贡献代码，欢迎 fork 之后再提 pull request；\n* 插件请提交到 [wukong-contrib](https://github.com/wzpan/wukong-contrib) ；\n\n\n## 引用\n\n如果使用本项目的代码或插件，请引用本项目。\n\n```\n@misc{wukong-robot,\n  author = {潘伟洲},\n  title = {wukong-robot，一个简单、灵活、优雅的中文语音对话机器人/智能音箱项目},\n  year = {2019},\n  publisher = {GitHub},\n  journal = {GitHub repository},\n  howpublished = {\\url{https://github.com/wzpan/wukong-robot}},\n}\n```\n\n\n## 联系\n\n* wukong-robot 的主要开发者是 [潘伟洲](http://hahack.com) 。\n* QQ 频道（推荐）：\n\n使用 QQ 扫码加入：\n\n![](https://wzpan-1253537070.cos.ap-guangzhou.myqcloud.com/misc/wukong-guild-qrcode-256.png)\n\n* QQ 群：580447290（人数将满，为控制人数，需付费20元入群。微信或支付宝支付后，申请入群时贴上转账单号即可。**群收入的前一万元已无偿捐赠给[壹基金等公益项目](https://hahack-1253537070.cos.ap-chengdu.myqcloud.com/images/donate.png)**）。\n\n| 支付宝 | 微信支付 |\n| ------ | --------- |\n| <img src=\"http://hahack.com/images/misc/alipay.png\" height=\"248px\" width=\"164px\" title=\"支付宝\" style=\"display:inherit;\"/> | <img src=\"http://hahack.com/images/misc/wechatpay.jpeg\" height=\"248px\" width=\"164px\" title=\"微信支付\" style=\"display:inherit;\"/> |\n\n如果以上的图裂了，可以下载图片（[支付宝](http://hahack.com/images/misc/alipay.png) | [微信](http://hahack.com/images/misc/wechatpay.jpeg)）到本地进行扫描。\n\n## 感谢\n\n* 悟空的前身是 [dingdang-robot](https://github.com/dingdang-robot/dingdang-robot) 项目和 [jasper-client](https://github.com/jasperproject/jasper-client) 项目。感谢 [Shubhro Saha](http://www.shubhro.com/), [Charles Marsh](http://www.crmarsh.com/) and [Jan Holthuis](http://homepage.ruhr-uni-bochum.de/Jan.Holthuis/) 在 Jasper 项目上做出的优秀贡献；\n* 感谢三咲智子提供了备选的后台管理端 Demo 体验地址。\n* 感谢 aliciacai 贡献的 wukong-robot 图标。\n* 感谢所有为[本项目](https://github.com/wzpan/wukong-robot/graphs/contributors)、 [wukong-contrib](https://github.com/wzpan/wukong-contrib/graphs/contributors) 项目以及[dingdang-robot](https://github.com/dingdang-robot/dingdang-robot/graphs/contributors) 项目做出过贡献的人！\n\n## Star 历史\n\n[![Star History Chart](https://api.star-history.com/svg?repos=wzpan/wukong-robot&type=Date)](https://star-history.com/#wzpan/wukong-robot&Date)\n\n## 免责声明\n\n* wukong-robot 只用作个人学习研究，如因使用 wukong-robot 导致任何损失，本人概不负责。\n* 本开源项目与腾讯叮当助手及优必选悟空项目没有任何关系。\n"
  },
  {
    "path": "VERSION",
    "content": "3.5.3\n"
  },
  {
    "path": "docker/Dockerfile",
    "content": "# 使用官方 Python 3.8 基础镜像\nFROM python:3.8-slim\n\n# 设置工作目录\nWORKDIR /app\n\n# 安装依赖库\nRUN apt-get update && apt-get install -y \\\n    git \\\n    portaudio19-dev \\\n    python3-pyaudio \\\n    sox \\\n    pulseaudio \\\n    libsox-fmt-all \\\n    ffmpeg \\\n    wget \\\n    swig \\\n    libpcre3 \\\n    libpcre3-dev \\\n    libatlas-base-dev \\\n    build-essential \\\n    && rm -rf /var/lib/apt/lists/*\n\n# 克隆项目仓库\nRUN git clone https://github.com/wzpan/wukong-robot.git .\n\n# 安装 PyAudio\nRUN pip install pyaudio\n\n# 安装 Python 依赖\nRUN pip install --trusted-host pypi.python.org -r requirements.txt\n\n# 安装 wukong-contrib\nRUN mkdir -p $HOME/.wukong \\\n    && cd $HOME/.wukong \\\n    && git clone http://github.com/wzpan/wukong-contrib.git contrib \\\n    && pip install -r contrib/requirements.txt\n\n# 下载并编译 snowboy\nRUN wget https://wzpan-1253537070.cos.ap-guangzhou.myqcloud.com/misc/snowboy.tar.bz2 \\\n    && tar -xvjf snowboy.tar.bz2 \\\n    && cd snowboy/swig/Python3 \\\n    && make \\\n    && cp _snowboydetect.so /app/snowboy/\n\n# 暴露端口\nEXPOSE 5001\n\n# 设置 ENTRYPOINT\nENTRYPOINT [\"python\", \"wukong.py\"]\n"
  },
  {
    "path": "docker/DockerfileArm",
    "content": "# 使用官方 Python 3.8 基于 ARM 的镜像\nFROM arm32v7/python:3.8-slim\n\nMAINTAINER wzpan\n\n# 设置工作目录\nWORKDIR /app\n\n# 安装依赖库\nRUN apt-get update && apt-get install -y \\\n    git \\\n    portaudio19-dev \\\n    python3-pyaudio \\\n    sox \\\n    pulseaudio \\\n    libsox-fmt-all \\\n    ffmpeg \\\n    wget \\\n    swig \\\n    libpcre3 \\\n    libpcre3-dev \\\n    libatlas-base-dev \\\n    libffi-dev \\\n    build-essential \\\n    && rm -rf /var/lib/apt/lists/*\n\n# 克隆项目仓库\nRUN git clone https://github.com/wzpan/wukong-robot.git .\n\n# 安装 PyAudio\nRUN pip install pyaudio\n\n# 安装 Python 依赖\nRUN pip install --trusted-host pypi.python.org -r requirements.txt\n\n# 安装 wukong-contrib\nRUN mkdir -p $HOME/.wukong \\\n    && cd $HOME/.wukong \\\n    && git clone http://github.com/wzpan/wukong-contrib.git contrib \\\n    && pip install -r contrib/requirements.txt\n\n# 下载并编译 snowboy\nRUN wget https://wzpan-1253537070.cos.ap-guangzhou.myqcloud.com/misc/snowboy.tar.bz2 \\\n    && tar -xvjf snowboy.tar.bz2 \\\n    && cd snowboy/swig/Python3 \\\n    && make \\\n    && cp _snowboydetect.so /app/snowboy/\n\n# 暴露端口\nEXPOSE 5001\n\n# 设置 ENTRYPOINT\nENTRYPOINT [\"python\", \"wukong.py\"]\n"
  },
  {
    "path": "docs/.buildinfo",
    "content": "# Sphinx build info version 1\n# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.\nconfig: bed81550a26bd552fac818a5876d05a1\ntags: 645f666f9bcd5a90fca523b33c5a78b7\n"
  },
  {
    "path": "docs/.nojekyll",
    "content": ""
  },
  {
    "path": "docs/AI.html",
    "content": "\n\n<!DOCTYPE html>\n<!--[if IE 8]><html class=\"no-js lt-ie9\" lang=\"zh-CN\" > <![endif]-->\n<!--[if gt IE 8]><!--> <html class=\"no-js\" lang=\"zh-CN\" > <!--<![endif]-->\n<head>\n  <meta charset=\"utf-8\">\n  \n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  \n  <title>AI module &mdash; wukong-robot 1.2.0 文档</title>\n  \n\n  \n  \n  \n  \n\n  \n  <script type=\"text/javascript\" src=\"_static/js/modernizr.min.js\"></script>\n  \n    \n      <script type=\"text/javascript\" id=\"documentation_options\" data-url_root=\"./\" src=\"_static/documentation_options.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/jquery.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/underscore.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/doctools.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/language_data.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/translations.js\"></script>\n    \n    <script type=\"text/javascript\" src=\"_static/js/theme.js\"></script>\n\n    \n\n  \n  <link rel=\"stylesheet\" href=\"_static/css/theme.css\" type=\"text/css\" />\n  <link rel=\"stylesheet\" href=\"_static/pygments.css\" type=\"text/css\" />\n    <link rel=\"index\" title=\"索引\" href=\"genindex.html\" />\n    <link rel=\"search\" title=\"搜索\" href=\"search.html\" /> \n</head>\n\n<body class=\"wy-body-for-nav\">\n\n   \n  <div class=\"wy-grid-for-nav\">\n    \n    <nav data-toggle=\"wy-nav-shift\" class=\"wy-nav-side\">\n      <div class=\"wy-side-scroll\">\n        <div class=\"wy-side-nav-search\" >\n          \n\n          \n            <a href=\"index.html\" class=\"icon icon-home\"> wukong-robot\n          \n\n          \n          </a>\n\n          \n            \n            \n          \n\n          \n<div role=\"search\">\n  <form id=\"rtd-search-form\" class=\"wy-form\" action=\"search.html\" method=\"get\">\n    <input type=\"text\" name=\"q\" placeholder=\"Search docs\" />\n    <input type=\"hidden\" name=\"check_keywords\" value=\"yes\" />\n    <input type=\"hidden\" name=\"area\" value=\"default\" />\n  </form>\n</div>\n\n          \n        </div>\n\n        <div class=\"wy-menu wy-menu-vertical\" data-spy=\"affix\" role=\"navigation\" aria-label=\"main navigation\">\n          \n            \n            \n              \n            \n            \n              <!-- Local TOC -->\n              <div class=\"local-toc\"><ul>\n<li><a class=\"reference internal\" href=\"#\">AI module</a></li>\n</ul>\n</div>\n            \n          \n        </div>\n      </div>\n    </nav>\n\n    <section data-toggle=\"wy-nav-shift\" class=\"wy-nav-content-wrap\">\n\n      \n      <nav class=\"wy-nav-top\" aria-label=\"top navigation\">\n        \n          <i data-toggle=\"wy-nav-top\" class=\"fa fa-bars\"></i>\n          <a href=\"index.html\">wukong-robot</a>\n        \n      </nav>\n\n\n      <div class=\"wy-nav-content\">\n        \n        <div class=\"rst-content\">\n        \n          \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<div role=\"navigation\" aria-label=\"breadcrumbs navigation\">\n\n  <ul class=\"wy-breadcrumbs\">\n    \n      <li><a href=\"index.html\">Docs</a> &raquo;</li>\n        \n      <li>AI module</li>\n    \n    \n      <li class=\"wy-breadcrumbs-aside\">\n        \n            \n            <a href=\"_sources/AI.rst.txt\" rel=\"nofollow\"> View page source</a>\n          \n        \n      </li>\n    \n  </ul>\n\n  \n  <hr/>\n</div>\n          <div role=\"main\" class=\"document\" itemscope=\"itemscope\" itemtype=\"http://schema.org/Article\">\n           <div itemprop=\"articleBody\">\n            \n  <div class=\"section\" id=\"ai-module\">\n<h1>AI module<a class=\"headerlink\" href=\"#ai-module\" title=\"永久链接至标题\">¶</a></h1>\n</div>\n\n\n           </div>\n           \n          </div>\n          <footer>\n  \n\n  <hr/>\n\n  <div role=\"contentinfo\">\n    <p>\n        &copy; Copyright 2019, wzpan\n\n    </p>\n  </div>\n  Built with <a href=\"http://sphinx-doc.org/\">Sphinx</a> using a <a href=\"https://github.com/rtfd/sphinx_rtd_theme\">theme</a> provided by <a href=\"https://readthedocs.org\">Read the Docs</a>. \n\n</footer>\n\n        </div>\n      </div>\n\n    </section>\n\n  </div>\n  \n\n\n  <script type=\"text/javascript\">\n      jQuery(function () {\n          SphinxRtdTheme.Navigation.enable(true);\n      });\n  </script>\n\n  \n  \n    \n   \n\n</body>\n</html>"
  },
  {
    "path": "docs/ASR.html",
    "content": "\n\n<!DOCTYPE html>\n<!--[if IE 8]><html class=\"no-js lt-ie9\" lang=\"zh-CN\" > <![endif]-->\n<!--[if gt IE 8]><!--> <html class=\"no-js\" lang=\"zh-CN\" > <!--<![endif]-->\n<head>\n  <meta charset=\"utf-8\">\n  \n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  \n  <title>ASR module &mdash; wukong-robot 1.2.0 文档</title>\n  \n\n  \n  \n  \n  \n\n  \n  <script type=\"text/javascript\" src=\"_static/js/modernizr.min.js\"></script>\n  \n    \n      <script type=\"text/javascript\" id=\"documentation_options\" data-url_root=\"./\" src=\"_static/documentation_options.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/jquery.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/underscore.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/doctools.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/language_data.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/translations.js\"></script>\n    \n    <script type=\"text/javascript\" src=\"_static/js/theme.js\"></script>\n\n    \n\n  \n  <link rel=\"stylesheet\" href=\"_static/css/theme.css\" type=\"text/css\" />\n  <link rel=\"stylesheet\" href=\"_static/pygments.css\" type=\"text/css\" />\n    <link rel=\"index\" title=\"索引\" href=\"genindex.html\" />\n    <link rel=\"search\" title=\"搜索\" href=\"search.html\" /> \n</head>\n\n<body class=\"wy-body-for-nav\">\n\n   \n  <div class=\"wy-grid-for-nav\">\n    \n    <nav data-toggle=\"wy-nav-shift\" class=\"wy-nav-side\">\n      <div class=\"wy-side-scroll\">\n        <div class=\"wy-side-nav-search\" >\n          \n\n          \n            <a href=\"index.html\" class=\"icon icon-home\"> wukong-robot\n          \n\n          \n          </a>\n\n          \n            \n            \n          \n\n          \n<div role=\"search\">\n  <form id=\"rtd-search-form\" class=\"wy-form\" action=\"search.html\" method=\"get\">\n    <input type=\"text\" name=\"q\" placeholder=\"Search docs\" />\n    <input type=\"hidden\" name=\"check_keywords\" value=\"yes\" />\n    <input type=\"hidden\" name=\"area\" value=\"default\" />\n  </form>\n</div>\n\n          \n        </div>\n\n        <div class=\"wy-menu wy-menu-vertical\" data-spy=\"affix\" role=\"navigation\" aria-label=\"main navigation\">\n          \n            \n            \n              \n            \n            \n              <!-- Local TOC -->\n              <div class=\"local-toc\"><ul>\n<li><a class=\"reference internal\" href=\"#\">ASR module</a></li>\n</ul>\n</div>\n            \n          \n        </div>\n      </div>\n    </nav>\n\n    <section data-toggle=\"wy-nav-shift\" class=\"wy-nav-content-wrap\">\n\n      \n      <nav class=\"wy-nav-top\" aria-label=\"top navigation\">\n        \n          <i data-toggle=\"wy-nav-top\" class=\"fa fa-bars\"></i>\n          <a href=\"index.html\">wukong-robot</a>\n        \n      </nav>\n\n\n      <div class=\"wy-nav-content\">\n        \n        <div class=\"rst-content\">\n        \n          \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<div role=\"navigation\" aria-label=\"breadcrumbs navigation\">\n\n  <ul class=\"wy-breadcrumbs\">\n    \n      <li><a href=\"index.html\">Docs</a> &raquo;</li>\n        \n      <li>ASR module</li>\n    \n    \n      <li class=\"wy-breadcrumbs-aside\">\n        \n            \n            <a href=\"_sources/ASR.rst.txt\" rel=\"nofollow\"> View page source</a>\n          \n        \n      </li>\n    \n  </ul>\n\n  \n  <hr/>\n</div>\n          <div role=\"main\" class=\"document\" itemscope=\"itemscope\" itemtype=\"http://schema.org/Article\">\n           <div itemprop=\"articleBody\">\n            \n  <div class=\"section\" id=\"asr-module\">\n<h1>ASR module<a class=\"headerlink\" href=\"#asr-module\" title=\"永久链接至标题\">¶</a></h1>\n</div>\n\n\n           </div>\n           \n          </div>\n          <footer>\n  \n\n  <hr/>\n\n  <div role=\"contentinfo\">\n    <p>\n        &copy; Copyright 2019, wzpan\n\n    </p>\n  </div>\n  Built with <a href=\"http://sphinx-doc.org/\">Sphinx</a> using a <a href=\"https://github.com/rtfd/sphinx_rtd_theme\">theme</a> provided by <a href=\"https://readthedocs.org\">Read the Docs</a>. \n\n</footer>\n\n        </div>\n      </div>\n\n    </section>\n\n  </div>\n  \n\n\n  <script type=\"text/javascript\">\n      jQuery(function () {\n          SphinxRtdTheme.Navigation.enable(true);\n      });\n  </script>\n\n  \n  \n    \n   \n\n</body>\n</html>"
  },
  {
    "path": "docs/Brain.html",
    "content": "\n\n<!DOCTYPE html>\n<!--[if IE 8]><html class=\"no-js lt-ie9\" lang=\"zh-CN\" > <![endif]-->\n<!--[if gt IE 8]><!--> <html class=\"no-js\" lang=\"zh-CN\" > <!--<![endif]-->\n<head>\n  <meta charset=\"utf-8\">\n  \n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  \n  <title>Brain module &mdash; wukong-robot 1.2.0 文档</title>\n  \n\n  \n  \n  \n  \n\n  \n  <script type=\"text/javascript\" src=\"_static/js/modernizr.min.js\"></script>\n  \n    \n      <script type=\"text/javascript\" id=\"documentation_options\" data-url_root=\"./\" src=\"_static/documentation_options.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/jquery.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/underscore.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/doctools.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/language_data.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/translations.js\"></script>\n    \n    <script type=\"text/javascript\" src=\"_static/js/theme.js\"></script>\n\n    \n\n  \n  <link rel=\"stylesheet\" href=\"_static/css/theme.css\" type=\"text/css\" />\n  <link rel=\"stylesheet\" href=\"_static/pygments.css\" type=\"text/css\" />\n    <link rel=\"index\" title=\"索引\" href=\"genindex.html\" />\n    <link rel=\"search\" title=\"搜索\" href=\"search.html\" /> \n</head>\n\n<body class=\"wy-body-for-nav\">\n\n   \n  <div class=\"wy-grid-for-nav\">\n    \n    <nav data-toggle=\"wy-nav-shift\" class=\"wy-nav-side\">\n      <div class=\"wy-side-scroll\">\n        <div class=\"wy-side-nav-search\" >\n          \n\n          \n            <a href=\"index.html\" class=\"icon icon-home\"> wukong-robot\n          \n\n          \n          </a>\n\n          \n            \n            \n          \n\n          \n<div role=\"search\">\n  <form id=\"rtd-search-form\" class=\"wy-form\" action=\"search.html\" method=\"get\">\n    <input type=\"text\" name=\"q\" placeholder=\"Search docs\" />\n    <input type=\"hidden\" name=\"check_keywords\" value=\"yes\" />\n    <input type=\"hidden\" name=\"area\" value=\"default\" />\n  </form>\n</div>\n\n          \n        </div>\n\n        <div class=\"wy-menu wy-menu-vertical\" data-spy=\"affix\" role=\"navigation\" aria-label=\"main navigation\">\n          \n            \n            \n              \n            \n            \n              <!-- Local TOC -->\n              <div class=\"local-toc\"><ul>\n<li><a class=\"reference internal\" href=\"#\">Brain module</a></li>\n</ul>\n</div>\n            \n          \n        </div>\n      </div>\n    </nav>\n\n    <section data-toggle=\"wy-nav-shift\" class=\"wy-nav-content-wrap\">\n\n      \n      <nav class=\"wy-nav-top\" aria-label=\"top navigation\">\n        \n          <i data-toggle=\"wy-nav-top\" class=\"fa fa-bars\"></i>\n          <a href=\"index.html\">wukong-robot</a>\n        \n      </nav>\n\n\n      <div class=\"wy-nav-content\">\n        \n        <div class=\"rst-content\">\n        \n          \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<div role=\"navigation\" aria-label=\"breadcrumbs navigation\">\n\n  <ul class=\"wy-breadcrumbs\">\n    \n      <li><a href=\"index.html\">Docs</a> &raquo;</li>\n        \n      <li>Brain module</li>\n    \n    \n      <li class=\"wy-breadcrumbs-aside\">\n        \n            \n            <a href=\"_sources/Brain.rst.txt\" rel=\"nofollow\"> View page source</a>\n          \n        \n      </li>\n    \n  </ul>\n\n  \n  <hr/>\n</div>\n          <div role=\"main\" class=\"document\" itemscope=\"itemscope\" itemtype=\"http://schema.org/Article\">\n           <div itemprop=\"articleBody\">\n            \n  <div class=\"section\" id=\"brain-module\">\n<h1>Brain module<a class=\"headerlink\" href=\"#brain-module\" title=\"永久链接至标题\">¶</a></h1>\n</div>\n\n\n           </div>\n           \n          </div>\n          <footer>\n  \n\n  <hr/>\n\n  <div role=\"contentinfo\">\n    <p>\n        &copy; Copyright 2019, wzpan\n\n    </p>\n  </div>\n  Built with <a href=\"http://sphinx-doc.org/\">Sphinx</a> using a <a href=\"https://github.com/rtfd/sphinx_rtd_theme\">theme</a> provided by <a href=\"https://readthedocs.org\">Read the Docs</a>. \n\n</footer>\n\n        </div>\n      </div>\n\n    </section>\n\n  </div>\n  \n\n\n  <script type=\"text/javascript\">\n      jQuery(function () {\n          SphinxRtdTheme.Navigation.enable(true);\n      });\n  </script>\n\n  \n  \n    \n   \n\n</body>\n</html>"
  },
  {
    "path": "docs/ConfigMonitor.html",
    "content": "\n\n<!DOCTYPE html>\n<!--[if IE 8]><html class=\"no-js lt-ie9\" lang=\"zh-CN\" > <![endif]-->\n<!--[if gt IE 8]><!--> <html class=\"no-js\" lang=\"zh-CN\" > <!--<![endif]-->\n<head>\n  <meta charset=\"utf-8\">\n  \n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  \n  <title>ConfigMonitor module &mdash; wukong-robot 1.2.0 文档</title>\n  \n\n  \n  \n  \n  \n\n  \n  <script type=\"text/javascript\" src=\"_static/js/modernizr.min.js\"></script>\n  \n    \n      <script type=\"text/javascript\" id=\"documentation_options\" data-url_root=\"./\" src=\"_static/documentation_options.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/jquery.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/underscore.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/doctools.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/language_data.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/translations.js\"></script>\n    \n    <script type=\"text/javascript\" src=\"_static/js/theme.js\"></script>\n\n    \n\n  \n  <link rel=\"stylesheet\" href=\"_static/css/theme.css\" type=\"text/css\" />\n  <link rel=\"stylesheet\" href=\"_static/pygments.css\" type=\"text/css\" />\n    <link rel=\"index\" title=\"索引\" href=\"genindex.html\" />\n    <link rel=\"search\" title=\"搜索\" href=\"search.html\" /> \n</head>\n\n<body class=\"wy-body-for-nav\">\n\n   \n  <div class=\"wy-grid-for-nav\">\n    \n    <nav data-toggle=\"wy-nav-shift\" class=\"wy-nav-side\">\n      <div class=\"wy-side-scroll\">\n        <div class=\"wy-side-nav-search\" >\n          \n\n          \n            <a href=\"index.html\" class=\"icon icon-home\"> wukong-robot\n          \n\n          \n          </a>\n\n          \n            \n            \n          \n\n          \n<div role=\"search\">\n  <form id=\"rtd-search-form\" class=\"wy-form\" action=\"search.html\" method=\"get\">\n    <input type=\"text\" name=\"q\" placeholder=\"Search docs\" />\n    <input type=\"hidden\" name=\"check_keywords\" value=\"yes\" />\n    <input type=\"hidden\" name=\"area\" value=\"default\" />\n  </form>\n</div>\n\n          \n        </div>\n\n        <div class=\"wy-menu wy-menu-vertical\" data-spy=\"affix\" role=\"navigation\" aria-label=\"main navigation\">\n          \n            \n            \n              \n            \n            \n              <!-- Local TOC -->\n              <div class=\"local-toc\"><ul>\n<li><a class=\"reference internal\" href=\"#\">ConfigMonitor module</a></li>\n</ul>\n</div>\n            \n          \n        </div>\n      </div>\n    </nav>\n\n    <section data-toggle=\"wy-nav-shift\" class=\"wy-nav-content-wrap\">\n\n      \n      <nav class=\"wy-nav-top\" aria-label=\"top navigation\">\n        \n          <i data-toggle=\"wy-nav-top\" class=\"fa fa-bars\"></i>\n          <a href=\"index.html\">wukong-robot</a>\n        \n      </nav>\n\n\n      <div class=\"wy-nav-content\">\n        \n        <div class=\"rst-content\">\n        \n          \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<div role=\"navigation\" aria-label=\"breadcrumbs navigation\">\n\n  <ul class=\"wy-breadcrumbs\">\n    \n      <li><a href=\"index.html\">Docs</a> &raquo;</li>\n        \n      <li>ConfigMonitor module</li>\n    \n    \n      <li class=\"wy-breadcrumbs-aside\">\n        \n            \n            <a href=\"_sources/ConfigMonitor.rst.txt\" rel=\"nofollow\"> View page source</a>\n          \n        \n      </li>\n    \n  </ul>\n\n  \n  <hr/>\n</div>\n          <div role=\"main\" class=\"document\" itemscope=\"itemscope\" itemtype=\"http://schema.org/Article\">\n           <div itemprop=\"articleBody\">\n            \n  <div class=\"section\" id=\"configmonitor-module\">\n<h1>ConfigMonitor module<a class=\"headerlink\" href=\"#configmonitor-module\" title=\"永久链接至标题\">¶</a></h1>\n</div>\n\n\n           </div>\n           \n          </div>\n          <footer>\n  \n\n  <hr/>\n\n  <div role=\"contentinfo\">\n    <p>\n        &copy; Copyright 2019, wzpan\n\n    </p>\n  </div>\n  Built with <a href=\"http://sphinx-doc.org/\">Sphinx</a> using a <a href=\"https://github.com/rtfd/sphinx_rtd_theme\">theme</a> provided by <a href=\"https://readthedocs.org\">Read the Docs</a>. \n\n</footer>\n\n        </div>\n      </div>\n\n    </section>\n\n  </div>\n  \n\n\n  <script type=\"text/javascript\">\n      jQuery(function () {\n          SphinxRtdTheme.Navigation.enable(true);\n      });\n  </script>\n\n  \n  \n    \n   \n\n</body>\n</html>"
  },
  {
    "path": "docs/Conversation.html",
    "content": "\n\n<!DOCTYPE html>\n<!--[if IE 8]><html class=\"no-js lt-ie9\" lang=\"zh-CN\" > <![endif]-->\n<!--[if gt IE 8]><!--> <html class=\"no-js\" lang=\"zh-CN\" > <!--<![endif]-->\n<head>\n  <meta charset=\"utf-8\">\n  \n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  \n  <title>Conversation module &mdash; wukong-robot 1.2.0 文档</title>\n  \n\n  \n  \n  \n  \n\n  \n  <script type=\"text/javascript\" src=\"_static/js/modernizr.min.js\"></script>\n  \n    \n      <script type=\"text/javascript\" id=\"documentation_options\" data-url_root=\"./\" src=\"_static/documentation_options.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/jquery.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/underscore.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/doctools.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/language_data.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/translations.js\"></script>\n    \n    <script type=\"text/javascript\" src=\"_static/js/theme.js\"></script>\n\n    \n\n  \n  <link rel=\"stylesheet\" href=\"_static/css/theme.css\" type=\"text/css\" />\n  <link rel=\"stylesheet\" href=\"_static/pygments.css\" type=\"text/css\" />\n    <link rel=\"index\" title=\"索引\" href=\"genindex.html\" />\n    <link rel=\"search\" title=\"搜索\" href=\"search.html\" /> \n</head>\n\n<body class=\"wy-body-for-nav\">\n\n   \n  <div class=\"wy-grid-for-nav\">\n    \n    <nav data-toggle=\"wy-nav-shift\" class=\"wy-nav-side\">\n      <div class=\"wy-side-scroll\">\n        <div class=\"wy-side-nav-search\" >\n          \n\n          \n            <a href=\"index.html\" class=\"icon icon-home\"> wukong-robot\n          \n\n          \n          </a>\n\n          \n            \n            \n          \n\n          \n<div role=\"search\">\n  <form id=\"rtd-search-form\" class=\"wy-form\" action=\"search.html\" method=\"get\">\n    <input type=\"text\" name=\"q\" placeholder=\"Search docs\" />\n    <input type=\"hidden\" name=\"check_keywords\" value=\"yes\" />\n    <input type=\"hidden\" name=\"area\" value=\"default\" />\n  </form>\n</div>\n\n          \n        </div>\n\n        <div class=\"wy-menu wy-menu-vertical\" data-spy=\"affix\" role=\"navigation\" aria-label=\"main navigation\">\n          \n            \n            \n              \n            \n            \n              <!-- Local TOC -->\n              <div class=\"local-toc\"><ul>\n<li><a class=\"reference internal\" href=\"#\">Conversation module</a></li>\n</ul>\n</div>\n            \n          \n        </div>\n      </div>\n    </nav>\n\n    <section data-toggle=\"wy-nav-shift\" class=\"wy-nav-content-wrap\">\n\n      \n      <nav class=\"wy-nav-top\" aria-label=\"top navigation\">\n        \n          <i data-toggle=\"wy-nav-top\" class=\"fa fa-bars\"></i>\n          <a href=\"index.html\">wukong-robot</a>\n        \n      </nav>\n\n\n      <div class=\"wy-nav-content\">\n        \n        <div class=\"rst-content\">\n        \n          \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<div role=\"navigation\" aria-label=\"breadcrumbs navigation\">\n\n  <ul class=\"wy-breadcrumbs\">\n    \n      <li><a href=\"index.html\">Docs</a> &raquo;</li>\n        \n      <li>Conversation module</li>\n    \n    \n      <li class=\"wy-breadcrumbs-aside\">\n        \n            \n            <a href=\"_sources/Conversation.rst.txt\" rel=\"nofollow\"> View page source</a>\n          \n        \n      </li>\n    \n  </ul>\n\n  \n  <hr/>\n</div>\n          <div role=\"main\" class=\"document\" itemscope=\"itemscope\" itemtype=\"http://schema.org/Article\">\n           <div itemprop=\"articleBody\">\n            \n  <div class=\"section\" id=\"conversation-module\">\n<h1>Conversation module<a class=\"headerlink\" href=\"#conversation-module\" title=\"永久链接至标题\">¶</a></h1>\n</div>\n\n\n           </div>\n           \n          </div>\n          <footer>\n  \n\n  <hr/>\n\n  <div role=\"contentinfo\">\n    <p>\n        &copy; Copyright 2019, wzpan\n\n    </p>\n  </div>\n  Built with <a href=\"http://sphinx-doc.org/\">Sphinx</a> using a <a href=\"https://github.com/rtfd/sphinx_rtd_theme\">theme</a> provided by <a href=\"https://readthedocs.org\">Read the Docs</a>. \n\n</footer>\n\n        </div>\n      </div>\n\n    </section>\n\n  </div>\n  \n\n\n  <script type=\"text/javascript\">\n      jQuery(function () {\n          SphinxRtdTheme.Navigation.enable(true);\n      });\n  </script>\n\n  \n  \n    \n   \n\n</body>\n</html>"
  },
  {
    "path": "docs/Player.html",
    "content": "\n\n<!DOCTYPE html>\n<!--[if IE 8]><html class=\"no-js lt-ie9\" lang=\"zh-CN\" > <![endif]-->\n<!--[if gt IE 8]><!--> <html class=\"no-js\" lang=\"zh-CN\" > <!--<![endif]-->\n<head>\n  <meta charset=\"utf-8\">\n  \n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  \n  <title>Player module &mdash; wukong-robot 1.2.0 文档</title>\n  \n\n  \n  \n  \n  \n\n  \n  <script type=\"text/javascript\" src=\"_static/js/modernizr.min.js\"></script>\n  \n    \n      <script type=\"text/javascript\" id=\"documentation_options\" data-url_root=\"./\" src=\"_static/documentation_options.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/jquery.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/underscore.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/doctools.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/language_data.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/translations.js\"></script>\n    \n    <script type=\"text/javascript\" src=\"_static/js/theme.js\"></script>\n\n    \n\n  \n  <link rel=\"stylesheet\" href=\"_static/css/theme.css\" type=\"text/css\" />\n  <link rel=\"stylesheet\" href=\"_static/pygments.css\" type=\"text/css\" />\n    <link rel=\"index\" title=\"索引\" href=\"genindex.html\" />\n    <link rel=\"search\" title=\"搜索\" href=\"search.html\" /> \n</head>\n\n<body class=\"wy-body-for-nav\">\n\n   \n  <div class=\"wy-grid-for-nav\">\n    \n    <nav data-toggle=\"wy-nav-shift\" class=\"wy-nav-side\">\n      <div class=\"wy-side-scroll\">\n        <div class=\"wy-side-nav-search\" >\n          \n\n          \n            <a href=\"index.html\" class=\"icon icon-home\"> wukong-robot\n          \n\n          \n          </a>\n\n          \n            \n            \n          \n\n          \n<div role=\"search\">\n  <form id=\"rtd-search-form\" class=\"wy-form\" action=\"search.html\" method=\"get\">\n    <input type=\"text\" name=\"q\" placeholder=\"Search docs\" />\n    <input type=\"hidden\" name=\"check_keywords\" value=\"yes\" />\n    <input type=\"hidden\" name=\"area\" value=\"default\" />\n  </form>\n</div>\n\n          \n        </div>\n\n        <div class=\"wy-menu wy-menu-vertical\" data-spy=\"affix\" role=\"navigation\" aria-label=\"main navigation\">\n          \n            \n            \n              \n            \n            \n              <!-- Local TOC -->\n              <div class=\"local-toc\"><ul>\n<li><a class=\"reference internal\" href=\"#\">Player module</a></li>\n</ul>\n</div>\n            \n          \n        </div>\n      </div>\n    </nav>\n\n    <section data-toggle=\"wy-nav-shift\" class=\"wy-nav-content-wrap\">\n\n      \n      <nav class=\"wy-nav-top\" aria-label=\"top navigation\">\n        \n          <i data-toggle=\"wy-nav-top\" class=\"fa fa-bars\"></i>\n          <a href=\"index.html\">wukong-robot</a>\n        \n      </nav>\n\n\n      <div class=\"wy-nav-content\">\n        \n        <div class=\"rst-content\">\n        \n          \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<div role=\"navigation\" aria-label=\"breadcrumbs navigation\">\n\n  <ul class=\"wy-breadcrumbs\">\n    \n      <li><a href=\"index.html\">Docs</a> &raquo;</li>\n        \n      <li>Player module</li>\n    \n    \n      <li class=\"wy-breadcrumbs-aside\">\n        \n            \n            <a href=\"_sources/Player.rst.txt\" rel=\"nofollow\"> View page source</a>\n          \n        \n      </li>\n    \n  </ul>\n\n  \n  <hr/>\n</div>\n          <div role=\"main\" class=\"document\" itemscope=\"itemscope\" itemtype=\"http://schema.org/Article\">\n           <div itemprop=\"articleBody\">\n            \n  <div class=\"section\" id=\"player-module\">\n<h1>Player module<a class=\"headerlink\" href=\"#player-module\" title=\"永久链接至标题\">¶</a></h1>\n</div>\n\n\n           </div>\n           \n          </div>\n          <footer>\n  \n\n  <hr/>\n\n  <div role=\"contentinfo\">\n    <p>\n        &copy; Copyright 2019, wzpan\n\n    </p>\n  </div>\n  Built with <a href=\"http://sphinx-doc.org/\">Sphinx</a> using a <a href=\"https://github.com/rtfd/sphinx_rtd_theme\">theme</a> provided by <a href=\"https://readthedocs.org\">Read the Docs</a>. \n\n</footer>\n\n        </div>\n      </div>\n\n    </section>\n\n  </div>\n  \n\n\n  <script type=\"text/javascript\">\n      jQuery(function () {\n          SphinxRtdTheme.Navigation.enable(true);\n      });\n  </script>\n\n  \n  \n    \n   \n\n</body>\n</html>"
  },
  {
    "path": "docs/TTS.html",
    "content": "\n\n<!DOCTYPE html>\n<!--[if IE 8]><html class=\"no-js lt-ie9\" lang=\"zh-CN\" > <![endif]-->\n<!--[if gt IE 8]><!--> <html class=\"no-js\" lang=\"zh-CN\" > <!--<![endif]-->\n<head>\n  <meta charset=\"utf-8\">\n  \n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  \n  <title>TTS module &mdash; wukong-robot 1.2.0 文档</title>\n  \n\n  \n  \n  \n  \n\n  \n  <script type=\"text/javascript\" src=\"_static/js/modernizr.min.js\"></script>\n  \n    \n      <script type=\"text/javascript\" id=\"documentation_options\" data-url_root=\"./\" src=\"_static/documentation_options.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/jquery.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/underscore.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/doctools.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/language_data.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/translations.js\"></script>\n    \n    <script type=\"text/javascript\" src=\"_static/js/theme.js\"></script>\n\n    \n\n  \n  <link rel=\"stylesheet\" href=\"_static/css/theme.css\" type=\"text/css\" />\n  <link rel=\"stylesheet\" href=\"_static/pygments.css\" type=\"text/css\" />\n    <link rel=\"index\" title=\"索引\" href=\"genindex.html\" />\n    <link rel=\"search\" title=\"搜索\" href=\"search.html\" /> \n</head>\n\n<body class=\"wy-body-for-nav\">\n\n   \n  <div class=\"wy-grid-for-nav\">\n    \n    <nav data-toggle=\"wy-nav-shift\" class=\"wy-nav-side\">\n      <div class=\"wy-side-scroll\">\n        <div class=\"wy-side-nav-search\" >\n          \n\n          \n            <a href=\"index.html\" class=\"icon icon-home\"> wukong-robot\n          \n\n          \n          </a>\n\n          \n            \n            \n          \n\n          \n<div role=\"search\">\n  <form id=\"rtd-search-form\" class=\"wy-form\" action=\"search.html\" method=\"get\">\n    <input type=\"text\" name=\"q\" placeholder=\"Search docs\" />\n    <input type=\"hidden\" name=\"check_keywords\" value=\"yes\" />\n    <input type=\"hidden\" name=\"area\" value=\"default\" />\n  </form>\n</div>\n\n          \n        </div>\n\n        <div class=\"wy-menu wy-menu-vertical\" data-spy=\"affix\" role=\"navigation\" aria-label=\"main navigation\">\n          \n            \n            \n              \n            \n            \n              <!-- Local TOC -->\n              <div class=\"local-toc\"><ul>\n<li><a class=\"reference internal\" href=\"#\">TTS module</a></li>\n</ul>\n</div>\n            \n          \n        </div>\n      </div>\n    </nav>\n\n    <section data-toggle=\"wy-nav-shift\" class=\"wy-nav-content-wrap\">\n\n      \n      <nav class=\"wy-nav-top\" aria-label=\"top navigation\">\n        \n          <i data-toggle=\"wy-nav-top\" class=\"fa fa-bars\"></i>\n          <a href=\"index.html\">wukong-robot</a>\n        \n      </nav>\n\n\n      <div class=\"wy-nav-content\">\n        \n        <div class=\"rst-content\">\n        \n          \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<div role=\"navigation\" aria-label=\"breadcrumbs navigation\">\n\n  <ul class=\"wy-breadcrumbs\">\n    \n      <li><a href=\"index.html\">Docs</a> &raquo;</li>\n        \n      <li>TTS module</li>\n    \n    \n      <li class=\"wy-breadcrumbs-aside\">\n        \n            \n            <a href=\"_sources/TTS.rst.txt\" rel=\"nofollow\"> View page source</a>\n          \n        \n      </li>\n    \n  </ul>\n\n  \n  <hr/>\n</div>\n          <div role=\"main\" class=\"document\" itemscope=\"itemscope\" itemtype=\"http://schema.org/Article\">\n           <div itemprop=\"articleBody\">\n            \n  <div class=\"section\" id=\"tts-module\">\n<h1>TTS module<a class=\"headerlink\" href=\"#tts-module\" title=\"永久链接至标题\">¶</a></h1>\n</div>\n\n\n           </div>\n           \n          </div>\n          <footer>\n  \n\n  <hr/>\n\n  <div role=\"contentinfo\">\n    <p>\n        &copy; Copyright 2019, wzpan\n\n    </p>\n  </div>\n  Built with <a href=\"http://sphinx-doc.org/\">Sphinx</a> using a <a href=\"https://github.com/rtfd/sphinx_rtd_theme\">theme</a> provided by <a href=\"https://readthedocs.org\">Read the Docs</a>. \n\n</footer>\n\n        </div>\n      </div>\n\n    </section>\n\n  </div>\n  \n\n\n  <script type=\"text/javascript\">\n      jQuery(function () {\n          SphinxRtdTheme.Navigation.enable(true);\n      });\n  </script>\n\n  \n  \n    \n   \n\n</body>\n</html>"
  },
  {
    "path": "docs/Updater.html",
    "content": "\n\n<!DOCTYPE html>\n<!--[if IE 8]><html class=\"no-js lt-ie9\" lang=\"zh-CN\" > <![endif]-->\n<!--[if gt IE 8]><!--> <html class=\"no-js\" lang=\"zh-CN\" > <!--<![endif]-->\n<head>\n  <meta charset=\"utf-8\">\n  \n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  \n  <title>Updater module &mdash; wukong-robot 1.2.0 文档</title>\n  \n\n  \n  \n  \n  \n\n  \n  <script type=\"text/javascript\" src=\"_static/js/modernizr.min.js\"></script>\n  \n    \n      <script type=\"text/javascript\" id=\"documentation_options\" data-url_root=\"./\" src=\"_static/documentation_options.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/jquery.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/underscore.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/doctools.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/language_data.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/translations.js\"></script>\n    \n    <script type=\"text/javascript\" src=\"_static/js/theme.js\"></script>\n\n    \n\n  \n  <link rel=\"stylesheet\" href=\"_static/css/theme.css\" type=\"text/css\" />\n  <link rel=\"stylesheet\" href=\"_static/pygments.css\" type=\"text/css\" />\n    <link rel=\"index\" title=\"索引\" href=\"genindex.html\" />\n    <link rel=\"search\" title=\"搜索\" href=\"search.html\" /> \n</head>\n\n<body class=\"wy-body-for-nav\">\n\n   \n  <div class=\"wy-grid-for-nav\">\n    \n    <nav data-toggle=\"wy-nav-shift\" class=\"wy-nav-side\">\n      <div class=\"wy-side-scroll\">\n        <div class=\"wy-side-nav-search\" >\n          \n\n          \n            <a href=\"index.html\" class=\"icon icon-home\"> wukong-robot\n          \n\n          \n          </a>\n\n          \n            \n            \n          \n\n          \n<div role=\"search\">\n  <form id=\"rtd-search-form\" class=\"wy-form\" action=\"search.html\" method=\"get\">\n    <input type=\"text\" name=\"q\" placeholder=\"Search docs\" />\n    <input type=\"hidden\" name=\"check_keywords\" value=\"yes\" />\n    <input type=\"hidden\" name=\"area\" value=\"default\" />\n  </form>\n</div>\n\n          \n        </div>\n\n        <div class=\"wy-menu wy-menu-vertical\" data-spy=\"affix\" role=\"navigation\" aria-label=\"main navigation\">\n          \n            \n            \n              \n            \n            \n              <!-- Local TOC -->\n              <div class=\"local-toc\"><ul>\n<li><a class=\"reference internal\" href=\"#\">Updater module</a></li>\n</ul>\n</div>\n            \n          \n        </div>\n      </div>\n    </nav>\n\n    <section data-toggle=\"wy-nav-shift\" class=\"wy-nav-content-wrap\">\n\n      \n      <nav class=\"wy-nav-top\" aria-label=\"top navigation\">\n        \n          <i data-toggle=\"wy-nav-top\" class=\"fa fa-bars\"></i>\n          <a href=\"index.html\">wukong-robot</a>\n        \n      </nav>\n\n\n      <div class=\"wy-nav-content\">\n        \n        <div class=\"rst-content\">\n        \n          \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<div role=\"navigation\" aria-label=\"breadcrumbs navigation\">\n\n  <ul class=\"wy-breadcrumbs\">\n    \n      <li><a href=\"index.html\">Docs</a> &raquo;</li>\n        \n      <li>Updater module</li>\n    \n    \n      <li class=\"wy-breadcrumbs-aside\">\n        \n            \n            <a href=\"_sources/Updater.rst.txt\" rel=\"nofollow\"> View page source</a>\n          \n        \n      </li>\n    \n  </ul>\n\n  \n  <hr/>\n</div>\n          <div role=\"main\" class=\"document\" itemscope=\"itemscope\" itemtype=\"http://schema.org/Article\">\n           <div itemprop=\"articleBody\">\n            \n  <div class=\"section\" id=\"updater-module\">\n<h1>Updater module<a class=\"headerlink\" href=\"#updater-module\" title=\"永久链接至标题\">¶</a></h1>\n</div>\n\n\n           </div>\n           \n          </div>\n          <footer>\n  \n\n  <hr/>\n\n  <div role=\"contentinfo\">\n    <p>\n        &copy; Copyright 2019, wzpan\n\n    </p>\n  </div>\n  Built with <a href=\"http://sphinx-doc.org/\">Sphinx</a> using a <a href=\"https://github.com/rtfd/sphinx_rtd_theme\">theme</a> provided by <a href=\"https://readthedocs.org\">Read the Docs</a>. \n\n</footer>\n\n        </div>\n      </div>\n\n    </section>\n\n  </div>\n  \n\n\n  <script type=\"text/javascript\">\n      jQuery(function () {\n          SphinxRtdTheme.Navigation.enable(true);\n      });\n  </script>\n\n  \n  \n    \n   \n\n</body>\n</html>"
  },
  {
    "path": "docs/_modules/index.html",
    "content": "\n\n<!DOCTYPE html>\n<!--[if IE 8]><html class=\"no-js lt-ie9\" lang=\"zh-CN\" > <![endif]-->\n<!--[if gt IE 8]><!--> <html class=\"no-js\" lang=\"zh-CN\" > <!--<![endif]-->\n<head>\n  <meta charset=\"utf-8\">\n  \n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  \n  <title>概览：模块代码 &mdash; wukong-robot 1.2.0 文档</title>\n  \n\n  \n  \n  \n  \n\n  \n  <script type=\"text/javascript\" src=\"../_static/js/modernizr.min.js\"></script>\n  \n    \n      <script type=\"text/javascript\" id=\"documentation_options\" data-url_root=\"../\" src=\"../_static/documentation_options.js\"></script>\n        <script type=\"text/javascript\" src=\"../_static/jquery.js\"></script>\n        <script type=\"text/javascript\" src=\"../_static/underscore.js\"></script>\n        <script type=\"text/javascript\" src=\"../_static/doctools.js\"></script>\n        <script type=\"text/javascript\" src=\"../_static/language_data.js\"></script>\n        <script type=\"text/javascript\" src=\"../_static/translations.js\"></script>\n    \n    <script type=\"text/javascript\" src=\"../_static/js/theme.js\"></script>\n\n    \n\n  \n  <link rel=\"stylesheet\" href=\"../_static/css/theme.css\" type=\"text/css\" />\n  <link rel=\"stylesheet\" href=\"../_static/pygments.css\" type=\"text/css\" />\n    <link rel=\"index\" title=\"索引\" href=\"../genindex.html\" />\n    <link rel=\"search\" title=\"搜索\" href=\"../search.html\" /> \n</head>\n\n<body class=\"wy-body-for-nav\">\n\n   \n  <div class=\"wy-grid-for-nav\">\n    \n    <nav data-toggle=\"wy-nav-shift\" class=\"wy-nav-side\">\n      <div class=\"wy-side-scroll\">\n        <div class=\"wy-side-nav-search\" >\n          \n\n          \n            <a href=\"../index.html\" class=\"icon icon-home\"> wukong-robot\n          \n\n          \n          </a>\n\n          \n            \n            \n          \n\n          \n<div role=\"search\">\n  <form id=\"rtd-search-form\" class=\"wy-form\" action=\"../search.html\" method=\"get\">\n    <input type=\"text\" name=\"q\" placeholder=\"Search docs\" />\n    <input type=\"hidden\" name=\"check_keywords\" value=\"yes\" />\n    <input type=\"hidden\" name=\"area\" value=\"default\" />\n  </form>\n</div>\n\n          \n        </div>\n\n        <div class=\"wy-menu wy-menu-vertical\" data-spy=\"affix\" role=\"navigation\" aria-label=\"main navigation\">\n          \n            \n            \n              \n            \n            \n              <!-- Local TOC -->\n              <div class=\"local-toc\"></div>\n            \n          \n        </div>\n      </div>\n    </nav>\n\n    <section data-toggle=\"wy-nav-shift\" class=\"wy-nav-content-wrap\">\n\n      \n      <nav class=\"wy-nav-top\" aria-label=\"top navigation\">\n        \n          <i data-toggle=\"wy-nav-top\" class=\"fa fa-bars\"></i>\n          <a href=\"../index.html\">wukong-robot</a>\n        \n      </nav>\n\n\n      <div class=\"wy-nav-content\">\n        \n        <div class=\"rst-content\">\n        \n          \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<div role=\"navigation\" aria-label=\"breadcrumbs navigation\">\n\n  <ul class=\"wy-breadcrumbs\">\n    \n      <li><a href=\"../index.html\">Docs</a> &raquo;</li>\n        \n      <li>概览：模块代码</li>\n    \n    \n      <li class=\"wy-breadcrumbs-aside\">\n        \n      </li>\n    \n  </ul>\n\n  \n  <hr/>\n</div>\n          <div role=\"main\" class=\"document\" itemscope=\"itemscope\" itemtype=\"http://schema.org/Article\">\n           <div itemprop=\"articleBody\">\n            \n  <h1>代码可用的所有模块</h1>\n<ul><li><a href=\"plugins/Camera.html\">plugins.Camera</a></li>\n<li><a href=\"plugins/CleanCache.html\">plugins.CleanCache</a></li>\n<li><a href=\"plugins/Echo.html\">plugins.Echo</a></li>\n<li><a href=\"plugins/Email.html\">plugins.Email</a></li>\n<li><a href=\"plugins/Geek.html\">plugins.Geek</a></li>\n<li><a href=\"plugins/LocalPlayer.html\">plugins.LocalPlayer</a></li>\n<li><a href=\"plugins/Poem.html\">plugins.Poem</a></li>\n<li><a href=\"robot/AI.html\">robot.AI</a></li>\n<li><a href=\"robot/ASR.html\">robot.ASR</a></li>\n<li><a href=\"robot/Brain.html\">robot.Brain</a></li>\n<li><a href=\"robot/ConfigMonitor.html\">robot.ConfigMonitor</a></li>\n<li><a href=\"robot/Conversation.html\">robot.Conversation</a></li>\n<li><a href=\"robot/NLU.html\">robot.NLU</a></li>\n<li><a href=\"robot/Player.html\">robot.Player</a></li>\n<li><a href=\"robot/TTS.html\">robot.TTS</a></li>\n<li><a href=\"robot/Updater.html\">robot.Updater</a></li>\n<li><a href=\"robot/config.html\">robot.config</a></li>\n<li><a href=\"robot/constants.html\">robot.constants</a></li>\n<li><a href=\"robot/logging.html\">robot.logging</a></li>\n<li><a href=\"robot/plugin_loader.html\">robot.plugin_loader</a></li>\n<li><a href=\"robot/sdk/AbstractPlugin.html\">robot.sdk.AbstractPlugin</a></li>\n<li><a href=\"robot/sdk/AliSpeech.html\">robot.sdk.AliSpeech</a></li>\n<li><a href=\"robot/sdk/RASRsdk.html\">robot.sdk.RASRsdk</a></li>\n<li><a href=\"robot/sdk/TencentSpeech.html\">robot.sdk.TencentSpeech</a></li>\n<li><a href=\"robot/sdk/XunfeiSpeech.html\">robot.sdk.XunfeiSpeech</a></li>\n<li><a href=\"robot/sdk/unit.html\">robot.sdk.unit</a></li>\n<li><a href=\"robot/statistic.html\">robot.statistic</a></li>\n<li><a href=\"robot/utils.html\">robot.utils</a></li>\n<li><a href=\"snowboy/snowboydecoder.html\">snowboy.snowboydecoder</a></li>\n<li><a href=\"snowboy/snowboydetect.html\">snowboy.snowboydetect</a></li>\n<li><a href=\"wukong.html\">wukong</a></li>\n</ul>\n\n           </div>\n           \n          </div>\n          <footer>\n  \n\n  <hr/>\n\n  <div role=\"contentinfo\">\n    <p>\n        &copy; Copyright 2019, wzpan\n\n    </p>\n  </div>\n  Built with <a href=\"http://sphinx-doc.org/\">Sphinx</a> using a <a href=\"https://github.com/rtfd/sphinx_rtd_theme\">theme</a> provided by <a href=\"https://readthedocs.org\">Read the Docs</a>. \n\n</footer>\n\n        </div>\n      </div>\n\n    </section>\n\n  </div>\n  \n\n\n  <script type=\"text/javascript\">\n      jQuery(function () {\n          SphinxRtdTheme.Navigation.enable(true);\n      });\n  </script>\n\n  \n  \n    \n   \n\n</body>\n</html>"
  },
  {
    "path": "docs/_modules/logging.html",
    "content": "\n\n<!DOCTYPE html>\n<!--[if IE 8]><html class=\"no-js lt-ie9\" lang=\"zh-CN\" > <![endif]-->\n<!--[if gt IE 8]><!--> <html class=\"no-js\" lang=\"zh-CN\" > <!--<![endif]-->\n<head>\n  <meta charset=\"utf-8\">\n  \n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  \n  <title>logging &mdash; wukong-robot 1.2.0 文档</title>\n  \n\n  \n  \n  \n  \n\n  \n  <script type=\"text/javascript\" src=\"../_static/js/modernizr.min.js\"></script>\n  \n    \n      <script type=\"text/javascript\" id=\"documentation_options\" data-url_root=\"../\" src=\"../_static/documentation_options.js\"></script>\n        <script type=\"text/javascript\" src=\"../_static/jquery.js\"></script>\n        <script type=\"text/javascript\" src=\"../_static/underscore.js\"></script>\n        <script type=\"text/javascript\" src=\"../_static/doctools.js\"></script>\n        <script type=\"text/javascript\" src=\"../_static/language_data.js\"></script>\n        <script type=\"text/javascript\" src=\"../_static/translations.js\"></script>\n    \n    <script type=\"text/javascript\" src=\"../_static/js/theme.js\"></script>\n\n    \n\n  \n  <link rel=\"stylesheet\" href=\"../_static/css/theme.css\" type=\"text/css\" />\n  <link rel=\"stylesheet\" href=\"../_static/pygments.css\" type=\"text/css\" />\n    <link rel=\"index\" title=\"索引\" href=\"../genindex.html\" />\n    <link rel=\"search\" title=\"搜索\" href=\"../search.html\" /> \n</head>\n\n<body class=\"wy-body-for-nav\">\n\n   \n  <div class=\"wy-grid-for-nav\">\n    \n    <nav data-toggle=\"wy-nav-shift\" class=\"wy-nav-side\">\n      <div class=\"wy-side-scroll\">\n        <div class=\"wy-side-nav-search\" >\n          \n\n          \n            <a href=\"../index.html\" class=\"icon icon-home\"> wukong-robot\n          \n\n          \n          </a>\n\n          \n            \n            \n          \n\n          \n<div role=\"search\">\n  <form id=\"rtd-search-form\" class=\"wy-form\" action=\"../search.html\" method=\"get\">\n    <input type=\"text\" name=\"q\" placeholder=\"Search docs\" />\n    <input type=\"hidden\" name=\"check_keywords\" value=\"yes\" />\n    <input type=\"hidden\" name=\"area\" value=\"default\" />\n  </form>\n</div>\n\n          \n        </div>\n\n        <div class=\"wy-menu wy-menu-vertical\" data-spy=\"affix\" role=\"navigation\" aria-label=\"main navigation\">\n          \n            \n            \n              \n            \n            \n              <!-- Local TOC -->\n              <div class=\"local-toc\"></div>\n            \n          \n        </div>\n      </div>\n    </nav>\n\n    <section data-toggle=\"wy-nav-shift\" class=\"wy-nav-content-wrap\">\n\n      \n      <nav class=\"wy-nav-top\" aria-label=\"top navigation\">\n        \n          <i data-toggle=\"wy-nav-top\" class=\"fa fa-bars\"></i>\n          <a href=\"../index.html\">wukong-robot</a>\n        \n      </nav>\n\n\n      <div class=\"wy-nav-content\">\n        \n        <div class=\"rst-content\">\n        \n          \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<div role=\"navigation\" aria-label=\"breadcrumbs navigation\">\n\n  <ul class=\"wy-breadcrumbs\">\n    \n      <li><a href=\"../index.html\">Docs</a> &raquo;</li>\n        \n          <li><a href=\"index.html\">模块代码</a> &raquo;</li>\n        \n      <li>logging</li>\n    \n    \n      <li class=\"wy-breadcrumbs-aside\">\n        \n      </li>\n    \n  </ul>\n\n  \n  <hr/>\n</div>\n          <div role=\"main\" class=\"document\" itemscope=\"itemscope\" itemtype=\"http://schema.org/Article\">\n           <div itemprop=\"articleBody\">\n            \n  <h1>logging 源代码</h1><div class=\"highlight\"><pre>\n<span></span><span class=\"c1\"># Copyright 2001-2016 by Vinay Sajip. All Rights Reserved.</span>\n<span class=\"c1\">#</span>\n<span class=\"c1\"># Permission to use, copy, modify, and distribute this software and its</span>\n<span class=\"c1\"># documentation for any purpose and without fee is hereby granted,</span>\n<span class=\"c1\"># provided that the above copyright notice appear in all copies and that</span>\n<span class=\"c1\"># both that copyright notice and this permission notice appear in</span>\n<span class=\"c1\"># supporting documentation, and that the name of Vinay Sajip</span>\n<span class=\"c1\"># not be used in advertising or publicity pertaining to distribution</span>\n<span class=\"c1\"># of the software without specific, written prior permission.</span>\n<span class=\"c1\"># VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING</span>\n<span class=\"c1\"># ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL</span>\n<span class=\"c1\"># VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR</span>\n<span class=\"c1\"># ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER</span>\n<span class=\"c1\"># IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT</span>\n<span class=\"c1\"># OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.</span>\n\n<span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">Logging package for Python. Based on PEP 282 and comments thereto in</span>\n<span class=\"sd\">comp.lang.python.</span>\n\n<span class=\"sd\">Copyright (C) 2001-2016 Vinay Sajip. All Rights Reserved.</span>\n\n<span class=\"sd\">To use, simply &#39;import logging&#39; and log away!</span>\n<span class=\"sd\">&quot;&quot;&quot;</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">sys</span><span class=\"o\">,</span> <span class=\"nn\">os</span><span class=\"o\">,</span> <span class=\"nn\">time</span><span class=\"o\">,</span> <span class=\"nn\">io</span><span class=\"o\">,</span> <span class=\"nn\">traceback</span><span class=\"o\">,</span> <span class=\"nn\">warnings</span><span class=\"o\">,</span> <span class=\"nn\">weakref</span><span class=\"o\">,</span> <span class=\"nn\">collections</span>\n\n<span class=\"kn\">from</span> <span class=\"nn\">string</span> <span class=\"k\">import</span> <span class=\"n\">Template</span>\n\n<span class=\"n\">__all__</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s1\">&#39;BASIC_FORMAT&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;BufferingFormatter&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;CRITICAL&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;DEBUG&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;ERROR&#39;</span><span class=\"p\">,</span>\n           <span class=\"s1\">&#39;FATAL&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;FileHandler&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;Filter&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;Formatter&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;Handler&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;INFO&#39;</span><span class=\"p\">,</span>\n           <span class=\"s1\">&#39;LogRecord&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;Logger&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;LoggerAdapter&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;NOTSET&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;NullHandler&#39;</span><span class=\"p\">,</span>\n           <span class=\"s1\">&#39;StreamHandler&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;WARN&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;WARNING&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;addLevelName&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;basicConfig&#39;</span><span class=\"p\">,</span>\n           <span class=\"s1\">&#39;captureWarnings&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;critical&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;debug&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;disable&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;error&#39;</span><span class=\"p\">,</span>\n           <span class=\"s1\">&#39;exception&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;fatal&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;getLevelName&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;getLogger&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;getLoggerClass&#39;</span><span class=\"p\">,</span>\n           <span class=\"s1\">&#39;info&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;log&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;makeLogRecord&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;setLoggerClass&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;warn&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;warning&#39;</span><span class=\"p\">,</span>\n           <span class=\"s1\">&#39;getLogRecordFactory&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;setLogRecordFactory&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;lastResort&#39;</span><span class=\"p\">]</span>\n\n<span class=\"k\">try</span><span class=\"p\">:</span>\n    <span class=\"kn\">import</span> <span class=\"nn\">threading</span>\n<span class=\"k\">except</span> <span class=\"ne\">ImportError</span><span class=\"p\">:</span> <span class=\"c1\">#pragma: no cover</span>\n    <span class=\"n\">threading</span> <span class=\"o\">=</span> <span class=\"kc\">None</span>\n\n<span class=\"n\">__author__</span>  <span class=\"o\">=</span> <span class=\"s2\">&quot;Vinay Sajip &lt;vinay_sajip@red-dove.com&gt;&quot;</span>\n<span class=\"n\">__status__</span>  <span class=\"o\">=</span> <span class=\"s2\">&quot;production&quot;</span>\n<span class=\"c1\"># The following module attributes are no longer updated.</span>\n<span class=\"n\">__version__</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;0.5.1.2&quot;</span>\n<span class=\"n\">__date__</span>    <span class=\"o\">=</span> <span class=\"s2\">&quot;07 February 2010&quot;</span>\n\n<span class=\"c1\">#---------------------------------------------------------------------------</span>\n<span class=\"c1\">#   Miscellaneous module data</span>\n<span class=\"c1\">#---------------------------------------------------------------------------</span>\n\n<span class=\"c1\">#</span>\n<span class=\"c1\">#_startTime is used as the base when calculating the relative time of events</span>\n<span class=\"c1\">#</span>\n<span class=\"n\">_startTime</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"o\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n\n<span class=\"c1\">#</span>\n<span class=\"c1\">#raiseExceptions is used to see if exceptions during handling should be</span>\n<span class=\"c1\">#propagated</span>\n<span class=\"c1\">#</span>\n<span class=\"n\">raiseExceptions</span> <span class=\"o\">=</span> <span class=\"kc\">True</span>\n\n<span class=\"c1\">#</span>\n<span class=\"c1\"># If you don&#39;t want threading information in the log, set this to zero</span>\n<span class=\"c1\">#</span>\n<span class=\"n\">logThreads</span> <span class=\"o\">=</span> <span class=\"kc\">True</span>\n\n<span class=\"c1\">#</span>\n<span class=\"c1\"># If you don&#39;t want multiprocessing information in the log, set this to zero</span>\n<span class=\"c1\">#</span>\n<span class=\"n\">logMultiprocessing</span> <span class=\"o\">=</span> <span class=\"kc\">True</span>\n\n<span class=\"c1\">#</span>\n<span class=\"c1\"># If you don&#39;t want process information in the log, set this to zero</span>\n<span class=\"c1\">#</span>\n<span class=\"n\">logProcesses</span> <span class=\"o\">=</span> <span class=\"kc\">True</span>\n\n<span class=\"c1\">#---------------------------------------------------------------------------</span>\n<span class=\"c1\">#   Level related stuff</span>\n<span class=\"c1\">#---------------------------------------------------------------------------</span>\n<span class=\"c1\">#</span>\n<span class=\"c1\"># Default levels and level names, these can be replaced with any positive set</span>\n<span class=\"c1\"># of values having corresponding names. There is a pseudo-level, NOTSET, which</span>\n<span class=\"c1\"># is only really there as a lower limit for user-defined levels. Handlers and</span>\n<span class=\"c1\"># loggers are initialized with NOTSET so that they will log all messages, even</span>\n<span class=\"c1\"># at user-defined levels.</span>\n<span class=\"c1\">#</span>\n\n<span class=\"n\">CRITICAL</span> <span class=\"o\">=</span> <span class=\"mi\">50</span>\n<span class=\"n\">FATAL</span> <span class=\"o\">=</span> <span class=\"n\">CRITICAL</span>\n<span class=\"n\">ERROR</span> <span class=\"o\">=</span> <span class=\"mi\">40</span>\n<span class=\"n\">WARNING</span> <span class=\"o\">=</span> <span class=\"mi\">30</span>\n<span class=\"n\">WARN</span> <span class=\"o\">=</span> <span class=\"n\">WARNING</span>\n<span class=\"n\">INFO</span> <span class=\"o\">=</span> <span class=\"mi\">20</span>\n<span class=\"n\">DEBUG</span> <span class=\"o\">=</span> <span class=\"mi\">10</span>\n<span class=\"n\">NOTSET</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n\n<span class=\"n\">_levelToName</span> <span class=\"o\">=</span> <span class=\"p\">{</span>\n    <span class=\"n\">CRITICAL</span><span class=\"p\">:</span> <span class=\"s1\">&#39;CRITICAL&#39;</span><span class=\"p\">,</span>\n    <span class=\"n\">ERROR</span><span class=\"p\">:</span> <span class=\"s1\">&#39;ERROR&#39;</span><span class=\"p\">,</span>\n    <span class=\"n\">WARNING</span><span class=\"p\">:</span> <span class=\"s1\">&#39;WARNING&#39;</span><span class=\"p\">,</span>\n    <span class=\"n\">INFO</span><span class=\"p\">:</span> <span class=\"s1\">&#39;INFO&#39;</span><span class=\"p\">,</span>\n    <span class=\"n\">DEBUG</span><span class=\"p\">:</span> <span class=\"s1\">&#39;DEBUG&#39;</span><span class=\"p\">,</span>\n    <span class=\"n\">NOTSET</span><span class=\"p\">:</span> <span class=\"s1\">&#39;NOTSET&#39;</span><span class=\"p\">,</span>\n<span class=\"p\">}</span>\n<span class=\"n\">_nameToLevel</span> <span class=\"o\">=</span> <span class=\"p\">{</span>\n    <span class=\"s1\">&#39;CRITICAL&#39;</span><span class=\"p\">:</span> <span class=\"n\">CRITICAL</span><span class=\"p\">,</span>\n    <span class=\"s1\">&#39;ERROR&#39;</span><span class=\"p\">:</span> <span class=\"n\">ERROR</span><span class=\"p\">,</span>\n    <span class=\"s1\">&#39;WARN&#39;</span><span class=\"p\">:</span> <span class=\"n\">WARNING</span><span class=\"p\">,</span>\n    <span class=\"s1\">&#39;WARNING&#39;</span><span class=\"p\">:</span> <span class=\"n\">WARNING</span><span class=\"p\">,</span>\n    <span class=\"s1\">&#39;INFO&#39;</span><span class=\"p\">:</span> <span class=\"n\">INFO</span><span class=\"p\">,</span>\n    <span class=\"s1\">&#39;DEBUG&#39;</span><span class=\"p\">:</span> <span class=\"n\">DEBUG</span><span class=\"p\">,</span>\n    <span class=\"s1\">&#39;NOTSET&#39;</span><span class=\"p\">:</span> <span class=\"n\">NOTSET</span><span class=\"p\">,</span>\n<span class=\"p\">}</span>\n\n<div class=\"viewcode-block\" id=\"getLevelName\"><a class=\"viewcode-back\" href=\"../logging.html#logging.getLevelName\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">getLevelName</span><span class=\"p\">(</span><span class=\"n\">level</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    Return the textual representation of logging level &#39;level&#39;.</span>\n\n<span class=\"sd\">    If the level is one of the predefined levels (CRITICAL, ERROR, WARNING,</span>\n<span class=\"sd\">    INFO, DEBUG) then you get the corresponding string. If you have</span>\n<span class=\"sd\">    associated levels with names using addLevelName then the name you have</span>\n<span class=\"sd\">    associated with &#39;level&#39; is returned.</span>\n\n<span class=\"sd\">    If a numeric value corresponding to one of the defined levels is passed</span>\n<span class=\"sd\">    in, the corresponding string representation is returned.</span>\n\n<span class=\"sd\">    Otherwise, the string &quot;Level %s&quot; % level is returned.</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"c1\"># See Issues #22386 and #27937 for why it&#39;s this way</span>\n    <span class=\"k\">return</span> <span class=\"p\">(</span><span class=\"n\">_levelToName</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">level</span><span class=\"p\">)</span> <span class=\"ow\">or</span> <span class=\"n\">_nameToLevel</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">level</span><span class=\"p\">)</span> <span class=\"ow\">or</span>\n            <span class=\"s2\">&quot;Level </span><span class=\"si\">%s</span><span class=\"s2\">&quot;</span> <span class=\"o\">%</span> <span class=\"n\">level</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"addLevelName\"><a class=\"viewcode-back\" href=\"../logging.html#logging.addLevelName\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">addLevelName</span><span class=\"p\">(</span><span class=\"n\">level</span><span class=\"p\">,</span> <span class=\"n\">levelName</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    Associate &#39;levelName&#39; with &#39;level&#39;.</span>\n\n<span class=\"sd\">    This is used when converting levels to text during message formatting.</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"n\">_acquireLock</span><span class=\"p\">()</span>\n    <span class=\"k\">try</span><span class=\"p\">:</span>    <span class=\"c1\">#unlikely to cause an exception, but you never know...</span>\n        <span class=\"n\">_levelToName</span><span class=\"p\">[</span><span class=\"n\">level</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">levelName</span>\n        <span class=\"n\">_nameToLevel</span><span class=\"p\">[</span><span class=\"n\">levelName</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">level</span>\n    <span class=\"k\">finally</span><span class=\"p\">:</span>\n        <span class=\"n\">_releaseLock</span><span class=\"p\">()</span></div>\n\n<span class=\"k\">if</span> <span class=\"nb\">hasattr</span><span class=\"p\">(</span><span class=\"n\">sys</span><span class=\"p\">,</span> <span class=\"s1\">&#39;_getframe&#39;</span><span class=\"p\">):</span>\n    <span class=\"n\">currentframe</span> <span class=\"o\">=</span> <span class=\"k\">lambda</span><span class=\"p\">:</span> <span class=\"n\">sys</span><span class=\"o\">.</span><span class=\"n\">_getframe</span><span class=\"p\">(</span><span class=\"mi\">3</span><span class=\"p\">)</span>\n<span class=\"k\">else</span><span class=\"p\">:</span> <span class=\"c1\">#pragma: no cover</span>\n    <span class=\"k\">def</span> <span class=\"nf\">currentframe</span><span class=\"p\">():</span>\n        <span class=\"sd\">&quot;&quot;&quot;Return the frame object for the caller&#39;s stack frame.&quot;&quot;&quot;</span>\n        <span class=\"k\">try</span><span class=\"p\">:</span>\n            <span class=\"k\">raise</span> <span class=\"ne\">Exception</span>\n        <span class=\"k\">except</span> <span class=\"ne\">Exception</span><span class=\"p\">:</span>\n            <span class=\"k\">return</span> <span class=\"n\">sys</span><span class=\"o\">.</span><span class=\"n\">exc_info</span><span class=\"p\">()[</span><span class=\"mi\">2</span><span class=\"p\">]</span><span class=\"o\">.</span><span class=\"n\">tb_frame</span><span class=\"o\">.</span><span class=\"n\">f_back</span>\n\n<span class=\"c1\">#</span>\n<span class=\"c1\"># _srcfile is used when walking the stack to check when we&#39;ve got the first</span>\n<span class=\"c1\"># caller stack frame, by skipping frames whose filename is that of this</span>\n<span class=\"c1\"># module&#39;s source. It therefore should contain the filename of this module&#39;s</span>\n<span class=\"c1\"># source file.</span>\n<span class=\"c1\">#</span>\n<span class=\"c1\"># Ordinarily we would use __file__ for this, but frozen modules don&#39;t always</span>\n<span class=\"c1\"># have __file__ set, for some reason (see Issue #21736). Thus, we get the</span>\n<span class=\"c1\"># filename from a handy code object from a function defined in this module.</span>\n<span class=\"c1\"># (There&#39;s no particular reason for picking addLevelName.)</span>\n<span class=\"c1\">#</span>\n\n<span class=\"n\">_srcfile</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">normcase</span><span class=\"p\">(</span><span class=\"n\">addLevelName</span><span class=\"o\">.</span><span class=\"vm\">__code__</span><span class=\"o\">.</span><span class=\"n\">co_filename</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># _srcfile is only used in conjunction with sys._getframe().</span>\n<span class=\"c1\"># To provide compatibility with older versions of Python, set _srcfile</span>\n<span class=\"c1\"># to None if _getframe() is not available; this value will prevent</span>\n<span class=\"c1\"># findCaller() from being called. You can also do this if you want to avoid</span>\n<span class=\"c1\"># the overhead of fetching caller information, even when _getframe() is</span>\n<span class=\"c1\"># available.</span>\n<span class=\"c1\">#if not hasattr(sys, &#39;_getframe&#39;):</span>\n<span class=\"c1\">#    _srcfile = None</span>\n\n\n<span class=\"k\">def</span> <span class=\"nf\">_checkLevel</span><span class=\"p\">(</span><span class=\"n\">level</span><span class=\"p\">):</span>\n    <span class=\"k\">if</span> <span class=\"nb\">isinstance</span><span class=\"p\">(</span><span class=\"n\">level</span><span class=\"p\">,</span> <span class=\"nb\">int</span><span class=\"p\">):</span>\n        <span class=\"n\">rv</span> <span class=\"o\">=</span> <span class=\"n\">level</span>\n    <span class=\"k\">elif</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">level</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"n\">level</span><span class=\"p\">:</span>\n        <span class=\"k\">if</span> <span class=\"n\">level</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"n\">_nameToLevel</span><span class=\"p\">:</span>\n            <span class=\"k\">raise</span> <span class=\"ne\">ValueError</span><span class=\"p\">(</span><span class=\"s2\">&quot;Unknown level: </span><span class=\"si\">%r</span><span class=\"s2\">&quot;</span> <span class=\"o\">%</span> <span class=\"n\">level</span><span class=\"p\">)</span>\n        <span class=\"n\">rv</span> <span class=\"o\">=</span> <span class=\"n\">_nameToLevel</span><span class=\"p\">[</span><span class=\"n\">level</span><span class=\"p\">]</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"k\">raise</span> <span class=\"ne\">TypeError</span><span class=\"p\">(</span><span class=\"s2\">&quot;Level not an integer or a valid string: </span><span class=\"si\">%r</span><span class=\"s2\">&quot;</span> <span class=\"o\">%</span> <span class=\"n\">level</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">rv</span>\n\n<span class=\"c1\">#---------------------------------------------------------------------------</span>\n<span class=\"c1\">#   Thread-related stuff</span>\n<span class=\"c1\">#---------------------------------------------------------------------------</span>\n\n<span class=\"c1\">#</span>\n<span class=\"c1\">#_lock is used to serialize access to shared data structures in this module.</span>\n<span class=\"c1\">#This needs to be an RLock because fileConfig() creates and configures</span>\n<span class=\"c1\">#Handlers, and so might arbitrary user threads. Since Handler code updates the</span>\n<span class=\"c1\">#shared dictionary _handlers, it needs to acquire the lock. But if configuring,</span>\n<span class=\"c1\">#the lock would already have been acquired - so we need an RLock.</span>\n<span class=\"c1\">#The same argument applies to Loggers and Manager.loggerDict.</span>\n<span class=\"c1\">#</span>\n<span class=\"k\">if</span> <span class=\"n\">threading</span><span class=\"p\">:</span>\n    <span class=\"n\">_lock</span> <span class=\"o\">=</span> <span class=\"n\">threading</span><span class=\"o\">.</span><span class=\"n\">RLock</span><span class=\"p\">()</span>\n<span class=\"k\">else</span><span class=\"p\">:</span> <span class=\"c1\">#pragma: no cover</span>\n    <span class=\"n\">_lock</span> <span class=\"o\">=</span> <span class=\"kc\">None</span>\n\n\n<span class=\"k\">def</span> <span class=\"nf\">_acquireLock</span><span class=\"p\">():</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    Acquire the module-level lock for serializing access to shared data.</span>\n\n<span class=\"sd\">    This should be released with _releaseLock().</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"k\">if</span> <span class=\"n\">_lock</span><span class=\"p\">:</span>\n        <span class=\"n\">_lock</span><span class=\"o\">.</span><span class=\"n\">acquire</span><span class=\"p\">()</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">_releaseLock</span><span class=\"p\">():</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    Release the module-level lock acquired by calling _acquireLock().</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"k\">if</span> <span class=\"n\">_lock</span><span class=\"p\">:</span>\n        <span class=\"n\">_lock</span><span class=\"o\">.</span><span class=\"n\">release</span><span class=\"p\">()</span>\n\n<span class=\"c1\">#---------------------------------------------------------------------------</span>\n<span class=\"c1\">#   The logging record</span>\n<span class=\"c1\">#---------------------------------------------------------------------------</span>\n\n<div class=\"viewcode-block\" id=\"LogRecord\"><a class=\"viewcode-back\" href=\"../logging.html#logging.LogRecord\">[文档]</a><span class=\"k\">class</span> <span class=\"nc\">LogRecord</span><span class=\"p\">(</span><span class=\"nb\">object</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    A LogRecord instance represents an event being logged.</span>\n\n<span class=\"sd\">    LogRecord instances are created every time something is logged. They</span>\n<span class=\"sd\">    contain all the information pertinent to the event being logged. The</span>\n<span class=\"sd\">    main information passed in is in msg and args, which are combined</span>\n<span class=\"sd\">    using str(msg) % args to create the message field of the record. The</span>\n<span class=\"sd\">    record also includes information such as when the record was created,</span>\n<span class=\"sd\">    the source line where the logging call was made, and any exception</span>\n<span class=\"sd\">    information to be logged.</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">name</span><span class=\"p\">,</span> <span class=\"n\">level</span><span class=\"p\">,</span> <span class=\"n\">pathname</span><span class=\"p\">,</span> <span class=\"n\">lineno</span><span class=\"p\">,</span>\n                 <span class=\"n\">msg</span><span class=\"p\">,</span> <span class=\"n\">args</span><span class=\"p\">,</span> <span class=\"n\">exc_info</span><span class=\"p\">,</span> <span class=\"n\">func</span><span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">,</span> <span class=\"n\">sinfo</span><span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Initialize a logging record with interesting information.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"n\">ct</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"o\">.</span><span class=\"n\">time</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">name</span> <span class=\"o\">=</span> <span class=\"n\">name</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">msg</span> <span class=\"o\">=</span> <span class=\"n\">msg</span>\n        <span class=\"c1\">#</span>\n        <span class=\"c1\"># The following statement allows passing of a dictionary as a sole</span>\n        <span class=\"c1\"># argument, so that you can do something like</span>\n        <span class=\"c1\">#  logging.debug(&quot;a %(a)d b %(b)s&quot;, {&#39;a&#39;:1, &#39;b&#39;:2})</span>\n        <span class=\"c1\"># Suggested by Stefan Behnel.</span>\n        <span class=\"c1\"># Note that without the test for args[0], we get a problem because</span>\n        <span class=\"c1\"># during formatting, we test to see if the arg is present using</span>\n        <span class=\"c1\"># &#39;if self.args:&#39;. If the event being logged is e.g. &#39;Value is %d&#39;</span>\n        <span class=\"c1\"># and if the passed arg fails &#39;if self.args:&#39; then no formatting</span>\n        <span class=\"c1\"># is done. For example, logger.warning(&#39;Value is %d&#39;, 0) would log</span>\n        <span class=\"c1\"># &#39;Value is %d&#39; instead of &#39;Value is 0&#39;.</span>\n        <span class=\"c1\"># For the use case of passing a dictionary, this should not be a</span>\n        <span class=\"c1\"># problem.</span>\n        <span class=\"c1\"># Issue #21172: a request was made to relax the isinstance check</span>\n        <span class=\"c1\"># to hasattr(args[0], &#39;__getitem__&#39;). However, the docs on string</span>\n        <span class=\"c1\"># formatting still seem to suggest a mapping object is required.</span>\n        <span class=\"c1\"># Thus, while not removing the isinstance check, it does now look</span>\n        <span class=\"c1\"># for collections.Mapping rather than, as before, dict.</span>\n        <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">args</span> <span class=\"ow\">and</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"nb\">isinstance</span><span class=\"p\">(</span><span class=\"n\">args</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">],</span> <span class=\"n\">collections</span><span class=\"o\">.</span><span class=\"n\">Mapping</span><span class=\"p\">)</span>\n            <span class=\"ow\">and</span> <span class=\"n\">args</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]):</span>\n            <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">args</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"n\">args</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">levelname</span> <span class=\"o\">=</span> <span class=\"n\">getLevelName</span><span class=\"p\">(</span><span class=\"n\">level</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">levelno</span> <span class=\"o\">=</span> <span class=\"n\">level</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">pathname</span> <span class=\"o\">=</span> <span class=\"n\">pathname</span>\n        <span class=\"k\">try</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">filename</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">basename</span><span class=\"p\">(</span><span class=\"n\">pathname</span><span class=\"p\">)</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">module</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">splitext</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">filename</span><span class=\"p\">)[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n        <span class=\"k\">except</span> <span class=\"p\">(</span><span class=\"ne\">TypeError</span><span class=\"p\">,</span> <span class=\"ne\">ValueError</span><span class=\"p\">,</span> <span class=\"ne\">AttributeError</span><span class=\"p\">):</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">filename</span> <span class=\"o\">=</span> <span class=\"n\">pathname</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">module</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;Unknown module&quot;</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">exc_info</span> <span class=\"o\">=</span> <span class=\"n\">exc_info</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">exc_text</span> <span class=\"o\">=</span> <span class=\"kc\">None</span>      <span class=\"c1\"># used to cache the traceback text</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">stack_info</span> <span class=\"o\">=</span> <span class=\"n\">sinfo</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">lineno</span> <span class=\"o\">=</span> <span class=\"n\">lineno</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">funcName</span> <span class=\"o\">=</span> <span class=\"n\">func</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">created</span> <span class=\"o\">=</span> <span class=\"n\">ct</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">msecs</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"n\">ct</span> <span class=\"o\">-</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">ct</span><span class=\"p\">))</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">relativeCreated</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">created</span> <span class=\"o\">-</span> <span class=\"n\">_startTime</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"mi\">1000</span>\n        <span class=\"k\">if</span> <span class=\"n\">logThreads</span> <span class=\"ow\">and</span> <span class=\"n\">threading</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">thread</span> <span class=\"o\">=</span> <span class=\"n\">threading</span><span class=\"o\">.</span><span class=\"n\">get_ident</span><span class=\"p\">()</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">threadName</span> <span class=\"o\">=</span> <span class=\"n\">threading</span><span class=\"o\">.</span><span class=\"n\">current_thread</span><span class=\"p\">()</span><span class=\"o\">.</span><span class=\"n\">name</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span> <span class=\"c1\"># pragma: no cover</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">thread</span> <span class=\"o\">=</span> <span class=\"kc\">None</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">threadName</span> <span class=\"o\">=</span> <span class=\"kc\">None</span>\n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">logMultiprocessing</span><span class=\"p\">:</span> <span class=\"c1\"># pragma: no cover</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">processName</span> <span class=\"o\">=</span> <span class=\"kc\">None</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">processName</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;MainProcess&#39;</span>\n            <span class=\"n\">mp</span> <span class=\"o\">=</span> <span class=\"n\">sys</span><span class=\"o\">.</span><span class=\"n\">modules</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;multiprocessing&#39;</span><span class=\"p\">)</span>\n            <span class=\"k\">if</span> <span class=\"n\">mp</span> <span class=\"ow\">is</span> <span class=\"ow\">not</span> <span class=\"kc\">None</span><span class=\"p\">:</span>\n                <span class=\"c1\"># Errors may occur if multiprocessing has not finished loading</span>\n                <span class=\"c1\"># yet - e.g. if a custom import hook causes third-party code</span>\n                <span class=\"c1\"># to run when multiprocessing calls import. See issue 8200</span>\n                <span class=\"c1\"># for an example</span>\n                <span class=\"k\">try</span><span class=\"p\">:</span>\n                    <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">processName</span> <span class=\"o\">=</span> <span class=\"n\">mp</span><span class=\"o\">.</span><span class=\"n\">current_process</span><span class=\"p\">()</span><span class=\"o\">.</span><span class=\"n\">name</span>\n                <span class=\"k\">except</span> <span class=\"ne\">Exception</span><span class=\"p\">:</span> <span class=\"c1\">#pragma: no cover</span>\n                    <span class=\"k\">pass</span>\n        <span class=\"k\">if</span> <span class=\"n\">logProcesses</span> <span class=\"ow\">and</span> <span class=\"nb\">hasattr</span><span class=\"p\">(</span><span class=\"n\">os</span><span class=\"p\">,</span> <span class=\"s1\">&#39;getpid&#39;</span><span class=\"p\">):</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">process</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">getpid</span><span class=\"p\">()</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">process</span> <span class=\"o\">=</span> <span class=\"kc\">None</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">__str__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"s1\">&#39;&lt;LogRecord: </span><span class=\"si\">%s</span><span class=\"s1\">, </span><span class=\"si\">%s</span><span class=\"s1\">, </span><span class=\"si\">%s</span><span class=\"s1\">, </span><span class=\"si\">%s</span><span class=\"s1\">, &quot;</span><span class=\"si\">%s</span><span class=\"s1\">&quot;&gt;&#39;</span><span class=\"o\">%</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">name</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">levelno</span><span class=\"p\">,</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">pathname</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">lineno</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">msg</span><span class=\"p\">)</span>\n\n    <span class=\"fm\">__repr__</span> <span class=\"o\">=</span> <span class=\"fm\">__str__</span>\n\n<div class=\"viewcode-block\" id=\"LogRecord.getMessage\"><a class=\"viewcode-back\" href=\"../logging.html#logging.LogRecord.getMessage\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">getMessage</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Return the message for this LogRecord.</span>\n\n<span class=\"sd\">        Return the message for this LogRecord after merging any user-supplied</span>\n<span class=\"sd\">        arguments with the message.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"n\">msg</span> <span class=\"o\">=</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">msg</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">args</span><span class=\"p\">:</span>\n            <span class=\"n\">msg</span> <span class=\"o\">=</span> <span class=\"n\">msg</span> <span class=\"o\">%</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">args</span>\n        <span class=\"k\">return</span> <span class=\"n\">msg</span></div></div>\n\n<span class=\"c1\">#</span>\n<span class=\"c1\">#   Determine which class to use when instantiating log records.</span>\n<span class=\"c1\">#</span>\n<span class=\"n\">_logRecordFactory</span> <span class=\"o\">=</span> <span class=\"n\">LogRecord</span>\n\n<div class=\"viewcode-block\" id=\"setLogRecordFactory\"><a class=\"viewcode-back\" href=\"../logging.html#logging.setLogRecordFactory\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">setLogRecordFactory</span><span class=\"p\">(</span><span class=\"n\">factory</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    Set the factory to be used when instantiating a log record.</span>\n\n<span class=\"sd\">    :param factory: A callable which will be called to instantiate</span>\n<span class=\"sd\">    a log record.</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"k\">global</span> <span class=\"n\">_logRecordFactory</span>\n    <span class=\"n\">_logRecordFactory</span> <span class=\"o\">=</span> <span class=\"n\">factory</span></div>\n\n<div class=\"viewcode-block\" id=\"getLogRecordFactory\"><a class=\"viewcode-back\" href=\"../logging.html#logging.getLogRecordFactory\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">getLogRecordFactory</span><span class=\"p\">():</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    Return the factory to be used when instantiating a log record.</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n\n    <span class=\"k\">return</span> <span class=\"n\">_logRecordFactory</span></div>\n\n<div class=\"viewcode-block\" id=\"makeLogRecord\"><a class=\"viewcode-back\" href=\"../logging.html#logging.makeLogRecord\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">makeLogRecord</span><span class=\"p\">(</span><span class=\"nb\">dict</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    Make a LogRecord whose attributes are defined by the specified dictionary,</span>\n<span class=\"sd\">    This function is useful for converting a logging event received over</span>\n<span class=\"sd\">    a socket connection (which is sent as a dictionary) into a LogRecord</span>\n<span class=\"sd\">    instance.</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"n\">rv</span> <span class=\"o\">=</span> <span class=\"n\">_logRecordFactory</span><span class=\"p\">(</span><span class=\"kc\">None</span><span class=\"p\">,</span> <span class=\"kc\">None</span><span class=\"p\">,</span> <span class=\"s2\">&quot;&quot;</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"s2\">&quot;&quot;</span><span class=\"p\">,</span> <span class=\"p\">(),</span> <span class=\"kc\">None</span><span class=\"p\">,</span> <span class=\"kc\">None</span><span class=\"p\">)</span>\n    <span class=\"n\">rv</span><span class=\"o\">.</span><span class=\"vm\">__dict__</span><span class=\"o\">.</span><span class=\"n\">update</span><span class=\"p\">(</span><span class=\"nb\">dict</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">rv</span></div>\n\n<span class=\"c1\">#---------------------------------------------------------------------------</span>\n<span class=\"c1\">#   Formatter classes and functions</span>\n<span class=\"c1\">#---------------------------------------------------------------------------</span>\n\n<span class=\"k\">class</span> <span class=\"nc\">PercentStyle</span><span class=\"p\">(</span><span class=\"nb\">object</span><span class=\"p\">):</span>\n\n    <span class=\"n\">default_format</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;</span><span class=\"si\">%(message)s</span><span class=\"s1\">&#39;</span>\n    <span class=\"n\">asctime_format</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;</span><span class=\"si\">%(asctime)s</span><span class=\"s1\">&#39;</span>\n    <span class=\"n\">asctime_search</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;%(asctime)&#39;</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">fmt</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_fmt</span> <span class=\"o\">=</span> <span class=\"n\">fmt</span> <span class=\"ow\">or</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">default_format</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">usesTime</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_fmt</span><span class=\"o\">.</span><span class=\"n\">find</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">asctime_search</span><span class=\"p\">)</span> <span class=\"o\">&gt;=</span> <span class=\"mi\">0</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">format</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">record</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_fmt</span> <span class=\"o\">%</span> <span class=\"n\">record</span><span class=\"o\">.</span><span class=\"vm\">__dict__</span>\n\n<span class=\"k\">class</span> <span class=\"nc\">StrFormatStyle</span><span class=\"p\">(</span><span class=\"n\">PercentStyle</span><span class=\"p\">):</span>\n    <span class=\"n\">default_format</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;</span><span class=\"si\">{message}</span><span class=\"s1\">&#39;</span>\n    <span class=\"n\">asctime_format</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;</span><span class=\"si\">{asctime}</span><span class=\"s1\">&#39;</span>\n    <span class=\"n\">asctime_search</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;{asctime&#39;</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">format</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">record</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_fmt</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"o\">**</span><span class=\"n\">record</span><span class=\"o\">.</span><span class=\"vm\">__dict__</span><span class=\"p\">)</span>\n\n\n<span class=\"k\">class</span> <span class=\"nc\">StringTemplateStyle</span><span class=\"p\">(</span><span class=\"n\">PercentStyle</span><span class=\"p\">):</span>\n    <span class=\"n\">default_format</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;$</span><span class=\"si\">{message}</span><span class=\"s1\">&#39;</span>\n    <span class=\"n\">asctime_format</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;$</span><span class=\"si\">{asctime}</span><span class=\"s1\">&#39;</span>\n    <span class=\"n\">asctime_search</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;$</span><span class=\"si\">{asctime}</span><span class=\"s1\">&#39;</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">fmt</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_fmt</span> <span class=\"o\">=</span> <span class=\"n\">fmt</span> <span class=\"ow\">or</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">default_format</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_tpl</span> <span class=\"o\">=</span> <span class=\"n\">Template</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_fmt</span><span class=\"p\">)</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">usesTime</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"n\">fmt</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_fmt</span>\n        <span class=\"k\">return</span> <span class=\"n\">fmt</span><span class=\"o\">.</span><span class=\"n\">find</span><span class=\"p\">(</span><span class=\"s1\">&#39;$asctime&#39;</span><span class=\"p\">)</span> <span class=\"o\">&gt;=</span> <span class=\"mi\">0</span> <span class=\"ow\">or</span> <span class=\"n\">fmt</span><span class=\"o\">.</span><span class=\"n\">find</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">asctime_format</span><span class=\"p\">)</span> <span class=\"o\">&gt;=</span> <span class=\"mi\">0</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">format</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">record</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_tpl</span><span class=\"o\">.</span><span class=\"n\">substitute</span><span class=\"p\">(</span><span class=\"o\">**</span><span class=\"n\">record</span><span class=\"o\">.</span><span class=\"vm\">__dict__</span><span class=\"p\">)</span>\n\n<span class=\"n\">BASIC_FORMAT</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;</span><span class=\"si\">%(levelname)s</span><span class=\"s2\">:</span><span class=\"si\">%(name)s</span><span class=\"s2\">:</span><span class=\"si\">%(message)s</span><span class=\"s2\">&quot;</span>\n\n<span class=\"n\">_STYLES</span> <span class=\"o\">=</span> <span class=\"p\">{</span>\n    <span class=\"s1\">&#39;%&#39;</span><span class=\"p\">:</span> <span class=\"p\">(</span><span class=\"n\">PercentStyle</span><span class=\"p\">,</span> <span class=\"n\">BASIC_FORMAT</span><span class=\"p\">),</span>\n    <span class=\"s1\">&#39;{&#39;</span><span class=\"p\">:</span> <span class=\"p\">(</span><span class=\"n\">StrFormatStyle</span><span class=\"p\">,</span> <span class=\"s1\">&#39;</span><span class=\"si\">{levelname}</span><span class=\"s1\">:</span><span class=\"si\">{name}</span><span class=\"s1\">:</span><span class=\"si\">{message}</span><span class=\"s1\">&#39;</span><span class=\"p\">),</span>\n    <span class=\"s1\">&#39;$&#39;</span><span class=\"p\">:</span> <span class=\"p\">(</span><span class=\"n\">StringTemplateStyle</span><span class=\"p\">,</span> <span class=\"s1\">&#39;$</span><span class=\"si\">{levelname}</span><span class=\"s1\">:$</span><span class=\"si\">{name}</span><span class=\"s1\">:$</span><span class=\"si\">{message}</span><span class=\"s1\">&#39;</span><span class=\"p\">),</span>\n<span class=\"p\">}</span>\n\n<div class=\"viewcode-block\" id=\"Formatter\"><a class=\"viewcode-back\" href=\"../logging.html#logging.Formatter\">[文档]</a><span class=\"k\">class</span> <span class=\"nc\">Formatter</span><span class=\"p\">(</span><span class=\"nb\">object</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    Formatter instances are used to convert a LogRecord to text.</span>\n\n<span class=\"sd\">    Formatters need to know how a LogRecord is constructed. They are</span>\n<span class=\"sd\">    responsible for converting a LogRecord to (usually) a string which can</span>\n<span class=\"sd\">    be interpreted by either a human or an external system. The base Formatter</span>\n<span class=\"sd\">    allows a formatting string to be specified. If none is supplied, the</span>\n<span class=\"sd\">    default value of &quot;%s(message)&quot; is used.</span>\n\n<span class=\"sd\">    The Formatter can be initialized with a format string which makes use of</span>\n<span class=\"sd\">    knowledge of the LogRecord attributes - e.g. the default value mentioned</span>\n<span class=\"sd\">    above makes use of the fact that the user&#39;s message and arguments are pre-</span>\n<span class=\"sd\">    formatted into a LogRecord&#39;s message attribute. Currently, the useful</span>\n<span class=\"sd\">    attributes in a LogRecord are described by:</span>\n\n<span class=\"sd\">    %(name)s            Name of the logger (logging channel)</span>\n<span class=\"sd\">    %(levelno)s         Numeric logging level for the message (DEBUG, INFO,</span>\n<span class=\"sd\">                        WARNING, ERROR, CRITICAL)</span>\n<span class=\"sd\">    %(levelname)s       Text logging level for the message (&quot;DEBUG&quot;, &quot;INFO&quot;,</span>\n<span class=\"sd\">                        &quot;WARNING&quot;, &quot;ERROR&quot;, &quot;CRITICAL&quot;)</span>\n<span class=\"sd\">    %(pathname)s        Full pathname of the source file where the logging</span>\n<span class=\"sd\">                        call was issued (if available)</span>\n<span class=\"sd\">    %(filename)s        Filename portion of pathname</span>\n<span class=\"sd\">    %(module)s          Module (name portion of filename)</span>\n<span class=\"sd\">    %(lineno)d          Source line number where the logging call was issued</span>\n<span class=\"sd\">                        (if available)</span>\n<span class=\"sd\">    %(funcName)s        Function name</span>\n<span class=\"sd\">    %(created)f         Time when the LogRecord was created (time.time()</span>\n<span class=\"sd\">                        return value)</span>\n<span class=\"sd\">    %(asctime)s         Textual time when the LogRecord was created</span>\n<span class=\"sd\">    %(msecs)d           Millisecond portion of the creation time</span>\n<span class=\"sd\">    %(relativeCreated)d Time in milliseconds when the LogRecord was created,</span>\n<span class=\"sd\">                        relative to the time the logging module was loaded</span>\n<span class=\"sd\">                        (typically at application startup time)</span>\n<span class=\"sd\">    %(thread)d          Thread ID (if available)</span>\n<span class=\"sd\">    %(threadName)s      Thread name (if available)</span>\n<span class=\"sd\">    %(process)d         Process ID (if available)</span>\n<span class=\"sd\">    %(message)s         The result of record.getMessage(), computed just as</span>\n<span class=\"sd\">                        the record is emitted</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n\n    <span class=\"n\">converter</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"o\">.</span><span class=\"n\">localtime</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">fmt</span><span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">,</span> <span class=\"n\">datefmt</span><span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">,</span> <span class=\"n\">style</span><span class=\"o\">=</span><span class=\"s1\">&#39;%&#39;</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Initialize the formatter with specified format strings.</span>\n\n<span class=\"sd\">        Initialize the formatter either with the specified format string, or a</span>\n<span class=\"sd\">        default as described above. Allow for specialized date formatting with</span>\n<span class=\"sd\">        the optional datefmt argument (if omitted, you get the ISO8601 format).</span>\n\n<span class=\"sd\">        Use a style parameter of &#39;%&#39;, &#39;{&#39; or &#39;$&#39; to specify that you want to</span>\n<span class=\"sd\">        use one of %-formatting, :meth:`str.format` (``{}``) formatting or</span>\n<span class=\"sd\">        :class:`string.Template` formatting in your format string.</span>\n\n<span class=\"sd\">        .. versionchanged:: 3.2</span>\n<span class=\"sd\">           Added the ``style`` parameter.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"k\">if</span> <span class=\"n\">style</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"n\">_STYLES</span><span class=\"p\">:</span>\n            <span class=\"k\">raise</span> <span class=\"ne\">ValueError</span><span class=\"p\">(</span><span class=\"s1\">&#39;Style must be one of: </span><span class=\"si\">%s</span><span class=\"s1\">&#39;</span> <span class=\"o\">%</span> <span class=\"s1\">&#39;,&#39;</span><span class=\"o\">.</span><span class=\"n\">join</span><span class=\"p\">(</span>\n                             <span class=\"n\">_STYLES</span><span class=\"o\">.</span><span class=\"n\">keys</span><span class=\"p\">()))</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_style</span> <span class=\"o\">=</span> <span class=\"n\">_STYLES</span><span class=\"p\">[</span><span class=\"n\">style</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">](</span><span class=\"n\">fmt</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_fmt</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_style</span><span class=\"o\">.</span><span class=\"n\">_fmt</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">datefmt</span> <span class=\"o\">=</span> <span class=\"n\">datefmt</span>\n\n    <span class=\"n\">default_time_format</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;%Y-%m-</span><span class=\"si\">%d</span><span class=\"s1\"> %H:%M:%S&#39;</span>\n    <span class=\"n\">default_msec_format</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;</span><span class=\"si\">%s</span><span class=\"s1\">,</span><span class=\"si\">%03d</span><span class=\"s1\">&#39;</span>\n\n<div class=\"viewcode-block\" id=\"Formatter.formatTime\"><a class=\"viewcode-back\" href=\"../logging.html#logging.Formatter.formatTime\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">formatTime</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">record</span><span class=\"p\">,</span> <span class=\"n\">datefmt</span><span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Return the creation time of the specified LogRecord as formatted text.</span>\n\n<span class=\"sd\">        This method should be called from format() by a formatter which</span>\n<span class=\"sd\">        wants to make use of a formatted time. This method can be overridden</span>\n<span class=\"sd\">        in formatters to provide for any specific requirement, but the</span>\n<span class=\"sd\">        basic behaviour is as follows: if datefmt (a string) is specified,</span>\n<span class=\"sd\">        it is used with time.strftime() to format the creation time of the</span>\n<span class=\"sd\">        record. Otherwise, the ISO8601 format is used. The resulting</span>\n<span class=\"sd\">        string is returned. This function uses a user-configurable function</span>\n<span class=\"sd\">        to convert the creation time to a tuple. By default, time.localtime()</span>\n<span class=\"sd\">        is used; to change this for a particular formatter instance, set the</span>\n<span class=\"sd\">        &#39;converter&#39; attribute to a function with the same signature as</span>\n<span class=\"sd\">        time.localtime() or time.gmtime(). To change it for all formatters,</span>\n<span class=\"sd\">        for example if you want all logging times to be shown in GMT,</span>\n<span class=\"sd\">        set the &#39;converter&#39; attribute in the Formatter class.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"n\">ct</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">converter</span><span class=\"p\">(</span><span class=\"n\">record</span><span class=\"o\">.</span><span class=\"n\">created</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">datefmt</span><span class=\"p\">:</span>\n            <span class=\"n\">s</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"o\">.</span><span class=\"n\">strftime</span><span class=\"p\">(</span><span class=\"n\">datefmt</span><span class=\"p\">,</span> <span class=\"n\">ct</span><span class=\"p\">)</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"n\">t</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"o\">.</span><span class=\"n\">strftime</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">default_time_format</span><span class=\"p\">,</span> <span class=\"n\">ct</span><span class=\"p\">)</span>\n            <span class=\"n\">s</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">default_msec_format</span> <span class=\"o\">%</span> <span class=\"p\">(</span><span class=\"n\">t</span><span class=\"p\">,</span> <span class=\"n\">record</span><span class=\"o\">.</span><span class=\"n\">msecs</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span> <span class=\"n\">s</span></div>\n\n<div class=\"viewcode-block\" id=\"Formatter.formatException\"><a class=\"viewcode-back\" href=\"../logging.html#logging.Formatter.formatException\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">formatException</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">ei</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Format and return the specified exception information as a string.</span>\n\n<span class=\"sd\">        This default implementation just uses</span>\n<span class=\"sd\">        traceback.print_exception()</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"n\">sio</span> <span class=\"o\">=</span> <span class=\"n\">io</span><span class=\"o\">.</span><span class=\"n\">StringIO</span><span class=\"p\">()</span>\n        <span class=\"n\">tb</span> <span class=\"o\">=</span> <span class=\"n\">ei</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">]</span>\n        <span class=\"c1\"># See issues #9427, #1553375. Commented out for now.</span>\n        <span class=\"c1\">#if getattr(self, &#39;fullstack&#39;, False):</span>\n        <span class=\"c1\">#    traceback.print_stack(tb.tb_frame.f_back, file=sio)</span>\n        <span class=\"n\">traceback</span><span class=\"o\">.</span><span class=\"n\">print_exception</span><span class=\"p\">(</span><span class=\"n\">ei</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">],</span> <span class=\"n\">ei</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">],</span> <span class=\"n\">tb</span><span class=\"p\">,</span> <span class=\"kc\">None</span><span class=\"p\">,</span> <span class=\"n\">sio</span><span class=\"p\">)</span>\n        <span class=\"n\">s</span> <span class=\"o\">=</span> <span class=\"n\">sio</span><span class=\"o\">.</span><span class=\"n\">getvalue</span><span class=\"p\">()</span>\n        <span class=\"n\">sio</span><span class=\"o\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"n\">s</span><span class=\"p\">[</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">:]</span> <span class=\"o\">==</span> <span class=\"s2\">&quot;</span><span class=\"se\">\\n</span><span class=\"s2\">&quot;</span><span class=\"p\">:</span>\n            <span class=\"n\">s</span> <span class=\"o\">=</span> <span class=\"n\">s</span><span class=\"p\">[:</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n        <span class=\"k\">return</span> <span class=\"n\">s</span></div>\n\n<div class=\"viewcode-block\" id=\"Formatter.usesTime\"><a class=\"viewcode-back\" href=\"../logging.html#logging.Formatter.usesTime\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">usesTime</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Check if the format uses the creation time of the record.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"k\">return</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_style</span><span class=\"o\">.</span><span class=\"n\">usesTime</span><span class=\"p\">()</span></div>\n\n<div class=\"viewcode-block\" id=\"Formatter.formatMessage\"><a class=\"viewcode-back\" href=\"../logging.html#logging.Formatter.formatMessage\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">formatMessage</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">record</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_style</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">record</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"Formatter.formatStack\"><a class=\"viewcode-back\" href=\"../logging.html#logging.Formatter.formatStack\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">formatStack</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">stack_info</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        This method is provided as an extension point for specialized</span>\n<span class=\"sd\">        formatting of stack information.</span>\n\n<span class=\"sd\">        The input data is a string as returned from a call to</span>\n<span class=\"sd\">        :func:`traceback.print_stack`, but with the last trailing newline</span>\n<span class=\"sd\">        removed.</span>\n\n<span class=\"sd\">        The base implementation just returns the value passed in.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"k\">return</span> <span class=\"n\">stack_info</span></div>\n\n<div class=\"viewcode-block\" id=\"Formatter.format\"><a class=\"viewcode-back\" href=\"../logging.html#logging.Formatter.format\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">format</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">record</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Format the specified record as text.</span>\n\n<span class=\"sd\">        The record&#39;s attribute dictionary is used as the operand to a</span>\n<span class=\"sd\">        string formatting operation which yields the returned string.</span>\n<span class=\"sd\">        Before formatting the dictionary, a couple of preparatory steps</span>\n<span class=\"sd\">        are carried out. The message attribute of the record is computed</span>\n<span class=\"sd\">        using LogRecord.getMessage(). If the formatting string uses the</span>\n<span class=\"sd\">        time (as determined by a call to usesTime(), formatTime() is</span>\n<span class=\"sd\">        called to format the event time. If there is exception information,</span>\n<span class=\"sd\">        it is formatted using formatException() and appended to the message.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"n\">record</span><span class=\"o\">.</span><span class=\"n\">message</span> <span class=\"o\">=</span> <span class=\"n\">record</span><span class=\"o\">.</span><span class=\"n\">getMessage</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">usesTime</span><span class=\"p\">():</span>\n            <span class=\"n\">record</span><span class=\"o\">.</span><span class=\"n\">asctime</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">formatTime</span><span class=\"p\">(</span><span class=\"n\">record</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">datefmt</span><span class=\"p\">)</span>\n        <span class=\"n\">s</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">formatMessage</span><span class=\"p\">(</span><span class=\"n\">record</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">record</span><span class=\"o\">.</span><span class=\"n\">exc_info</span><span class=\"p\">:</span>\n            <span class=\"c1\"># Cache the traceback text to avoid converting it multiple times</span>\n            <span class=\"c1\"># (it&#39;s constant anyway)</span>\n            <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">record</span><span class=\"o\">.</span><span class=\"n\">exc_text</span><span class=\"p\">:</span>\n                <span class=\"n\">record</span><span class=\"o\">.</span><span class=\"n\">exc_text</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">formatException</span><span class=\"p\">(</span><span class=\"n\">record</span><span class=\"o\">.</span><span class=\"n\">exc_info</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">record</span><span class=\"o\">.</span><span class=\"n\">exc_text</span><span class=\"p\">:</span>\n            <span class=\"k\">if</span> <span class=\"n\">s</span><span class=\"p\">[</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">:]</span> <span class=\"o\">!=</span> <span class=\"s2\">&quot;</span><span class=\"se\">\\n</span><span class=\"s2\">&quot;</span><span class=\"p\">:</span>\n                <span class=\"n\">s</span> <span class=\"o\">=</span> <span class=\"n\">s</span> <span class=\"o\">+</span> <span class=\"s2\">&quot;</span><span class=\"se\">\\n</span><span class=\"s2\">&quot;</span>\n            <span class=\"n\">s</span> <span class=\"o\">=</span> <span class=\"n\">s</span> <span class=\"o\">+</span> <span class=\"n\">record</span><span class=\"o\">.</span><span class=\"n\">exc_text</span>\n        <span class=\"k\">if</span> <span class=\"n\">record</span><span class=\"o\">.</span><span class=\"n\">stack_info</span><span class=\"p\">:</span>\n            <span class=\"k\">if</span> <span class=\"n\">s</span><span class=\"p\">[</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">:]</span> <span class=\"o\">!=</span> <span class=\"s2\">&quot;</span><span class=\"se\">\\n</span><span class=\"s2\">&quot;</span><span class=\"p\">:</span>\n                <span class=\"n\">s</span> <span class=\"o\">=</span> <span class=\"n\">s</span> <span class=\"o\">+</span> <span class=\"s2\">&quot;</span><span class=\"se\">\\n</span><span class=\"s2\">&quot;</span>\n            <span class=\"n\">s</span> <span class=\"o\">=</span> <span class=\"n\">s</span> <span class=\"o\">+</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">formatStack</span><span class=\"p\">(</span><span class=\"n\">record</span><span class=\"o\">.</span><span class=\"n\">stack_info</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span> <span class=\"n\">s</span></div></div>\n\n<span class=\"c1\">#</span>\n<span class=\"c1\">#   The default formatter to use when no other is specified</span>\n<span class=\"c1\">#</span>\n<span class=\"n\">_defaultFormatter</span> <span class=\"o\">=</span> <span class=\"n\">Formatter</span><span class=\"p\">()</span>\n\n<div class=\"viewcode-block\" id=\"BufferingFormatter\"><a class=\"viewcode-back\" href=\"../logging.html#logging.BufferingFormatter\">[文档]</a><span class=\"k\">class</span> <span class=\"nc\">BufferingFormatter</span><span class=\"p\">(</span><span class=\"nb\">object</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    A formatter suitable for formatting a number of records.</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">linefmt</span><span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Optionally specify a formatter which will be used to format each</span>\n<span class=\"sd\">        individual record.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"k\">if</span> <span class=\"n\">linefmt</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">linefmt</span> <span class=\"o\">=</span> <span class=\"n\">linefmt</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">linefmt</span> <span class=\"o\">=</span> <span class=\"n\">_defaultFormatter</span>\n\n<div class=\"viewcode-block\" id=\"BufferingFormatter.formatHeader\"><a class=\"viewcode-back\" href=\"../logging.html#logging.BufferingFormatter.formatHeader\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">formatHeader</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">records</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Return the header string for the specified records.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"k\">return</span> <span class=\"s2\">&quot;&quot;</span></div>\n\n<div class=\"viewcode-block\" id=\"BufferingFormatter.formatFooter\"><a class=\"viewcode-back\" href=\"../logging.html#logging.BufferingFormatter.formatFooter\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">formatFooter</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">records</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Return the footer string for the specified records.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"k\">return</span> <span class=\"s2\">&quot;&quot;</span></div>\n\n<div class=\"viewcode-block\" id=\"BufferingFormatter.format\"><a class=\"viewcode-back\" href=\"../logging.html#logging.BufferingFormatter.format\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">format</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">records</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Format the specified records and return the result as a string.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"n\">rv</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;&quot;</span>\n        <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">records</span><span class=\"p\">)</span> <span class=\"o\">&gt;</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"n\">rv</span> <span class=\"o\">=</span> <span class=\"n\">rv</span> <span class=\"o\">+</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">formatHeader</span><span class=\"p\">(</span><span class=\"n\">records</span><span class=\"p\">)</span>\n            <span class=\"k\">for</span> <span class=\"n\">record</span> <span class=\"ow\">in</span> <span class=\"n\">records</span><span class=\"p\">:</span>\n                <span class=\"n\">rv</span> <span class=\"o\">=</span> <span class=\"n\">rv</span> <span class=\"o\">+</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">linefmt</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">record</span><span class=\"p\">)</span>\n            <span class=\"n\">rv</span> <span class=\"o\">=</span> <span class=\"n\">rv</span> <span class=\"o\">+</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">formatFooter</span><span class=\"p\">(</span><span class=\"n\">records</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span> <span class=\"n\">rv</span></div></div>\n\n<span class=\"c1\">#---------------------------------------------------------------------------</span>\n<span class=\"c1\">#   Filter classes and functions</span>\n<span class=\"c1\">#---------------------------------------------------------------------------</span>\n\n<div class=\"viewcode-block\" id=\"Filter\"><a class=\"viewcode-back\" href=\"../logging.html#logging.Filter\">[文档]</a><span class=\"k\">class</span> <span class=\"nc\">Filter</span><span class=\"p\">(</span><span class=\"nb\">object</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    Filter instances are used to perform arbitrary filtering of LogRecords.</span>\n\n<span class=\"sd\">    Loggers and Handlers can optionally use Filter instances to filter</span>\n<span class=\"sd\">    records as desired. The base filter class only allows events which are</span>\n<span class=\"sd\">    below a certain point in the logger hierarchy. For example, a filter</span>\n<span class=\"sd\">    initialized with &quot;A.B&quot; will allow events logged by loggers &quot;A.B&quot;,</span>\n<span class=\"sd\">    &quot;A.B.C&quot;, &quot;A.B.C.D&quot;, &quot;A.B.D&quot; etc. but not &quot;A.BB&quot;, &quot;B.A.B&quot; etc. If</span>\n<span class=\"sd\">    initialized with the empty string, all events are passed.</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">name</span><span class=\"o\">=</span><span class=\"s1\">&#39;&#39;</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Initialize a filter.</span>\n\n<span class=\"sd\">        Initialize with the name of the logger which, together with its</span>\n<span class=\"sd\">        children, will have its events allowed through the filter. If no</span>\n<span class=\"sd\">        name is specified, allow every event.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">name</span> <span class=\"o\">=</span> <span class=\"n\">name</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">nlen</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">name</span><span class=\"p\">)</span>\n\n<div class=\"viewcode-block\" id=\"Filter.filter\"><a class=\"viewcode-back\" href=\"../logging.html#logging.Filter.filter\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">filter</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">record</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Determine if the specified record is to be logged.</span>\n\n<span class=\"sd\">        Is the specified record to be logged? Returns 0 for no, nonzero for</span>\n<span class=\"sd\">        yes. If deemed appropriate, the record may be modified in-place.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">nlen</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"k\">return</span> <span class=\"kc\">True</span>\n        <span class=\"k\">elif</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">name</span> <span class=\"o\">==</span> <span class=\"n\">record</span><span class=\"o\">.</span><span class=\"n\">name</span><span class=\"p\">:</span>\n            <span class=\"k\">return</span> <span class=\"kc\">True</span>\n        <span class=\"k\">elif</span> <span class=\"n\">record</span><span class=\"o\">.</span><span class=\"n\">name</span><span class=\"o\">.</span><span class=\"n\">find</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">name</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">nlen</span><span class=\"p\">)</span> <span class=\"o\">!=</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"k\">return</span> <span class=\"kc\">False</span>\n        <span class=\"k\">return</span> <span class=\"p\">(</span><span class=\"n\">record</span><span class=\"o\">.</span><span class=\"n\">name</span><span class=\"p\">[</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">nlen</span><span class=\"p\">]</span> <span class=\"o\">==</span> <span class=\"s2\">&quot;.&quot;</span><span class=\"p\">)</span></div></div>\n\n<span class=\"k\">class</span> <span class=\"nc\">Filterer</span><span class=\"p\">(</span><span class=\"nb\">object</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    A base class for loggers and handlers which allows them to share</span>\n<span class=\"sd\">    common code.</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Initialize the list of filters to be an empty list.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">filters</span> <span class=\"o\">=</span> <span class=\"p\">[]</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">addFilter</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"nb\">filter</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Add the specified filter to this handler.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"p\">(</span><span class=\"nb\">filter</span> <span class=\"ow\">in</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">filters</span><span class=\"p\">):</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">filters</span><span class=\"o\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"nb\">filter</span><span class=\"p\">)</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">removeFilter</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"nb\">filter</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Remove the specified filter from this handler.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"k\">if</span> <span class=\"nb\">filter</span> <span class=\"ow\">in</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">filters</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">filters</span><span class=\"o\">.</span><span class=\"n\">remove</span><span class=\"p\">(</span><span class=\"nb\">filter</span><span class=\"p\">)</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">filter</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">record</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Determine if a record is loggable by consulting all the filters.</span>\n\n<span class=\"sd\">        The default is to allow the record to be logged; any filter can veto</span>\n<span class=\"sd\">        this and the record is then dropped. Returns a zero value if a record</span>\n<span class=\"sd\">        is to be dropped, else non-zero.</span>\n\n<span class=\"sd\">        .. versionchanged:: 3.2</span>\n\n<span class=\"sd\">           Allow filters to be just callables.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"n\">rv</span> <span class=\"o\">=</span> <span class=\"kc\">True</span>\n        <span class=\"k\">for</span> <span class=\"n\">f</span> <span class=\"ow\">in</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">filters</span><span class=\"p\">:</span>\n            <span class=\"k\">if</span> <span class=\"nb\">hasattr</span><span class=\"p\">(</span><span class=\"n\">f</span><span class=\"p\">,</span> <span class=\"s1\">&#39;filter&#39;</span><span class=\"p\">):</span>\n                <span class=\"n\">result</span> <span class=\"o\">=</span> <span class=\"n\">f</span><span class=\"o\">.</span><span class=\"n\">filter</span><span class=\"p\">(</span><span class=\"n\">record</span><span class=\"p\">)</span>\n            <span class=\"k\">else</span><span class=\"p\">:</span>\n                <span class=\"n\">result</span> <span class=\"o\">=</span> <span class=\"n\">f</span><span class=\"p\">(</span><span class=\"n\">record</span><span class=\"p\">)</span> <span class=\"c1\"># assume callable - will raise if not</span>\n            <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">result</span><span class=\"p\">:</span>\n                <span class=\"n\">rv</span> <span class=\"o\">=</span> <span class=\"kc\">False</span>\n                <span class=\"k\">break</span>\n        <span class=\"k\">return</span> <span class=\"n\">rv</span>\n\n<span class=\"c1\">#---------------------------------------------------------------------------</span>\n<span class=\"c1\">#   Handler classes and functions</span>\n<span class=\"c1\">#---------------------------------------------------------------------------</span>\n\n<span class=\"n\">_handlers</span> <span class=\"o\">=</span> <span class=\"n\">weakref</span><span class=\"o\">.</span><span class=\"n\">WeakValueDictionary</span><span class=\"p\">()</span>  <span class=\"c1\">#map of handler names to handlers</span>\n<span class=\"n\">_handlerList</span> <span class=\"o\">=</span> <span class=\"p\">[]</span> <span class=\"c1\"># added to allow handlers to be removed in reverse of order initialized</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">_removeHandlerRef</span><span class=\"p\">(</span><span class=\"n\">wr</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    Remove a handler reference from the internal cleanup list.</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"c1\"># This function can be called during module teardown, when globals are</span>\n    <span class=\"c1\"># set to None. It can also be called from another thread. So we need to</span>\n    <span class=\"c1\"># pre-emptively grab the necessary globals and check if they&#39;re None,</span>\n    <span class=\"c1\"># to prevent race conditions and failures during interpreter shutdown.</span>\n    <span class=\"n\">acquire</span><span class=\"p\">,</span> <span class=\"n\">release</span><span class=\"p\">,</span> <span class=\"n\">handlers</span> <span class=\"o\">=</span> <span class=\"n\">_acquireLock</span><span class=\"p\">,</span> <span class=\"n\">_releaseLock</span><span class=\"p\">,</span> <span class=\"n\">_handlerList</span>\n    <span class=\"k\">if</span> <span class=\"n\">acquire</span> <span class=\"ow\">and</span> <span class=\"n\">release</span> <span class=\"ow\">and</span> <span class=\"n\">handlers</span><span class=\"p\">:</span>\n        <span class=\"n\">acquire</span><span class=\"p\">()</span>\n        <span class=\"k\">try</span><span class=\"p\">:</span>\n            <span class=\"k\">if</span> <span class=\"n\">wr</span> <span class=\"ow\">in</span> <span class=\"n\">handlers</span><span class=\"p\">:</span>\n                <span class=\"n\">handlers</span><span class=\"o\">.</span><span class=\"n\">remove</span><span class=\"p\">(</span><span class=\"n\">wr</span><span class=\"p\">)</span>\n        <span class=\"k\">finally</span><span class=\"p\">:</span>\n            <span class=\"n\">release</span><span class=\"p\">()</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">_addHandlerRef</span><span class=\"p\">(</span><span class=\"n\">handler</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    Add a handler to the internal cleanup list using a weak reference.</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"n\">_acquireLock</span><span class=\"p\">()</span>\n    <span class=\"k\">try</span><span class=\"p\">:</span>\n        <span class=\"n\">_handlerList</span><span class=\"o\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">weakref</span><span class=\"o\">.</span><span class=\"n\">ref</span><span class=\"p\">(</span><span class=\"n\">handler</span><span class=\"p\">,</span> <span class=\"n\">_removeHandlerRef</span><span class=\"p\">))</span>\n    <span class=\"k\">finally</span><span class=\"p\">:</span>\n        <span class=\"n\">_releaseLock</span><span class=\"p\">()</span>\n\n<div class=\"viewcode-block\" id=\"Handler\"><a class=\"viewcode-back\" href=\"../logging.html#logging.Handler\">[文档]</a><span class=\"k\">class</span> <span class=\"nc\">Handler</span><span class=\"p\">(</span><span class=\"n\">Filterer</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    Handler instances dispatch logging events to specific destinations.</span>\n\n<span class=\"sd\">    The base handler class. Acts as a placeholder which defines the Handler</span>\n<span class=\"sd\">    interface. Handlers can optionally use Formatter instances to format</span>\n<span class=\"sd\">    records as desired. By default, no formatter is specified; in this case,</span>\n<span class=\"sd\">    the &#39;raw&#39; message as determined by record.message is logged.</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">level</span><span class=\"o\">=</span><span class=\"n\">NOTSET</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Initializes the instance - basically setting the formatter to None</span>\n<span class=\"sd\">        and the filter list to empty.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"n\">Filterer</span><span class=\"o\">.</span><span class=\"fm\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_name</span> <span class=\"o\">=</span> <span class=\"kc\">None</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">level</span> <span class=\"o\">=</span> <span class=\"n\">_checkLevel</span><span class=\"p\">(</span><span class=\"n\">level</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">formatter</span> <span class=\"o\">=</span> <span class=\"kc\">None</span>\n        <span class=\"c1\"># Add the handler to the global _handlerList (for cleanup on shutdown)</span>\n        <span class=\"n\">_addHandlerRef</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">createLock</span><span class=\"p\">()</span>\n\n<div class=\"viewcode-block\" id=\"Handler.get_name\"><a class=\"viewcode-back\" href=\"../logging.html#logging.Handler.get_name\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">get_name</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_name</span></div>\n\n<div class=\"viewcode-block\" id=\"Handler.set_name\"><a class=\"viewcode-back\" href=\"../logging.html#logging.Handler.set_name\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">set_name</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">name</span><span class=\"p\">):</span>\n        <span class=\"n\">_acquireLock</span><span class=\"p\">()</span>\n        <span class=\"k\">try</span><span class=\"p\">:</span>\n            <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_name</span> <span class=\"ow\">in</span> <span class=\"n\">_handlers</span><span class=\"p\">:</span>\n                <span class=\"k\">del</span> <span class=\"n\">_handlers</span><span class=\"p\">[</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_name</span><span class=\"p\">]</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_name</span> <span class=\"o\">=</span> <span class=\"n\">name</span>\n            <span class=\"k\">if</span> <span class=\"n\">name</span><span class=\"p\">:</span>\n                <span class=\"n\">_handlers</span><span class=\"p\">[</span><span class=\"n\">name</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"bp\">self</span>\n        <span class=\"k\">finally</span><span class=\"p\">:</span>\n            <span class=\"n\">_releaseLock</span><span class=\"p\">()</span></div>\n\n    <span class=\"n\">name</span> <span class=\"o\">=</span> <span class=\"nb\">property</span><span class=\"p\">(</span><span class=\"n\">get_name</span><span class=\"p\">,</span> <span class=\"n\">set_name</span><span class=\"p\">)</span>\n\n<div class=\"viewcode-block\" id=\"Handler.createLock\"><a class=\"viewcode-back\" href=\"../logging.html#logging.Handler.createLock\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">createLock</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Acquire a thread lock for serializing access to the underlying I/O.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"k\">if</span> <span class=\"n\">threading</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">lock</span> <span class=\"o\">=</span> <span class=\"n\">threading</span><span class=\"o\">.</span><span class=\"n\">RLock</span><span class=\"p\">()</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span> <span class=\"c1\">#pragma: no cover</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">lock</span> <span class=\"o\">=</span> <span class=\"kc\">None</span></div>\n\n<div class=\"viewcode-block\" id=\"Handler.acquire\"><a class=\"viewcode-back\" href=\"../logging.html#logging.Handler.acquire\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">acquire</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Acquire the I/O thread lock.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">lock</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">lock</span><span class=\"o\">.</span><span class=\"n\">acquire</span><span class=\"p\">()</span></div>\n\n<div class=\"viewcode-block\" id=\"Handler.release\"><a class=\"viewcode-back\" href=\"../logging.html#logging.Handler.release\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">release</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Release the I/O thread lock.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">lock</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">lock</span><span class=\"o\">.</span><span class=\"n\">release</span><span class=\"p\">()</span></div>\n\n<div class=\"viewcode-block\" id=\"Handler.setLevel\"><a class=\"viewcode-back\" href=\"../logging.html#logging.Handler.setLevel\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">setLevel</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">level</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Set the logging level of this handler.  level must be an int or a str.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">level</span> <span class=\"o\">=</span> <span class=\"n\">_checkLevel</span><span class=\"p\">(</span><span class=\"n\">level</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"Handler.format\"><a class=\"viewcode-back\" href=\"../logging.html#logging.Handler.format\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">format</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">record</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Format the specified record.</span>\n\n<span class=\"sd\">        If a formatter is set, use it. Otherwise, use the default formatter</span>\n<span class=\"sd\">        for the module.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">formatter</span><span class=\"p\">:</span>\n            <span class=\"n\">fmt</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">formatter</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"n\">fmt</span> <span class=\"o\">=</span> <span class=\"n\">_defaultFormatter</span>\n        <span class=\"k\">return</span> <span class=\"n\">fmt</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">record</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"Handler.emit\"><a class=\"viewcode-back\" href=\"../logging.html#logging.Handler.emit\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">emit</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">record</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Do whatever it takes to actually log the specified logging record.</span>\n\n<span class=\"sd\">        This version is intended to be implemented by subclasses and so</span>\n<span class=\"sd\">        raises a NotImplementedError.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"k\">raise</span> <span class=\"ne\">NotImplementedError</span><span class=\"p\">(</span><span class=\"s1\">&#39;emit must be implemented &#39;</span>\n                                  <span class=\"s1\">&#39;by Handler subclasses&#39;</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"Handler.handle\"><a class=\"viewcode-back\" href=\"../logging.html#logging.Handler.handle\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">handle</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">record</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Conditionally emit the specified logging record.</span>\n\n<span class=\"sd\">        Emission depends on filters which may have been added to the handler.</span>\n<span class=\"sd\">        Wrap the actual emission of the record with acquisition/release of</span>\n<span class=\"sd\">        the I/O thread lock. Returns whether the filter passed the record for</span>\n<span class=\"sd\">        emission.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"n\">rv</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">filter</span><span class=\"p\">(</span><span class=\"n\">record</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">rv</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">acquire</span><span class=\"p\">()</span>\n            <span class=\"k\">try</span><span class=\"p\">:</span>\n                <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">emit</span><span class=\"p\">(</span><span class=\"n\">record</span><span class=\"p\">)</span>\n            <span class=\"k\">finally</span><span class=\"p\">:</span>\n                <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">release</span><span class=\"p\">()</span>\n        <span class=\"k\">return</span> <span class=\"n\">rv</span></div>\n\n<div class=\"viewcode-block\" id=\"Handler.setFormatter\"><a class=\"viewcode-back\" href=\"../logging.html#logging.Handler.setFormatter\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">setFormatter</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">fmt</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Set the formatter for this handler.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">formatter</span> <span class=\"o\">=</span> <span class=\"n\">fmt</span></div>\n\n<div class=\"viewcode-block\" id=\"Handler.flush\"><a class=\"viewcode-back\" href=\"../logging.html#logging.Handler.flush\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">flush</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Ensure all logging output has been flushed.</span>\n\n<span class=\"sd\">        This version does nothing and is intended to be implemented by</span>\n<span class=\"sd\">        subclasses.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"k\">pass</span></div>\n\n<div class=\"viewcode-block\" id=\"Handler.close\"><a class=\"viewcode-back\" href=\"../logging.html#logging.Handler.close\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">close</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Tidy up any resources used by the handler.</span>\n\n<span class=\"sd\">        This version removes the handler from an internal map of handlers,</span>\n<span class=\"sd\">        _handlers, which is used for handler lookup by name. Subclasses</span>\n<span class=\"sd\">        should ensure that this gets called from overridden close()</span>\n<span class=\"sd\">        methods.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"c1\">#get the module data lock, as we&#39;re updating a shared structure.</span>\n        <span class=\"n\">_acquireLock</span><span class=\"p\">()</span>\n        <span class=\"k\">try</span><span class=\"p\">:</span>    <span class=\"c1\">#unlikely to raise an exception, but you never know...</span>\n            <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_name</span> <span class=\"ow\">and</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_name</span> <span class=\"ow\">in</span> <span class=\"n\">_handlers</span><span class=\"p\">:</span>\n                <span class=\"k\">del</span> <span class=\"n\">_handlers</span><span class=\"p\">[</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_name</span><span class=\"p\">]</span>\n        <span class=\"k\">finally</span><span class=\"p\">:</span>\n            <span class=\"n\">_releaseLock</span><span class=\"p\">()</span></div>\n\n<div class=\"viewcode-block\" id=\"Handler.handleError\"><a class=\"viewcode-back\" href=\"../logging.html#logging.Handler.handleError\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">handleError</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">record</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Handle errors which occur during an emit() call.</span>\n\n<span class=\"sd\">        This method should be called from handlers when an exception is</span>\n<span class=\"sd\">        encountered during an emit() call. If raiseExceptions is false,</span>\n<span class=\"sd\">        exceptions get silently ignored. This is what is mostly wanted</span>\n<span class=\"sd\">        for a logging system - most users will not care about errors in</span>\n<span class=\"sd\">        the logging system, they are more interested in application errors.</span>\n<span class=\"sd\">        You could, however, replace this with a custom handler if you wish.</span>\n<span class=\"sd\">        The record which was being processed is passed in to this method.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"k\">if</span> <span class=\"n\">raiseExceptions</span> <span class=\"ow\">and</span> <span class=\"n\">sys</span><span class=\"o\">.</span><span class=\"n\">stderr</span><span class=\"p\">:</span>  <span class=\"c1\"># see issue 13807</span>\n            <span class=\"n\">t</span><span class=\"p\">,</span> <span class=\"n\">v</span><span class=\"p\">,</span> <span class=\"n\">tb</span> <span class=\"o\">=</span> <span class=\"n\">sys</span><span class=\"o\">.</span><span class=\"n\">exc_info</span><span class=\"p\">()</span>\n            <span class=\"k\">try</span><span class=\"p\">:</span>\n                <span class=\"n\">sys</span><span class=\"o\">.</span><span class=\"n\">stderr</span><span class=\"o\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"s1\">&#39;--- Logging error ---</span><span class=\"se\">\\n</span><span class=\"s1\">&#39;</span><span class=\"p\">)</span>\n                <span class=\"n\">traceback</span><span class=\"o\">.</span><span class=\"n\">print_exception</span><span class=\"p\">(</span><span class=\"n\">t</span><span class=\"p\">,</span> <span class=\"n\">v</span><span class=\"p\">,</span> <span class=\"n\">tb</span><span class=\"p\">,</span> <span class=\"kc\">None</span><span class=\"p\">,</span> <span class=\"n\">sys</span><span class=\"o\">.</span><span class=\"n\">stderr</span><span class=\"p\">)</span>\n                <span class=\"n\">sys</span><span class=\"o\">.</span><span class=\"n\">stderr</span><span class=\"o\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"s1\">&#39;Call stack:</span><span class=\"se\">\\n</span><span class=\"s1\">&#39;</span><span class=\"p\">)</span>\n                <span class=\"c1\"># Walk the stack frame up until we&#39;re out of logging,</span>\n                <span class=\"c1\"># so as to print the calling context.</span>\n                <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">tb</span><span class=\"o\">.</span><span class=\"n\">tb_frame</span>\n                <span class=\"k\">while</span> <span class=\"p\">(</span><span class=\"n\">frame</span> <span class=\"ow\">and</span> <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">dirname</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"o\">.</span><span class=\"n\">f_code</span><span class=\"o\">.</span><span class=\"n\">co_filename</span><span class=\"p\">)</span> <span class=\"o\">==</span>\n                       <span class=\"n\">__path__</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]):</span>\n                    <span class=\"n\">frame</span> <span class=\"o\">=</span> <span class=\"n\">frame</span><span class=\"o\">.</span><span class=\"n\">f_back</span>\n                <span class=\"k\">if</span> <span class=\"n\">frame</span><span class=\"p\">:</span>\n                    <span class=\"n\">traceback</span><span class=\"o\">.</span><span class=\"n\">print_stack</span><span class=\"p\">(</span><span class=\"n\">frame</span><span class=\"p\">,</span> <span class=\"n\">file</span><span class=\"o\">=</span><span class=\"n\">sys</span><span class=\"o\">.</span><span class=\"n\">stderr</span><span class=\"p\">)</span>\n                <span class=\"k\">else</span><span class=\"p\">:</span>\n                    <span class=\"c1\"># couldn&#39;t find the right stack frame, for some reason</span>\n                    <span class=\"n\">sys</span><span class=\"o\">.</span><span class=\"n\">stderr</span><span class=\"o\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"s1\">&#39;Logged from file </span><span class=\"si\">%s</span><span class=\"s1\">, line </span><span class=\"si\">%s</span><span class=\"se\">\\n</span><span class=\"s1\">&#39;</span> <span class=\"o\">%</span> <span class=\"p\">(</span>\n                                     <span class=\"n\">record</span><span class=\"o\">.</span><span class=\"n\">filename</span><span class=\"p\">,</span> <span class=\"n\">record</span><span class=\"o\">.</span><span class=\"n\">lineno</span><span class=\"p\">))</span>\n                <span class=\"c1\"># Issue 18671: output logging message and arguments</span>\n                <span class=\"k\">try</span><span class=\"p\">:</span>\n                    <span class=\"n\">sys</span><span class=\"o\">.</span><span class=\"n\">stderr</span><span class=\"o\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"s1\">&#39;Message: </span><span class=\"si\">%r</span><span class=\"se\">\\n</span><span class=\"s1\">&#39;</span>\n                                     <span class=\"s1\">&#39;Arguments: </span><span class=\"si\">%s</span><span class=\"se\">\\n</span><span class=\"s1\">&#39;</span> <span class=\"o\">%</span> <span class=\"p\">(</span><span class=\"n\">record</span><span class=\"o\">.</span><span class=\"n\">msg</span><span class=\"p\">,</span>\n                                                          <span class=\"n\">record</span><span class=\"o\">.</span><span class=\"n\">args</span><span class=\"p\">))</span>\n                <span class=\"k\">except</span> <span class=\"ne\">Exception</span><span class=\"p\">:</span>\n                    <span class=\"n\">sys</span><span class=\"o\">.</span><span class=\"n\">stderr</span><span class=\"o\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"s1\">&#39;Unable to print the message and arguments&#39;</span>\n                                     <span class=\"s1\">&#39; - possible formatting error.</span><span class=\"se\">\\n</span><span class=\"s1\">Use the&#39;</span>\n                                     <span class=\"s1\">&#39; traceback above to help find the error.</span><span class=\"se\">\\n</span><span class=\"s1\">&#39;</span>\n                                    <span class=\"p\">)</span>\n            <span class=\"k\">except</span> <span class=\"ne\">OSError</span><span class=\"p\">:</span> <span class=\"c1\">#pragma: no cover</span>\n                <span class=\"k\">pass</span>    <span class=\"c1\"># see issue 5971</span>\n            <span class=\"k\">finally</span><span class=\"p\">:</span>\n                <span class=\"k\">del</span> <span class=\"n\">t</span><span class=\"p\">,</span> <span class=\"n\">v</span><span class=\"p\">,</span> <span class=\"n\">tb</span></div></div>\n\n<div class=\"viewcode-block\" id=\"StreamHandler\"><a class=\"viewcode-back\" href=\"../logging.html#logging.StreamHandler\">[文档]</a><span class=\"k\">class</span> <span class=\"nc\">StreamHandler</span><span class=\"p\">(</span><span class=\"n\">Handler</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    A handler class which writes logging records, appropriately formatted,</span>\n<span class=\"sd\">    to a stream. Note that this class does not close the stream, as</span>\n<span class=\"sd\">    sys.stdout or sys.stderr may be used.</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n\n    <span class=\"n\">terminator</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;</span><span class=\"se\">\\n</span><span class=\"s1\">&#39;</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">stream</span><span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Initialize the handler.</span>\n\n<span class=\"sd\">        If stream is not specified, sys.stderr is used.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"n\">Handler</span><span class=\"o\">.</span><span class=\"fm\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">stream</span> <span class=\"ow\">is</span> <span class=\"kc\">None</span><span class=\"p\">:</span>\n            <span class=\"n\">stream</span> <span class=\"o\">=</span> <span class=\"n\">sys</span><span class=\"o\">.</span><span class=\"n\">stderr</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">stream</span> <span class=\"o\">=</span> <span class=\"n\">stream</span>\n\n<div class=\"viewcode-block\" id=\"StreamHandler.flush\"><a class=\"viewcode-back\" href=\"../logging.html#logging.StreamHandler.flush\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">flush</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Flushes the stream.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">acquire</span><span class=\"p\">()</span>\n        <span class=\"k\">try</span><span class=\"p\">:</span>\n            <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">stream</span> <span class=\"ow\">and</span> <span class=\"nb\">hasattr</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">stream</span><span class=\"p\">,</span> <span class=\"s2\">&quot;flush&quot;</span><span class=\"p\">):</span>\n                <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">stream</span><span class=\"o\">.</span><span class=\"n\">flush</span><span class=\"p\">()</span>\n        <span class=\"k\">finally</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">release</span><span class=\"p\">()</span></div>\n\n<div class=\"viewcode-block\" id=\"StreamHandler.emit\"><a class=\"viewcode-back\" href=\"../logging.html#logging.StreamHandler.emit\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">emit</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">record</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Emit a record.</span>\n\n<span class=\"sd\">        If a formatter is specified, it is used to format the record.</span>\n<span class=\"sd\">        The record is then written to the stream with a trailing newline.  If</span>\n<span class=\"sd\">        exception information is present, it is formatted using</span>\n<span class=\"sd\">        traceback.print_exception and appended to the stream.  If the stream</span>\n<span class=\"sd\">        has an &#39;encoding&#39; attribute, it is used to determine how to do the</span>\n<span class=\"sd\">        output to the stream.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"k\">try</span><span class=\"p\">:</span>\n            <span class=\"n\">msg</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">record</span><span class=\"p\">)</span>\n            <span class=\"n\">stream</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">stream</span>\n            <span class=\"n\">stream</span><span class=\"o\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"n\">msg</span><span class=\"p\">)</span>\n            <span class=\"n\">stream</span><span class=\"o\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">terminator</span><span class=\"p\">)</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">flush</span><span class=\"p\">()</span>\n        <span class=\"k\">except</span> <span class=\"ne\">Exception</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">handleError</span><span class=\"p\">(</span><span class=\"n\">record</span><span class=\"p\">)</span></div></div>\n\n<div class=\"viewcode-block\" id=\"FileHandler\"><a class=\"viewcode-back\" href=\"../logging.html#logging.FileHandler\">[文档]</a><span class=\"k\">class</span> <span class=\"nc\">FileHandler</span><span class=\"p\">(</span><span class=\"n\">StreamHandler</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    A handler class which writes formatted logging records to disk files.</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">filename</span><span class=\"p\">,</span> <span class=\"n\">mode</span><span class=\"o\">=</span><span class=\"s1\">&#39;a&#39;</span><span class=\"p\">,</span> <span class=\"n\">encoding</span><span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">,</span> <span class=\"n\">delay</span><span class=\"o\">=</span><span class=\"kc\">False</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Open the specified file and use it as the stream for logging.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"c1\">#keep the absolute path, otherwise derived classes which use this</span>\n        <span class=\"c1\">#may come a cropper when the current directory changes</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">baseFilename</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">abspath</span><span class=\"p\">(</span><span class=\"n\">filename</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">mode</span> <span class=\"o\">=</span> <span class=\"n\">mode</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">encoding</span> <span class=\"o\">=</span> <span class=\"n\">encoding</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">delay</span> <span class=\"o\">=</span> <span class=\"n\">delay</span>\n        <span class=\"k\">if</span> <span class=\"n\">delay</span><span class=\"p\">:</span>\n            <span class=\"c1\">#We don&#39;t open the stream, but we still need to call the</span>\n            <span class=\"c1\">#Handler constructor to set level, formatter, lock etc.</span>\n            <span class=\"n\">Handler</span><span class=\"o\">.</span><span class=\"fm\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">)</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">stream</span> <span class=\"o\">=</span> <span class=\"kc\">None</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"n\">StreamHandler</span><span class=\"o\">.</span><span class=\"fm\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_open</span><span class=\"p\">())</span>\n\n<div class=\"viewcode-block\" id=\"FileHandler.close\"><a class=\"viewcode-back\" href=\"../logging.html#logging.FileHandler.close\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">close</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Closes the stream.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">acquire</span><span class=\"p\">()</span>\n        <span class=\"k\">try</span><span class=\"p\">:</span>\n            <span class=\"k\">try</span><span class=\"p\">:</span>\n                <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">stream</span><span class=\"p\">:</span>\n                    <span class=\"k\">try</span><span class=\"p\">:</span>\n                        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">flush</span><span class=\"p\">()</span>\n                    <span class=\"k\">finally</span><span class=\"p\">:</span>\n                        <span class=\"n\">stream</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">stream</span>\n                        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">stream</span> <span class=\"o\">=</span> <span class=\"kc\">None</span>\n                        <span class=\"k\">if</span> <span class=\"nb\">hasattr</span><span class=\"p\">(</span><span class=\"n\">stream</span><span class=\"p\">,</span> <span class=\"s2\">&quot;close&quot;</span><span class=\"p\">):</span>\n                            <span class=\"n\">stream</span><span class=\"o\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n            <span class=\"k\">finally</span><span class=\"p\">:</span>\n                <span class=\"c1\"># Issue #19523: call unconditionally to</span>\n                <span class=\"c1\"># prevent a handler leak when delay is set</span>\n                <span class=\"n\">StreamHandler</span><span class=\"o\">.</span><span class=\"n\">close</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">)</span>\n        <span class=\"k\">finally</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">release</span><span class=\"p\">()</span></div>\n\n    <span class=\"k\">def</span> <span class=\"nf\">_open</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Open the current base file with the (original) mode and encoding.</span>\n<span class=\"sd\">        Return the resulting stream.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"k\">return</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">baseFilename</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">mode</span><span class=\"p\">,</span> <span class=\"n\">encoding</span><span class=\"o\">=</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">encoding</span><span class=\"p\">)</span>\n\n<div class=\"viewcode-block\" id=\"FileHandler.emit\"><a class=\"viewcode-back\" href=\"../logging.html#logging.FileHandler.emit\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">emit</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">record</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Emit a record.</span>\n\n<span class=\"sd\">        If the stream was not opened because &#39;delay&#39; was specified in the</span>\n<span class=\"sd\">        constructor, open it before calling the superclass&#39;s emit.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">stream</span> <span class=\"ow\">is</span> <span class=\"kc\">None</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">stream</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_open</span><span class=\"p\">()</span>\n        <span class=\"n\">StreamHandler</span><span class=\"o\">.</span><span class=\"n\">emit</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">record</span><span class=\"p\">)</span></div></div>\n\n<span class=\"k\">class</span> <span class=\"nc\">_StderrHandler</span><span class=\"p\">(</span><span class=\"n\">StreamHandler</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    This class is like a StreamHandler using sys.stderr, but always uses</span>\n<span class=\"sd\">    whatever sys.stderr is currently set to rather than the value of</span>\n<span class=\"sd\">    sys.stderr at handler construction time.</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">level</span><span class=\"o\">=</span><span class=\"n\">NOTSET</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Initialize the handler.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"n\">Handler</span><span class=\"o\">.</span><span class=\"fm\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">level</span><span class=\"p\">)</span>\n\n    <span class=\"nd\">@property</span>\n    <span class=\"k\">def</span> <span class=\"nf\">stream</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"n\">sys</span><span class=\"o\">.</span><span class=\"n\">stderr</span>\n\n\n<span class=\"n\">_defaultLastResort</span> <span class=\"o\">=</span> <span class=\"n\">_StderrHandler</span><span class=\"p\">(</span><span class=\"n\">WARNING</span><span class=\"p\">)</span>\n<span class=\"n\">lastResort</span> <span class=\"o\">=</span> <span class=\"n\">_defaultLastResort</span>\n\n<span class=\"c1\">#---------------------------------------------------------------------------</span>\n<span class=\"c1\">#   Manager classes and functions</span>\n<span class=\"c1\">#---------------------------------------------------------------------------</span>\n\n<span class=\"k\">class</span> <span class=\"nc\">PlaceHolder</span><span class=\"p\">(</span><span class=\"nb\">object</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    PlaceHolder instances are used in the Manager logger hierarchy to take</span>\n<span class=\"sd\">    the place of nodes for which no loggers have been defined. This class is</span>\n<span class=\"sd\">    intended for internal use only and not as part of the public API.</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">alogger</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Initialize with the specified logger being a child of this placeholder.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">loggerMap</span> <span class=\"o\">=</span> <span class=\"p\">{</span> <span class=\"n\">alogger</span> <span class=\"p\">:</span> <span class=\"kc\">None</span> <span class=\"p\">}</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">append</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">alogger</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Add the specified logger as a child of this placeholder.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"k\">if</span> <span class=\"n\">alogger</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">loggerMap</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">loggerMap</span><span class=\"p\">[</span><span class=\"n\">alogger</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"kc\">None</span>\n\n<span class=\"c1\">#</span>\n<span class=\"c1\">#   Determine which class to use when instantiating loggers.</span>\n<span class=\"c1\">#</span>\n\n<div class=\"viewcode-block\" id=\"setLoggerClass\"><a class=\"viewcode-back\" href=\"../logging.html#logging.setLoggerClass\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">setLoggerClass</span><span class=\"p\">(</span><span class=\"n\">klass</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    Set the class to be used when instantiating a logger. The class should</span>\n<span class=\"sd\">    define __init__() such that only a name argument is required, and the</span>\n<span class=\"sd\">    __init__() should call Logger.__init__()</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"k\">if</span> <span class=\"n\">klass</span> <span class=\"o\">!=</span> <span class=\"n\">Logger</span><span class=\"p\">:</span>\n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"nb\">issubclass</span><span class=\"p\">(</span><span class=\"n\">klass</span><span class=\"p\">,</span> <span class=\"n\">Logger</span><span class=\"p\">):</span>\n            <span class=\"k\">raise</span> <span class=\"ne\">TypeError</span><span class=\"p\">(</span><span class=\"s2\">&quot;logger not derived from logging.Logger: &quot;</span>\n                            <span class=\"o\">+</span> <span class=\"n\">klass</span><span class=\"o\">.</span><span class=\"vm\">__name__</span><span class=\"p\">)</span>\n    <span class=\"k\">global</span> <span class=\"n\">_loggerClass</span>\n    <span class=\"n\">_loggerClass</span> <span class=\"o\">=</span> <span class=\"n\">klass</span></div>\n\n<div class=\"viewcode-block\" id=\"getLoggerClass\"><a class=\"viewcode-back\" href=\"../logging.html#logging.getLoggerClass\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">getLoggerClass</span><span class=\"p\">():</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    Return the class to be used when instantiating a logger.</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"k\">return</span> <span class=\"n\">_loggerClass</span></div>\n\n<span class=\"k\">class</span> <span class=\"nc\">Manager</span><span class=\"p\">(</span><span class=\"nb\">object</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    There is [under normal circumstances] just one Manager instance, which</span>\n<span class=\"sd\">    holds the hierarchy of loggers.</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">rootnode</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Initialize the manager with the root node of the logger hierarchy.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">root</span> <span class=\"o\">=</span> <span class=\"n\">rootnode</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">disable</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">emittedNoHandlerWarning</span> <span class=\"o\">=</span> <span class=\"kc\">False</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">loggerDict</span> <span class=\"o\">=</span> <span class=\"p\">{}</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">loggerClass</span> <span class=\"o\">=</span> <span class=\"kc\">None</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">logRecordFactory</span> <span class=\"o\">=</span> <span class=\"kc\">None</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">getLogger</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">name</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Get a logger with the specified name (channel name), creating it</span>\n<span class=\"sd\">        if it doesn&#39;t yet exist. This name is a dot-separated hierarchical</span>\n<span class=\"sd\">        name, such as &quot;a&quot;, &quot;a.b&quot;, &quot;a.b.c&quot; or similar.</span>\n\n<span class=\"sd\">        If a PlaceHolder existed for the specified name [i.e. the logger</span>\n<span class=\"sd\">        didn&#39;t exist but a child of it did], replace it with the created</span>\n<span class=\"sd\">        logger and fix up the parent/child references which pointed to the</span>\n<span class=\"sd\">        placeholder to now point to the logger.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"n\">rv</span> <span class=\"o\">=</span> <span class=\"kc\">None</span>\n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"nb\">isinstance</span><span class=\"p\">(</span><span class=\"n\">name</span><span class=\"p\">,</span> <span class=\"nb\">str</span><span class=\"p\">):</span>\n            <span class=\"k\">raise</span> <span class=\"ne\">TypeError</span><span class=\"p\">(</span><span class=\"s1\">&#39;A logger name must be a string&#39;</span><span class=\"p\">)</span>\n        <span class=\"n\">_acquireLock</span><span class=\"p\">()</span>\n        <span class=\"k\">try</span><span class=\"p\">:</span>\n            <span class=\"k\">if</span> <span class=\"n\">name</span> <span class=\"ow\">in</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">loggerDict</span><span class=\"p\">:</span>\n                <span class=\"n\">rv</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">loggerDict</span><span class=\"p\">[</span><span class=\"n\">name</span><span class=\"p\">]</span>\n                <span class=\"k\">if</span> <span class=\"nb\">isinstance</span><span class=\"p\">(</span><span class=\"n\">rv</span><span class=\"p\">,</span> <span class=\"n\">PlaceHolder</span><span class=\"p\">):</span>\n                    <span class=\"n\">ph</span> <span class=\"o\">=</span> <span class=\"n\">rv</span>\n                    <span class=\"n\">rv</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">loggerClass</span> <span class=\"ow\">or</span> <span class=\"n\">_loggerClass</span><span class=\"p\">)(</span><span class=\"n\">name</span><span class=\"p\">)</span>\n                    <span class=\"n\">rv</span><span class=\"o\">.</span><span class=\"n\">manager</span> <span class=\"o\">=</span> <span class=\"bp\">self</span>\n                    <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">loggerDict</span><span class=\"p\">[</span><span class=\"n\">name</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">rv</span>\n                    <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_fixupChildren</span><span class=\"p\">(</span><span class=\"n\">ph</span><span class=\"p\">,</span> <span class=\"n\">rv</span><span class=\"p\">)</span>\n                    <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_fixupParents</span><span class=\"p\">(</span><span class=\"n\">rv</span><span class=\"p\">)</span>\n            <span class=\"k\">else</span><span class=\"p\">:</span>\n                <span class=\"n\">rv</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">loggerClass</span> <span class=\"ow\">or</span> <span class=\"n\">_loggerClass</span><span class=\"p\">)(</span><span class=\"n\">name</span><span class=\"p\">)</span>\n                <span class=\"n\">rv</span><span class=\"o\">.</span><span class=\"n\">manager</span> <span class=\"o\">=</span> <span class=\"bp\">self</span>\n                <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">loggerDict</span><span class=\"p\">[</span><span class=\"n\">name</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">rv</span>\n                <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_fixupParents</span><span class=\"p\">(</span><span class=\"n\">rv</span><span class=\"p\">)</span>\n        <span class=\"k\">finally</span><span class=\"p\">:</span>\n            <span class=\"n\">_releaseLock</span><span class=\"p\">()</span>\n        <span class=\"k\">return</span> <span class=\"n\">rv</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">setLoggerClass</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">klass</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Set the class to be used when instantiating a logger with this Manager.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"k\">if</span> <span class=\"n\">klass</span> <span class=\"o\">!=</span> <span class=\"n\">Logger</span><span class=\"p\">:</span>\n            <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"nb\">issubclass</span><span class=\"p\">(</span><span class=\"n\">klass</span><span class=\"p\">,</span> <span class=\"n\">Logger</span><span class=\"p\">):</span>\n                <span class=\"k\">raise</span> <span class=\"ne\">TypeError</span><span class=\"p\">(</span><span class=\"s2\">&quot;logger not derived from logging.Logger: &quot;</span>\n                                <span class=\"o\">+</span> <span class=\"n\">klass</span><span class=\"o\">.</span><span class=\"vm\">__name__</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">loggerClass</span> <span class=\"o\">=</span> <span class=\"n\">klass</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">setLogRecordFactory</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">factory</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Set the factory to be used when instantiating a log record with this</span>\n<span class=\"sd\">        Manager.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">logRecordFactory</span> <span class=\"o\">=</span> <span class=\"n\">factory</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">_fixupParents</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">alogger</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Ensure that there are either loggers or placeholders all the way</span>\n<span class=\"sd\">        from the specified logger to the root of the logger hierarchy.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"n\">name</span> <span class=\"o\">=</span> <span class=\"n\">alogger</span><span class=\"o\">.</span><span class=\"n\">name</span>\n        <span class=\"n\">i</span> <span class=\"o\">=</span> <span class=\"n\">name</span><span class=\"o\">.</span><span class=\"n\">rfind</span><span class=\"p\">(</span><span class=\"s2\">&quot;.&quot;</span><span class=\"p\">)</span>\n        <span class=\"n\">rv</span> <span class=\"o\">=</span> <span class=\"kc\">None</span>\n        <span class=\"k\">while</span> <span class=\"p\">(</span><span class=\"n\">i</span> <span class=\"o\">&gt;</span> <span class=\"mi\">0</span><span class=\"p\">)</span> <span class=\"ow\">and</span> <span class=\"ow\">not</span> <span class=\"n\">rv</span><span class=\"p\">:</span>\n            <span class=\"n\">substr</span> <span class=\"o\">=</span> <span class=\"n\">name</span><span class=\"p\">[:</span><span class=\"n\">i</span><span class=\"p\">]</span>\n            <span class=\"k\">if</span> <span class=\"n\">substr</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">loggerDict</span><span class=\"p\">:</span>\n                <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">loggerDict</span><span class=\"p\">[</span><span class=\"n\">substr</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">PlaceHolder</span><span class=\"p\">(</span><span class=\"n\">alogger</span><span class=\"p\">)</span>\n            <span class=\"k\">else</span><span class=\"p\">:</span>\n                <span class=\"n\">obj</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">loggerDict</span><span class=\"p\">[</span><span class=\"n\">substr</span><span class=\"p\">]</span>\n                <span class=\"k\">if</span> <span class=\"nb\">isinstance</span><span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">,</span> <span class=\"n\">Logger</span><span class=\"p\">):</span>\n                    <span class=\"n\">rv</span> <span class=\"o\">=</span> <span class=\"n\">obj</span>\n                <span class=\"k\">else</span><span class=\"p\">:</span>\n                    <span class=\"k\">assert</span> <span class=\"nb\">isinstance</span><span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">,</span> <span class=\"n\">PlaceHolder</span><span class=\"p\">)</span>\n                    <span class=\"n\">obj</span><span class=\"o\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">alogger</span><span class=\"p\">)</span>\n            <span class=\"n\">i</span> <span class=\"o\">=</span> <span class=\"n\">name</span><span class=\"o\">.</span><span class=\"n\">rfind</span><span class=\"p\">(</span><span class=\"s2\">&quot;.&quot;</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">i</span> <span class=\"o\">-</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">rv</span><span class=\"p\">:</span>\n            <span class=\"n\">rv</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">root</span>\n        <span class=\"n\">alogger</span><span class=\"o\">.</span><span class=\"n\">parent</span> <span class=\"o\">=</span> <span class=\"n\">rv</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">_fixupChildren</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">ph</span><span class=\"p\">,</span> <span class=\"n\">alogger</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Ensure that children of the placeholder ph are connected to the</span>\n<span class=\"sd\">        specified logger.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"n\">name</span> <span class=\"o\">=</span> <span class=\"n\">alogger</span><span class=\"o\">.</span><span class=\"n\">name</span>\n        <span class=\"n\">namelen</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">name</span><span class=\"p\">)</span>\n        <span class=\"k\">for</span> <span class=\"n\">c</span> <span class=\"ow\">in</span> <span class=\"n\">ph</span><span class=\"o\">.</span><span class=\"n\">loggerMap</span><span class=\"o\">.</span><span class=\"n\">keys</span><span class=\"p\">():</span>\n            <span class=\"c1\">#The if means ... if not c.parent.name.startswith(nm)</span>\n            <span class=\"k\">if</span> <span class=\"n\">c</span><span class=\"o\">.</span><span class=\"n\">parent</span><span class=\"o\">.</span><span class=\"n\">name</span><span class=\"p\">[:</span><span class=\"n\">namelen</span><span class=\"p\">]</span> <span class=\"o\">!=</span> <span class=\"n\">name</span><span class=\"p\">:</span>\n                <span class=\"n\">alogger</span><span class=\"o\">.</span><span class=\"n\">parent</span> <span class=\"o\">=</span> <span class=\"n\">c</span><span class=\"o\">.</span><span class=\"n\">parent</span>\n                <span class=\"n\">c</span><span class=\"o\">.</span><span class=\"n\">parent</span> <span class=\"o\">=</span> <span class=\"n\">alogger</span>\n\n<span class=\"c1\">#---------------------------------------------------------------------------</span>\n<span class=\"c1\">#   Logger classes and functions</span>\n<span class=\"c1\">#---------------------------------------------------------------------------</span>\n\n<div class=\"viewcode-block\" id=\"Logger\"><a class=\"viewcode-back\" href=\"../logging.html#logging.Logger\">[文档]</a><span class=\"k\">class</span> <span class=\"nc\">Logger</span><span class=\"p\">(</span><span class=\"n\">Filterer</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    Instances of the Logger class represent a single logging channel. A</span>\n<span class=\"sd\">    &quot;logging channel&quot; indicates an area of an application. Exactly how an</span>\n<span class=\"sd\">    &quot;area&quot; is defined is up to the application developer. Since an</span>\n<span class=\"sd\">    application can have any number of areas, logging channels are identified</span>\n<span class=\"sd\">    by a unique string. Application areas can be nested (e.g. an area</span>\n<span class=\"sd\">    of &quot;input processing&quot; might include sub-areas &quot;read CSV files&quot;, &quot;read</span>\n<span class=\"sd\">    XLS files&quot; and &quot;read Gnumeric files&quot;). To cater for this natural nesting,</span>\n<span class=\"sd\">    channel names are organized into a namespace hierarchy where levels are</span>\n<span class=\"sd\">    separated by periods, much like the Java or Python package namespace. So</span>\n<span class=\"sd\">    in the instance given above, channel names might be &quot;input&quot; for the upper</span>\n<span class=\"sd\">    level, and &quot;input.csv&quot;, &quot;input.xls&quot; and &quot;input.gnu&quot; for the sub-levels.</span>\n<span class=\"sd\">    There is no arbitrary limit to the depth of nesting.</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">name</span><span class=\"p\">,</span> <span class=\"n\">level</span><span class=\"o\">=</span><span class=\"n\">NOTSET</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Initialize the logger with a name and an optional level.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"n\">Filterer</span><span class=\"o\">.</span><span class=\"fm\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">name</span> <span class=\"o\">=</span> <span class=\"n\">name</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">level</span> <span class=\"o\">=</span> <span class=\"n\">_checkLevel</span><span class=\"p\">(</span><span class=\"n\">level</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">parent</span> <span class=\"o\">=</span> <span class=\"kc\">None</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">propagate</span> <span class=\"o\">=</span> <span class=\"kc\">True</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">handlers</span> <span class=\"o\">=</span> <span class=\"p\">[]</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">disabled</span> <span class=\"o\">=</span> <span class=\"kc\">False</span>\n\n<div class=\"viewcode-block\" id=\"Logger.setLevel\"><a class=\"viewcode-back\" href=\"../logging.html#logging.Logger.setLevel\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">setLevel</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">level</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Set the logging level of this logger.  level must be an int or a str.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">level</span> <span class=\"o\">=</span> <span class=\"n\">_checkLevel</span><span class=\"p\">(</span><span class=\"n\">level</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"Logger.debug\"><a class=\"viewcode-back\" href=\"../logging.html#logging.Logger.debug\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">debug</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">msg</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">args</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Log &#39;msg % args&#39; with severity &#39;DEBUG&#39;.</span>\n\n<span class=\"sd\">        To pass exception information, use the keyword argument exc_info with</span>\n<span class=\"sd\">        a true value, e.g.</span>\n\n<span class=\"sd\">        logger.debug(&quot;Houston, we have a %s&quot;, &quot;thorny problem&quot;, exc_info=1)</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">isEnabledFor</span><span class=\"p\">(</span><span class=\"n\">DEBUG</span><span class=\"p\">):</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_log</span><span class=\"p\">(</span><span class=\"n\">DEBUG</span><span class=\"p\">,</span> <span class=\"n\">msg</span><span class=\"p\">,</span> <span class=\"n\">args</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"Logger.info\"><a class=\"viewcode-back\" href=\"../logging.html#logging.Logger.info\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">info</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">msg</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">args</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Log &#39;msg % args&#39; with severity &#39;INFO&#39;.</span>\n\n<span class=\"sd\">        To pass exception information, use the keyword argument exc_info with</span>\n<span class=\"sd\">        a true value, e.g.</span>\n\n<span class=\"sd\">        logger.info(&quot;Houston, we have a %s&quot;, &quot;interesting problem&quot;, exc_info=1)</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">isEnabledFor</span><span class=\"p\">(</span><span class=\"n\">INFO</span><span class=\"p\">):</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_log</span><span class=\"p\">(</span><span class=\"n\">INFO</span><span class=\"p\">,</span> <span class=\"n\">msg</span><span class=\"p\">,</span> <span class=\"n\">args</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"Logger.warning\"><a class=\"viewcode-back\" href=\"../logging.html#logging.Logger.warning\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">warning</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">msg</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">args</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Log &#39;msg % args&#39; with severity &#39;WARNING&#39;.</span>\n\n<span class=\"sd\">        To pass exception information, use the keyword argument exc_info with</span>\n<span class=\"sd\">        a true value, e.g.</span>\n\n<span class=\"sd\">        logger.warning(&quot;Houston, we have a %s&quot;, &quot;bit of a problem&quot;, exc_info=1)</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">isEnabledFor</span><span class=\"p\">(</span><span class=\"n\">WARNING</span><span class=\"p\">):</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_log</span><span class=\"p\">(</span><span class=\"n\">WARNING</span><span class=\"p\">,</span> <span class=\"n\">msg</span><span class=\"p\">,</span> <span class=\"n\">args</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"Logger.warn\"><a class=\"viewcode-back\" href=\"../logging.html#logging.Logger.warn\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">warn</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">msg</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">args</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">):</span>\n        <span class=\"n\">warnings</span><span class=\"o\">.</span><span class=\"n\">warn</span><span class=\"p\">(</span><span class=\"s2\">&quot;The &#39;warn&#39; method is deprecated, &quot;</span>\n            <span class=\"s2\">&quot;use &#39;warning&#39; instead&quot;</span><span class=\"p\">,</span> <span class=\"ne\">DeprecationWarning</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">warning</span><span class=\"p\">(</span><span class=\"n\">msg</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">args</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"Logger.error\"><a class=\"viewcode-back\" href=\"../logging.html#logging.Logger.error\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">error</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">msg</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">args</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Log &#39;msg % args&#39; with severity &#39;ERROR&#39;.</span>\n\n<span class=\"sd\">        To pass exception information, use the keyword argument exc_info with</span>\n<span class=\"sd\">        a true value, e.g.</span>\n\n<span class=\"sd\">        logger.error(&quot;Houston, we have a %s&quot;, &quot;major problem&quot;, exc_info=1)</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">isEnabledFor</span><span class=\"p\">(</span><span class=\"n\">ERROR</span><span class=\"p\">):</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_log</span><span class=\"p\">(</span><span class=\"n\">ERROR</span><span class=\"p\">,</span> <span class=\"n\">msg</span><span class=\"p\">,</span> <span class=\"n\">args</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"Logger.exception\"><a class=\"viewcode-back\" href=\"../logging.html#logging.Logger.exception\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">exception</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">msg</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">args</span><span class=\"p\">,</span> <span class=\"n\">exc_info</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Convenience method for logging an ERROR with exception information.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">error</span><span class=\"p\">(</span><span class=\"n\">msg</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">args</span><span class=\"p\">,</span> <span class=\"n\">exc_info</span><span class=\"o\">=</span><span class=\"n\">exc_info</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"Logger.critical\"><a class=\"viewcode-back\" href=\"../logging.html#logging.Logger.critical\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">critical</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">msg</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">args</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Log &#39;msg % args&#39; with severity &#39;CRITICAL&#39;.</span>\n\n<span class=\"sd\">        To pass exception information, use the keyword argument exc_info with</span>\n<span class=\"sd\">        a true value, e.g.</span>\n\n<span class=\"sd\">        logger.critical(&quot;Houston, we have a %s&quot;, &quot;major disaster&quot;, exc_info=1)</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">isEnabledFor</span><span class=\"p\">(</span><span class=\"n\">CRITICAL</span><span class=\"p\">):</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_log</span><span class=\"p\">(</span><span class=\"n\">CRITICAL</span><span class=\"p\">,</span> <span class=\"n\">msg</span><span class=\"p\">,</span> <span class=\"n\">args</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">)</span></div>\n\n    <span class=\"n\">fatal</span> <span class=\"o\">=</span> <span class=\"n\">critical</span>\n\n<div class=\"viewcode-block\" id=\"Logger.log\"><a class=\"viewcode-back\" href=\"../logging.html#logging.Logger.log\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">log</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">level</span><span class=\"p\">,</span> <span class=\"n\">msg</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">args</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Log &#39;msg % args&#39; with the integer severity &#39;level&#39;.</span>\n\n<span class=\"sd\">        To pass exception information, use the keyword argument exc_info with</span>\n<span class=\"sd\">        a true value, e.g.</span>\n\n<span class=\"sd\">        logger.log(level, &quot;We have a %s&quot;, &quot;mysterious problem&quot;, exc_info=1)</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"nb\">isinstance</span><span class=\"p\">(</span><span class=\"n\">level</span><span class=\"p\">,</span> <span class=\"nb\">int</span><span class=\"p\">):</span>\n            <span class=\"k\">if</span> <span class=\"n\">raiseExceptions</span><span class=\"p\">:</span>\n                <span class=\"k\">raise</span> <span class=\"ne\">TypeError</span><span class=\"p\">(</span><span class=\"s2\">&quot;level must be an integer&quot;</span><span class=\"p\">)</span>\n            <span class=\"k\">else</span><span class=\"p\">:</span>\n                <span class=\"k\">return</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">isEnabledFor</span><span class=\"p\">(</span><span class=\"n\">level</span><span class=\"p\">):</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_log</span><span class=\"p\">(</span><span class=\"n\">level</span><span class=\"p\">,</span> <span class=\"n\">msg</span><span class=\"p\">,</span> <span class=\"n\">args</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"Logger.findCaller\"><a class=\"viewcode-back\" href=\"../logging.html#logging.Logger.findCaller\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">findCaller</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">stack_info</span><span class=\"o\">=</span><span class=\"kc\">False</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Find the stack frame of the caller so that we can note the source</span>\n<span class=\"sd\">        file name, line number and function name.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"n\">f</span> <span class=\"o\">=</span> <span class=\"n\">currentframe</span><span class=\"p\">()</span>\n        <span class=\"c1\">#On some versions of IronPython, currentframe() returns None if</span>\n        <span class=\"c1\">#IronPython isn&#39;t run with -X:Frames.</span>\n        <span class=\"k\">if</span> <span class=\"n\">f</span> <span class=\"ow\">is</span> <span class=\"ow\">not</span> <span class=\"kc\">None</span><span class=\"p\">:</span>\n            <span class=\"n\">f</span> <span class=\"o\">=</span> <span class=\"n\">f</span><span class=\"o\">.</span><span class=\"n\">f_back</span>\n        <span class=\"n\">rv</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;(unknown file)&quot;</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"s2\">&quot;(unknown function)&quot;</span><span class=\"p\">,</span> <span class=\"kc\">None</span>\n        <span class=\"k\">while</span> <span class=\"nb\">hasattr</span><span class=\"p\">(</span><span class=\"n\">f</span><span class=\"p\">,</span> <span class=\"s2\">&quot;f_code&quot;</span><span class=\"p\">):</span>\n            <span class=\"n\">co</span> <span class=\"o\">=</span> <span class=\"n\">f</span><span class=\"o\">.</span><span class=\"n\">f_code</span>\n            <span class=\"n\">filename</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">normcase</span><span class=\"p\">(</span><span class=\"n\">co</span><span class=\"o\">.</span><span class=\"n\">co_filename</span><span class=\"p\">)</span>\n            <span class=\"k\">if</span> <span class=\"n\">filename</span> <span class=\"o\">==</span> <span class=\"n\">_srcfile</span><span class=\"p\">:</span>\n                <span class=\"n\">f</span> <span class=\"o\">=</span> <span class=\"n\">f</span><span class=\"o\">.</span><span class=\"n\">f_back</span>\n                <span class=\"k\">continue</span>\n            <span class=\"n\">sinfo</span> <span class=\"o\">=</span> <span class=\"kc\">None</span>\n            <span class=\"k\">if</span> <span class=\"n\">stack_info</span><span class=\"p\">:</span>\n                <span class=\"n\">sio</span> <span class=\"o\">=</span> <span class=\"n\">io</span><span class=\"o\">.</span><span class=\"n\">StringIO</span><span class=\"p\">()</span>\n                <span class=\"n\">sio</span><span class=\"o\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"s1\">&#39;Stack (most recent call last):</span><span class=\"se\">\\n</span><span class=\"s1\">&#39;</span><span class=\"p\">)</span>\n                <span class=\"n\">traceback</span><span class=\"o\">.</span><span class=\"n\">print_stack</span><span class=\"p\">(</span><span class=\"n\">f</span><span class=\"p\">,</span> <span class=\"n\">file</span><span class=\"o\">=</span><span class=\"n\">sio</span><span class=\"p\">)</span>\n                <span class=\"n\">sinfo</span> <span class=\"o\">=</span> <span class=\"n\">sio</span><span class=\"o\">.</span><span class=\"n\">getvalue</span><span class=\"p\">()</span>\n                <span class=\"k\">if</span> <span class=\"n\">sinfo</span><span class=\"p\">[</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">==</span> <span class=\"s1\">&#39;</span><span class=\"se\">\\n</span><span class=\"s1\">&#39;</span><span class=\"p\">:</span>\n                    <span class=\"n\">sinfo</span> <span class=\"o\">=</span> <span class=\"n\">sinfo</span><span class=\"p\">[:</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n                <span class=\"n\">sio</span><span class=\"o\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n            <span class=\"n\">rv</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"n\">co</span><span class=\"o\">.</span><span class=\"n\">co_filename</span><span class=\"p\">,</span> <span class=\"n\">f</span><span class=\"o\">.</span><span class=\"n\">f_lineno</span><span class=\"p\">,</span> <span class=\"n\">co</span><span class=\"o\">.</span><span class=\"n\">co_name</span><span class=\"p\">,</span> <span class=\"n\">sinfo</span><span class=\"p\">)</span>\n            <span class=\"k\">break</span>\n        <span class=\"k\">return</span> <span class=\"n\">rv</span></div>\n\n<div class=\"viewcode-block\" id=\"Logger.makeRecord\"><a class=\"viewcode-back\" href=\"../logging.html#logging.Logger.makeRecord\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">makeRecord</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">name</span><span class=\"p\">,</span> <span class=\"n\">level</span><span class=\"p\">,</span> <span class=\"n\">fn</span><span class=\"p\">,</span> <span class=\"n\">lno</span><span class=\"p\">,</span> <span class=\"n\">msg</span><span class=\"p\">,</span> <span class=\"n\">args</span><span class=\"p\">,</span> <span class=\"n\">exc_info</span><span class=\"p\">,</span>\n                   <span class=\"n\">func</span><span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">,</span> <span class=\"n\">extra</span><span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">,</span> <span class=\"n\">sinfo</span><span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        A factory method which can be overridden in subclasses to create</span>\n<span class=\"sd\">        specialized LogRecords.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"n\">rv</span> <span class=\"o\">=</span> <span class=\"n\">_logRecordFactory</span><span class=\"p\">(</span><span class=\"n\">name</span><span class=\"p\">,</span> <span class=\"n\">level</span><span class=\"p\">,</span> <span class=\"n\">fn</span><span class=\"p\">,</span> <span class=\"n\">lno</span><span class=\"p\">,</span> <span class=\"n\">msg</span><span class=\"p\">,</span> <span class=\"n\">args</span><span class=\"p\">,</span> <span class=\"n\">exc_info</span><span class=\"p\">,</span> <span class=\"n\">func</span><span class=\"p\">,</span>\n                             <span class=\"n\">sinfo</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">extra</span> <span class=\"ow\">is</span> <span class=\"ow\">not</span> <span class=\"kc\">None</span><span class=\"p\">:</span>\n            <span class=\"k\">for</span> <span class=\"n\">key</span> <span class=\"ow\">in</span> <span class=\"n\">extra</span><span class=\"p\">:</span>\n                <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">key</span> <span class=\"ow\">in</span> <span class=\"p\">[</span><span class=\"s2\">&quot;message&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;asctime&quot;</span><span class=\"p\">])</span> <span class=\"ow\">or</span> <span class=\"p\">(</span><span class=\"n\">key</span> <span class=\"ow\">in</span> <span class=\"n\">rv</span><span class=\"o\">.</span><span class=\"vm\">__dict__</span><span class=\"p\">):</span>\n                    <span class=\"k\">raise</span> <span class=\"ne\">KeyError</span><span class=\"p\">(</span><span class=\"s2\">&quot;Attempt to overwrite </span><span class=\"si\">%r</span><span class=\"s2\"> in LogRecord&quot;</span> <span class=\"o\">%</span> <span class=\"n\">key</span><span class=\"p\">)</span>\n                <span class=\"n\">rv</span><span class=\"o\">.</span><span class=\"vm\">__dict__</span><span class=\"p\">[</span><span class=\"n\">key</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">extra</span><span class=\"p\">[</span><span class=\"n\">key</span><span class=\"p\">]</span>\n        <span class=\"k\">return</span> <span class=\"n\">rv</span></div>\n\n    <span class=\"k\">def</span> <span class=\"nf\">_log</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">level</span><span class=\"p\">,</span> <span class=\"n\">msg</span><span class=\"p\">,</span> <span class=\"n\">args</span><span class=\"p\">,</span> <span class=\"n\">exc_info</span><span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">,</span> <span class=\"n\">extra</span><span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">,</span> <span class=\"n\">stack_info</span><span class=\"o\">=</span><span class=\"kc\">False</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Low-level logging routine which creates a LogRecord and then calls</span>\n<span class=\"sd\">        all the handlers of this logger to handle the record.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"n\">sinfo</span> <span class=\"o\">=</span> <span class=\"kc\">None</span>\n        <span class=\"k\">if</span> <span class=\"n\">_srcfile</span><span class=\"p\">:</span>\n            <span class=\"c1\">#IronPython doesn&#39;t track Python frames, so findCaller raises an</span>\n            <span class=\"c1\">#exception on some versions of IronPython. We trap it here so that</span>\n            <span class=\"c1\">#IronPython can use logging.</span>\n            <span class=\"k\">try</span><span class=\"p\">:</span>\n                <span class=\"n\">fn</span><span class=\"p\">,</span> <span class=\"n\">lno</span><span class=\"p\">,</span> <span class=\"n\">func</span><span class=\"p\">,</span> <span class=\"n\">sinfo</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">findCaller</span><span class=\"p\">(</span><span class=\"n\">stack_info</span><span class=\"p\">)</span>\n            <span class=\"k\">except</span> <span class=\"ne\">ValueError</span><span class=\"p\">:</span> <span class=\"c1\"># pragma: no cover</span>\n                <span class=\"n\">fn</span><span class=\"p\">,</span> <span class=\"n\">lno</span><span class=\"p\">,</span> <span class=\"n\">func</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;(unknown file)&quot;</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"s2\">&quot;(unknown function)&quot;</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span> <span class=\"c1\"># pragma: no cover</span>\n            <span class=\"n\">fn</span><span class=\"p\">,</span> <span class=\"n\">lno</span><span class=\"p\">,</span> <span class=\"n\">func</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;(unknown file)&quot;</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"s2\">&quot;(unknown function)&quot;</span>\n        <span class=\"k\">if</span> <span class=\"n\">exc_info</span><span class=\"p\">:</span>\n            <span class=\"k\">if</span> <span class=\"nb\">isinstance</span><span class=\"p\">(</span><span class=\"n\">exc_info</span><span class=\"p\">,</span> <span class=\"ne\">BaseException</span><span class=\"p\">):</span>\n                <span class=\"n\">exc_info</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"nb\">type</span><span class=\"p\">(</span><span class=\"n\">exc_info</span><span class=\"p\">),</span> <span class=\"n\">exc_info</span><span class=\"p\">,</span> <span class=\"n\">exc_info</span><span class=\"o\">.</span><span class=\"n\">__traceback__</span><span class=\"p\">)</span>\n            <span class=\"k\">elif</span> <span class=\"ow\">not</span> <span class=\"nb\">isinstance</span><span class=\"p\">(</span><span class=\"n\">exc_info</span><span class=\"p\">,</span> <span class=\"nb\">tuple</span><span class=\"p\">):</span>\n                <span class=\"n\">exc_info</span> <span class=\"o\">=</span> <span class=\"n\">sys</span><span class=\"o\">.</span><span class=\"n\">exc_info</span><span class=\"p\">()</span>\n        <span class=\"n\">record</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">makeRecord</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">name</span><span class=\"p\">,</span> <span class=\"n\">level</span><span class=\"p\">,</span> <span class=\"n\">fn</span><span class=\"p\">,</span> <span class=\"n\">lno</span><span class=\"p\">,</span> <span class=\"n\">msg</span><span class=\"p\">,</span> <span class=\"n\">args</span><span class=\"p\">,</span>\n                                 <span class=\"n\">exc_info</span><span class=\"p\">,</span> <span class=\"n\">func</span><span class=\"p\">,</span> <span class=\"n\">extra</span><span class=\"p\">,</span> <span class=\"n\">sinfo</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">handle</span><span class=\"p\">(</span><span class=\"n\">record</span><span class=\"p\">)</span>\n\n<div class=\"viewcode-block\" id=\"Logger.handle\"><a class=\"viewcode-back\" href=\"../logging.html#logging.Logger.handle\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">handle</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">record</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Call the handlers for the specified record.</span>\n\n<span class=\"sd\">        This method is used for unpickled records received from a socket, as</span>\n<span class=\"sd\">        well as those created locally. Logger-level filtering is applied.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"ow\">not</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">disabled</span><span class=\"p\">)</span> <span class=\"ow\">and</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">filter</span><span class=\"p\">(</span><span class=\"n\">record</span><span class=\"p\">):</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">callHandlers</span><span class=\"p\">(</span><span class=\"n\">record</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"Logger.addHandler\"><a class=\"viewcode-back\" href=\"../logging.html#logging.Logger.addHandler\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">addHandler</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">hdlr</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Add the specified handler to this logger.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"n\">_acquireLock</span><span class=\"p\">()</span>\n        <span class=\"k\">try</span><span class=\"p\">:</span>\n            <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"p\">(</span><span class=\"n\">hdlr</span> <span class=\"ow\">in</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">handlers</span><span class=\"p\">):</span>\n                <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">handlers</span><span class=\"o\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">hdlr</span><span class=\"p\">)</span>\n        <span class=\"k\">finally</span><span class=\"p\">:</span>\n            <span class=\"n\">_releaseLock</span><span class=\"p\">()</span></div>\n\n<div class=\"viewcode-block\" id=\"Logger.removeHandler\"><a class=\"viewcode-back\" href=\"../logging.html#logging.Logger.removeHandler\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">removeHandler</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">hdlr</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Remove the specified handler from this logger.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"n\">_acquireLock</span><span class=\"p\">()</span>\n        <span class=\"k\">try</span><span class=\"p\">:</span>\n            <span class=\"k\">if</span> <span class=\"n\">hdlr</span> <span class=\"ow\">in</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">handlers</span><span class=\"p\">:</span>\n                <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">handlers</span><span class=\"o\">.</span><span class=\"n\">remove</span><span class=\"p\">(</span><span class=\"n\">hdlr</span><span class=\"p\">)</span>\n        <span class=\"k\">finally</span><span class=\"p\">:</span>\n            <span class=\"n\">_releaseLock</span><span class=\"p\">()</span></div>\n\n<div class=\"viewcode-block\" id=\"Logger.hasHandlers\"><a class=\"viewcode-back\" href=\"../logging.html#logging.Logger.hasHandlers\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">hasHandlers</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        See if this logger has any handlers configured.</span>\n\n<span class=\"sd\">        Loop through all handlers for this logger and its parents in the</span>\n<span class=\"sd\">        logger hierarchy. Return True if a handler was found, else False.</span>\n<span class=\"sd\">        Stop searching up the hierarchy whenever a logger with the &quot;propagate&quot;</span>\n<span class=\"sd\">        attribute set to zero is found - that will be the last logger which</span>\n<span class=\"sd\">        is checked for the existence of handlers.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"n\">c</span> <span class=\"o\">=</span> <span class=\"bp\">self</span>\n        <span class=\"n\">rv</span> <span class=\"o\">=</span> <span class=\"kc\">False</span>\n        <span class=\"k\">while</span> <span class=\"n\">c</span><span class=\"p\">:</span>\n            <span class=\"k\">if</span> <span class=\"n\">c</span><span class=\"o\">.</span><span class=\"n\">handlers</span><span class=\"p\">:</span>\n                <span class=\"n\">rv</span> <span class=\"o\">=</span> <span class=\"kc\">True</span>\n                <span class=\"k\">break</span>\n            <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">c</span><span class=\"o\">.</span><span class=\"n\">propagate</span><span class=\"p\">:</span>\n                <span class=\"k\">break</span>\n            <span class=\"k\">else</span><span class=\"p\">:</span>\n                <span class=\"n\">c</span> <span class=\"o\">=</span> <span class=\"n\">c</span><span class=\"o\">.</span><span class=\"n\">parent</span>\n        <span class=\"k\">return</span> <span class=\"n\">rv</span></div>\n\n<div class=\"viewcode-block\" id=\"Logger.callHandlers\"><a class=\"viewcode-back\" href=\"../logging.html#logging.Logger.callHandlers\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">callHandlers</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">record</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Pass a record to all relevant handlers.</span>\n\n<span class=\"sd\">        Loop through all handlers for this logger and its parents in the</span>\n<span class=\"sd\">        logger hierarchy. If no handler was found, output a one-off error</span>\n<span class=\"sd\">        message to sys.stderr. Stop searching up the hierarchy whenever a</span>\n<span class=\"sd\">        logger with the &quot;propagate&quot; attribute set to zero is found - that</span>\n<span class=\"sd\">        will be the last logger whose handlers are called.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"n\">c</span> <span class=\"o\">=</span> <span class=\"bp\">self</span>\n        <span class=\"n\">found</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n        <span class=\"k\">while</span> <span class=\"n\">c</span><span class=\"p\">:</span>\n            <span class=\"k\">for</span> <span class=\"n\">hdlr</span> <span class=\"ow\">in</span> <span class=\"n\">c</span><span class=\"o\">.</span><span class=\"n\">handlers</span><span class=\"p\">:</span>\n                <span class=\"n\">found</span> <span class=\"o\">=</span> <span class=\"n\">found</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n                <span class=\"k\">if</span> <span class=\"n\">record</span><span class=\"o\">.</span><span class=\"n\">levelno</span> <span class=\"o\">&gt;=</span> <span class=\"n\">hdlr</span><span class=\"o\">.</span><span class=\"n\">level</span><span class=\"p\">:</span>\n                    <span class=\"n\">hdlr</span><span class=\"o\">.</span><span class=\"n\">handle</span><span class=\"p\">(</span><span class=\"n\">record</span><span class=\"p\">)</span>\n            <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">c</span><span class=\"o\">.</span><span class=\"n\">propagate</span><span class=\"p\">:</span>\n                <span class=\"n\">c</span> <span class=\"o\">=</span> <span class=\"kc\">None</span>    <span class=\"c1\">#break out</span>\n            <span class=\"k\">else</span><span class=\"p\">:</span>\n                <span class=\"n\">c</span> <span class=\"o\">=</span> <span class=\"n\">c</span><span class=\"o\">.</span><span class=\"n\">parent</span>\n        <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">found</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">):</span>\n            <span class=\"k\">if</span> <span class=\"n\">lastResort</span><span class=\"p\">:</span>\n                <span class=\"k\">if</span> <span class=\"n\">record</span><span class=\"o\">.</span><span class=\"n\">levelno</span> <span class=\"o\">&gt;=</span> <span class=\"n\">lastResort</span><span class=\"o\">.</span><span class=\"n\">level</span><span class=\"p\">:</span>\n                    <span class=\"n\">lastResort</span><span class=\"o\">.</span><span class=\"n\">handle</span><span class=\"p\">(</span><span class=\"n\">record</span><span class=\"p\">)</span>\n            <span class=\"k\">elif</span> <span class=\"n\">raiseExceptions</span> <span class=\"ow\">and</span> <span class=\"ow\">not</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">manager</span><span class=\"o\">.</span><span class=\"n\">emittedNoHandlerWarning</span><span class=\"p\">:</span>\n                <span class=\"n\">sys</span><span class=\"o\">.</span><span class=\"n\">stderr</span><span class=\"o\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"s2\">&quot;No handlers could be found for logger&quot;</span>\n                                 <span class=\"s2\">&quot; </span><span class=\"se\">\\&quot;</span><span class=\"si\">%s</span><span class=\"se\">\\&quot;\\n</span><span class=\"s2\">&quot;</span> <span class=\"o\">%</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">name</span><span class=\"p\">)</span>\n                <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">manager</span><span class=\"o\">.</span><span class=\"n\">emittedNoHandlerWarning</span> <span class=\"o\">=</span> <span class=\"kc\">True</span></div>\n\n<div class=\"viewcode-block\" id=\"Logger.getEffectiveLevel\"><a class=\"viewcode-back\" href=\"../logging.html#logging.Logger.getEffectiveLevel\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">getEffectiveLevel</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Get the effective level for this logger.</span>\n\n<span class=\"sd\">        Loop through this logger and its parents in the logger hierarchy,</span>\n<span class=\"sd\">        looking for a non-zero logging level. Return the first one found.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"n\">logger</span> <span class=\"o\">=</span> <span class=\"bp\">self</span>\n        <span class=\"k\">while</span> <span class=\"n\">logger</span><span class=\"p\">:</span>\n            <span class=\"k\">if</span> <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">level</span><span class=\"p\">:</span>\n                <span class=\"k\">return</span> <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">level</span>\n            <span class=\"n\">logger</span> <span class=\"o\">=</span> <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">parent</span>\n        <span class=\"k\">return</span> <span class=\"n\">NOTSET</span></div>\n\n<div class=\"viewcode-block\" id=\"Logger.isEnabledFor\"><a class=\"viewcode-back\" href=\"../logging.html#logging.Logger.isEnabledFor\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">isEnabledFor</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">level</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Is this logger enabled for level &#39;level&#39;?</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">manager</span><span class=\"o\">.</span><span class=\"n\">disable</span> <span class=\"o\">&gt;=</span> <span class=\"n\">level</span><span class=\"p\">:</span>\n            <span class=\"k\">return</span> <span class=\"kc\">False</span>\n        <span class=\"k\">return</span> <span class=\"n\">level</span> <span class=\"o\">&gt;=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">getEffectiveLevel</span><span class=\"p\">()</span></div>\n\n<div class=\"viewcode-block\" id=\"Logger.getChild\"><a class=\"viewcode-back\" href=\"../logging.html#logging.Logger.getChild\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">getChild</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">suffix</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Get a logger which is a descendant to this one.</span>\n\n<span class=\"sd\">        This is a convenience method, such that</span>\n\n<span class=\"sd\">        logging.getLogger(&#39;abc&#39;).getChild(&#39;def.ghi&#39;)</span>\n\n<span class=\"sd\">        is the same as</span>\n\n<span class=\"sd\">        logging.getLogger(&#39;abc.def.ghi&#39;)</span>\n\n<span class=\"sd\">        It&#39;s useful, for example, when the parent logger is named using</span>\n<span class=\"sd\">        __name__ rather than a literal string.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">root</span> <span class=\"ow\">is</span> <span class=\"ow\">not</span> <span class=\"bp\">self</span><span class=\"p\">:</span>\n            <span class=\"n\">suffix</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;.&#39;</span><span class=\"o\">.</span><span class=\"n\">join</span><span class=\"p\">((</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">name</span><span class=\"p\">,</span> <span class=\"n\">suffix</span><span class=\"p\">))</span>\n        <span class=\"k\">return</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">manager</span><span class=\"o\">.</span><span class=\"n\">getLogger</span><span class=\"p\">(</span><span class=\"n\">suffix</span><span class=\"p\">)</span></div></div>\n\n<span class=\"k\">class</span> <span class=\"nc\">RootLogger</span><span class=\"p\">(</span><span class=\"n\">Logger</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    A root logger is not that different to any other logger, except that</span>\n<span class=\"sd\">    it must have a logging level and there is only one instance of it in</span>\n<span class=\"sd\">    the hierarchy.</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">level</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Initialize the logger with the name &quot;root&quot;.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"n\">Logger</span><span class=\"o\">.</span><span class=\"fm\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"s2\">&quot;root&quot;</span><span class=\"p\">,</span> <span class=\"n\">level</span><span class=\"p\">)</span>\n\n<span class=\"n\">_loggerClass</span> <span class=\"o\">=</span> <span class=\"n\">Logger</span>\n\n<div class=\"viewcode-block\" id=\"LoggerAdapter\"><a class=\"viewcode-back\" href=\"../logging.html#logging.LoggerAdapter\">[文档]</a><span class=\"k\">class</span> <span class=\"nc\">LoggerAdapter</span><span class=\"p\">(</span><span class=\"nb\">object</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    An adapter for loggers which makes it easier to specify contextual</span>\n<span class=\"sd\">    information in logging output.</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">logger</span><span class=\"p\">,</span> <span class=\"n\">extra</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Initialize the adapter with a logger and a dict-like object which</span>\n<span class=\"sd\">        provides contextual information. This constructor signature allows</span>\n<span class=\"sd\">        easy stacking of LoggerAdapters, if so desired.</span>\n\n<span class=\"sd\">        You can effectively pass keyword arguments as shown in the</span>\n<span class=\"sd\">        following example:</span>\n\n<span class=\"sd\">        adapter = LoggerAdapter(someLogger, dict(p1=v1, p2=&quot;v2&quot;))</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">logger</span> <span class=\"o\">=</span> <span class=\"n\">logger</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">extra</span> <span class=\"o\">=</span> <span class=\"n\">extra</span>\n\n<div class=\"viewcode-block\" id=\"LoggerAdapter.process\"><a class=\"viewcode-back\" href=\"../logging.html#logging.LoggerAdapter.process\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">process</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">msg</span><span class=\"p\">,</span> <span class=\"n\">kwargs</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Process the logging message and keyword arguments passed in to</span>\n<span class=\"sd\">        a logging call to insert contextual information. You can either</span>\n<span class=\"sd\">        manipulate the message itself, the keyword args or both. Return</span>\n<span class=\"sd\">        the message and kwargs modified (or not) to suit your needs.</span>\n\n<span class=\"sd\">        Normally, you&#39;ll only need to override this one method in a</span>\n<span class=\"sd\">        LoggerAdapter subclass for your specific needs.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"n\">kwargs</span><span class=\"p\">[</span><span class=\"s2\">&quot;extra&quot;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">extra</span>\n        <span class=\"k\">return</span> <span class=\"n\">msg</span><span class=\"p\">,</span> <span class=\"n\">kwargs</span></div>\n\n    <span class=\"c1\">#</span>\n    <span class=\"c1\"># Boilerplate convenience methods</span>\n    <span class=\"c1\">#</span>\n<div class=\"viewcode-block\" id=\"LoggerAdapter.debug\"><a class=\"viewcode-back\" href=\"../logging.html#logging.LoggerAdapter.debug\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">debug</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">msg</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">args</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Delegate a debug call to the underlying logger.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">log</span><span class=\"p\">(</span><span class=\"n\">DEBUG</span><span class=\"p\">,</span> <span class=\"n\">msg</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">args</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"LoggerAdapter.info\"><a class=\"viewcode-back\" href=\"../logging.html#logging.LoggerAdapter.info\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">info</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">msg</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">args</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Delegate an info call to the underlying logger.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">log</span><span class=\"p\">(</span><span class=\"n\">INFO</span><span class=\"p\">,</span> <span class=\"n\">msg</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">args</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"LoggerAdapter.warning\"><a class=\"viewcode-back\" href=\"../logging.html#logging.LoggerAdapter.warning\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">warning</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">msg</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">args</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Delegate a warning call to the underlying logger.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">log</span><span class=\"p\">(</span><span class=\"n\">WARNING</span><span class=\"p\">,</span> <span class=\"n\">msg</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">args</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"LoggerAdapter.warn\"><a class=\"viewcode-back\" href=\"../logging.html#logging.LoggerAdapter.warn\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">warn</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">msg</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">args</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">):</span>\n        <span class=\"n\">warnings</span><span class=\"o\">.</span><span class=\"n\">warn</span><span class=\"p\">(</span><span class=\"s2\">&quot;The &#39;warn&#39; method is deprecated, &quot;</span>\n            <span class=\"s2\">&quot;use &#39;warning&#39; instead&quot;</span><span class=\"p\">,</span> <span class=\"ne\">DeprecationWarning</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">warning</span><span class=\"p\">(</span><span class=\"n\">msg</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">args</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"LoggerAdapter.error\"><a class=\"viewcode-back\" href=\"../logging.html#logging.LoggerAdapter.error\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">error</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">msg</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">args</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Delegate an error call to the underlying logger.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">log</span><span class=\"p\">(</span><span class=\"n\">ERROR</span><span class=\"p\">,</span> <span class=\"n\">msg</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">args</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"LoggerAdapter.exception\"><a class=\"viewcode-back\" href=\"../logging.html#logging.LoggerAdapter.exception\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">exception</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">msg</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">args</span><span class=\"p\">,</span> <span class=\"n\">exc_info</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Delegate an exception call to the underlying logger.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">log</span><span class=\"p\">(</span><span class=\"n\">ERROR</span><span class=\"p\">,</span> <span class=\"n\">msg</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">args</span><span class=\"p\">,</span> <span class=\"n\">exc_info</span><span class=\"o\">=</span><span class=\"n\">exc_info</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"LoggerAdapter.critical\"><a class=\"viewcode-back\" href=\"../logging.html#logging.LoggerAdapter.critical\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">critical</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">msg</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">args</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Delegate a critical call to the underlying logger.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">log</span><span class=\"p\">(</span><span class=\"n\">CRITICAL</span><span class=\"p\">,</span> <span class=\"n\">msg</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">args</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"LoggerAdapter.log\"><a class=\"viewcode-back\" href=\"../logging.html#logging.LoggerAdapter.log\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">log</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">level</span><span class=\"p\">,</span> <span class=\"n\">msg</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">args</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Delegate a log call to the underlying logger, after adding</span>\n<span class=\"sd\">        contextual information from this adapter instance.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">isEnabledFor</span><span class=\"p\">(</span><span class=\"n\">level</span><span class=\"p\">):</span>\n            <span class=\"n\">msg</span><span class=\"p\">,</span> <span class=\"n\">kwargs</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">process</span><span class=\"p\">(</span><span class=\"n\">msg</span><span class=\"p\">,</span> <span class=\"n\">kwargs</span><span class=\"p\">)</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">_log</span><span class=\"p\">(</span><span class=\"n\">level</span><span class=\"p\">,</span> <span class=\"n\">msg</span><span class=\"p\">,</span> <span class=\"n\">args</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"LoggerAdapter.isEnabledFor\"><a class=\"viewcode-back\" href=\"../logging.html#logging.LoggerAdapter.isEnabledFor\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">isEnabledFor</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">level</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Is this logger enabled for level &#39;level&#39;?</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">manager</span><span class=\"o\">.</span><span class=\"n\">disable</span> <span class=\"o\">&gt;=</span> <span class=\"n\">level</span><span class=\"p\">:</span>\n            <span class=\"k\">return</span> <span class=\"kc\">False</span>\n        <span class=\"k\">return</span> <span class=\"n\">level</span> <span class=\"o\">&gt;=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">getEffectiveLevel</span><span class=\"p\">()</span></div>\n\n<div class=\"viewcode-block\" id=\"LoggerAdapter.setLevel\"><a class=\"viewcode-back\" href=\"../logging.html#logging.LoggerAdapter.setLevel\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">setLevel</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">level</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Set the specified level on the underlying logger.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">setLevel</span><span class=\"p\">(</span><span class=\"n\">level</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"LoggerAdapter.getEffectiveLevel\"><a class=\"viewcode-back\" href=\"../logging.html#logging.LoggerAdapter.getEffectiveLevel\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">getEffectiveLevel</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Get the effective level for the underlying logger.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"k\">return</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">getEffectiveLevel</span><span class=\"p\">()</span></div>\n\n<div class=\"viewcode-block\" id=\"LoggerAdapter.hasHandlers\"><a class=\"viewcode-back\" href=\"../logging.html#logging.LoggerAdapter.hasHandlers\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">hasHandlers</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        See if the underlying logger has any handlers.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"k\">return</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">hasHandlers</span><span class=\"p\">()</span></div></div>\n\n<span class=\"n\">root</span> <span class=\"o\">=</span> <span class=\"n\">RootLogger</span><span class=\"p\">(</span><span class=\"n\">WARNING</span><span class=\"p\">)</span>\n<span class=\"n\">Logger</span><span class=\"o\">.</span><span class=\"n\">root</span> <span class=\"o\">=</span> <span class=\"n\">root</span>\n<span class=\"n\">Logger</span><span class=\"o\">.</span><span class=\"n\">manager</span> <span class=\"o\">=</span> <span class=\"n\">Manager</span><span class=\"p\">(</span><span class=\"n\">Logger</span><span class=\"o\">.</span><span class=\"n\">root</span><span class=\"p\">)</span>\n\n<span class=\"c1\">#---------------------------------------------------------------------------</span>\n<span class=\"c1\"># Configuration classes and functions</span>\n<span class=\"c1\">#---------------------------------------------------------------------------</span>\n\n<div class=\"viewcode-block\" id=\"basicConfig\"><a class=\"viewcode-back\" href=\"../logging.html#logging.basicConfig\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">basicConfig</span><span class=\"p\">(</span><span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    Do basic configuration for the logging system.</span>\n\n<span class=\"sd\">    This function does nothing if the root logger already has handlers</span>\n<span class=\"sd\">    configured. It is a convenience method intended for use by simple scripts</span>\n<span class=\"sd\">    to do one-shot configuration of the logging package.</span>\n\n<span class=\"sd\">    The default behaviour is to create a StreamHandler which writes to</span>\n<span class=\"sd\">    sys.stderr, set a formatter using the BASIC_FORMAT format string, and</span>\n<span class=\"sd\">    add the handler to the root logger.</span>\n\n<span class=\"sd\">    A number of optional keyword arguments may be specified, which can alter</span>\n<span class=\"sd\">    the default behaviour.</span>\n\n<span class=\"sd\">    filename  Specifies that a FileHandler be created, using the specified</span>\n<span class=\"sd\">              filename, rather than a StreamHandler.</span>\n<span class=\"sd\">    filemode  Specifies the mode to open the file, if filename is specified</span>\n<span class=\"sd\">              (if filemode is unspecified, it defaults to &#39;a&#39;).</span>\n<span class=\"sd\">    format    Use the specified format string for the handler.</span>\n<span class=\"sd\">    datefmt   Use the specified date/time format.</span>\n<span class=\"sd\">    style     If a format string is specified, use this to specify the</span>\n<span class=\"sd\">              type of format string (possible values &#39;%&#39;, &#39;{&#39;, &#39;$&#39;, for</span>\n<span class=\"sd\">              %-formatting, :meth:`str.format` and :class:`string.Template`</span>\n<span class=\"sd\">              - defaults to &#39;%&#39;).</span>\n<span class=\"sd\">    level     Set the root logger level to the specified level.</span>\n<span class=\"sd\">    stream    Use the specified stream to initialize the StreamHandler. Note</span>\n<span class=\"sd\">              that this argument is incompatible with &#39;filename&#39; - if both</span>\n<span class=\"sd\">              are present, &#39;stream&#39; is ignored.</span>\n<span class=\"sd\">    handlers  If specified, this should be an iterable of already created</span>\n<span class=\"sd\">              handlers, which will be added to the root handler. Any handler</span>\n<span class=\"sd\">              in the list which does not have a formatter assigned will be</span>\n<span class=\"sd\">              assigned the formatter created in this function.</span>\n\n<span class=\"sd\">    Note that you could specify a stream created using open(filename, mode)</span>\n<span class=\"sd\">    rather than passing the filename and mode in. However, it should be</span>\n<span class=\"sd\">    remembered that StreamHandler does not close its stream (since it may be</span>\n<span class=\"sd\">    using sys.stdout or sys.stderr), whereas FileHandler closes its stream</span>\n<span class=\"sd\">    when the handler is closed.</span>\n\n<span class=\"sd\">    .. versionchanged:: 3.2</span>\n<span class=\"sd\">       Added the ``style`` parameter.</span>\n\n<span class=\"sd\">    .. versionchanged:: 3.3</span>\n<span class=\"sd\">       Added the ``handlers`` parameter. A ``ValueError`` is now thrown for</span>\n<span class=\"sd\">       incompatible arguments (e.g. ``handlers`` specified together with</span>\n<span class=\"sd\">       ``filename``/``filemode``, or ``filename``/``filemode`` specified</span>\n<span class=\"sd\">       together with ``stream``, or ``handlers`` specified together with</span>\n<span class=\"sd\">       ``stream``.</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"c1\"># Add thread safety in case someone mistakenly calls</span>\n    <span class=\"c1\"># basicConfig() from multiple threads</span>\n    <span class=\"n\">_acquireLock</span><span class=\"p\">()</span>\n    <span class=\"k\">try</span><span class=\"p\">:</span>\n        <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">root</span><span class=\"o\">.</span><span class=\"n\">handlers</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"n\">handlers</span> <span class=\"o\">=</span> <span class=\"n\">kwargs</span><span class=\"o\">.</span><span class=\"n\">pop</span><span class=\"p\">(</span><span class=\"s2\">&quot;handlers&quot;</span><span class=\"p\">,</span> <span class=\"kc\">None</span><span class=\"p\">)</span>\n            <span class=\"k\">if</span> <span class=\"n\">handlers</span> <span class=\"ow\">is</span> <span class=\"kc\">None</span><span class=\"p\">:</span>\n                <span class=\"k\">if</span> <span class=\"s2\">&quot;stream&quot;</span> <span class=\"ow\">in</span> <span class=\"n\">kwargs</span> <span class=\"ow\">and</span> <span class=\"s2\">&quot;filename&quot;</span> <span class=\"ow\">in</span> <span class=\"n\">kwargs</span><span class=\"p\">:</span>\n                    <span class=\"k\">raise</span> <span class=\"ne\">ValueError</span><span class=\"p\">(</span><span class=\"s2\">&quot;&#39;stream&#39; and &#39;filename&#39; should not be &quot;</span>\n                                     <span class=\"s2\">&quot;specified together&quot;</span><span class=\"p\">)</span>\n            <span class=\"k\">else</span><span class=\"p\">:</span>\n                <span class=\"k\">if</span> <span class=\"s2\">&quot;stream&quot;</span> <span class=\"ow\">in</span> <span class=\"n\">kwargs</span> <span class=\"ow\">or</span> <span class=\"s2\">&quot;filename&quot;</span> <span class=\"ow\">in</span> <span class=\"n\">kwargs</span><span class=\"p\">:</span>\n                    <span class=\"k\">raise</span> <span class=\"ne\">ValueError</span><span class=\"p\">(</span><span class=\"s2\">&quot;&#39;stream&#39; or &#39;filename&#39; should not be &quot;</span>\n                                     <span class=\"s2\">&quot;specified together with &#39;handlers&#39;&quot;</span><span class=\"p\">)</span>\n            <span class=\"k\">if</span> <span class=\"n\">handlers</span> <span class=\"ow\">is</span> <span class=\"kc\">None</span><span class=\"p\">:</span>\n                <span class=\"n\">filename</span> <span class=\"o\">=</span> <span class=\"n\">kwargs</span><span class=\"o\">.</span><span class=\"n\">pop</span><span class=\"p\">(</span><span class=\"s2\">&quot;filename&quot;</span><span class=\"p\">,</span> <span class=\"kc\">None</span><span class=\"p\">)</span>\n                <span class=\"n\">mode</span> <span class=\"o\">=</span> <span class=\"n\">kwargs</span><span class=\"o\">.</span><span class=\"n\">pop</span><span class=\"p\">(</span><span class=\"s2\">&quot;filemode&quot;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;a&#39;</span><span class=\"p\">)</span>\n                <span class=\"k\">if</span> <span class=\"n\">filename</span><span class=\"p\">:</span>\n                    <span class=\"n\">h</span> <span class=\"o\">=</span> <span class=\"n\">FileHandler</span><span class=\"p\">(</span><span class=\"n\">filename</span><span class=\"p\">,</span> <span class=\"n\">mode</span><span class=\"p\">)</span>\n                <span class=\"k\">else</span><span class=\"p\">:</span>\n                    <span class=\"n\">stream</span> <span class=\"o\">=</span> <span class=\"n\">kwargs</span><span class=\"o\">.</span><span class=\"n\">pop</span><span class=\"p\">(</span><span class=\"s2\">&quot;stream&quot;</span><span class=\"p\">,</span> <span class=\"kc\">None</span><span class=\"p\">)</span>\n                    <span class=\"n\">h</span> <span class=\"o\">=</span> <span class=\"n\">StreamHandler</span><span class=\"p\">(</span><span class=\"n\">stream</span><span class=\"p\">)</span>\n                <span class=\"n\">handlers</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">h</span><span class=\"p\">]</span>\n            <span class=\"n\">dfs</span> <span class=\"o\">=</span> <span class=\"n\">kwargs</span><span class=\"o\">.</span><span class=\"n\">pop</span><span class=\"p\">(</span><span class=\"s2\">&quot;datefmt&quot;</span><span class=\"p\">,</span> <span class=\"kc\">None</span><span class=\"p\">)</span>\n            <span class=\"n\">style</span> <span class=\"o\">=</span> <span class=\"n\">kwargs</span><span class=\"o\">.</span><span class=\"n\">pop</span><span class=\"p\">(</span><span class=\"s2\">&quot;style&quot;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;%&#39;</span><span class=\"p\">)</span>\n            <span class=\"k\">if</span> <span class=\"n\">style</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"n\">_STYLES</span><span class=\"p\">:</span>\n                <span class=\"k\">raise</span> <span class=\"ne\">ValueError</span><span class=\"p\">(</span><span class=\"s1\">&#39;Style must be one of: </span><span class=\"si\">%s</span><span class=\"s1\">&#39;</span> <span class=\"o\">%</span> <span class=\"s1\">&#39;,&#39;</span><span class=\"o\">.</span><span class=\"n\">join</span><span class=\"p\">(</span>\n                                 <span class=\"n\">_STYLES</span><span class=\"o\">.</span><span class=\"n\">keys</span><span class=\"p\">()))</span>\n            <span class=\"n\">fs</span> <span class=\"o\">=</span> <span class=\"n\">kwargs</span><span class=\"o\">.</span><span class=\"n\">pop</span><span class=\"p\">(</span><span class=\"s2\">&quot;format&quot;</span><span class=\"p\">,</span> <span class=\"n\">_STYLES</span><span class=\"p\">[</span><span class=\"n\">style</span><span class=\"p\">][</span><span class=\"mi\">1</span><span class=\"p\">])</span>\n            <span class=\"n\">fmt</span> <span class=\"o\">=</span> <span class=\"n\">Formatter</span><span class=\"p\">(</span><span class=\"n\">fs</span><span class=\"p\">,</span> <span class=\"n\">dfs</span><span class=\"p\">,</span> <span class=\"n\">style</span><span class=\"p\">)</span>\n            <span class=\"k\">for</span> <span class=\"n\">h</span> <span class=\"ow\">in</span> <span class=\"n\">handlers</span><span class=\"p\">:</span>\n                <span class=\"k\">if</span> <span class=\"n\">h</span><span class=\"o\">.</span><span class=\"n\">formatter</span> <span class=\"ow\">is</span> <span class=\"kc\">None</span><span class=\"p\">:</span>\n                    <span class=\"n\">h</span><span class=\"o\">.</span><span class=\"n\">setFormatter</span><span class=\"p\">(</span><span class=\"n\">fmt</span><span class=\"p\">)</span>\n                <span class=\"n\">root</span><span class=\"o\">.</span><span class=\"n\">addHandler</span><span class=\"p\">(</span><span class=\"n\">h</span><span class=\"p\">)</span>\n            <span class=\"n\">level</span> <span class=\"o\">=</span> <span class=\"n\">kwargs</span><span class=\"o\">.</span><span class=\"n\">pop</span><span class=\"p\">(</span><span class=\"s2\">&quot;level&quot;</span><span class=\"p\">,</span> <span class=\"kc\">None</span><span class=\"p\">)</span>\n            <span class=\"k\">if</span> <span class=\"n\">level</span> <span class=\"ow\">is</span> <span class=\"ow\">not</span> <span class=\"kc\">None</span><span class=\"p\">:</span>\n                <span class=\"n\">root</span><span class=\"o\">.</span><span class=\"n\">setLevel</span><span class=\"p\">(</span><span class=\"n\">level</span><span class=\"p\">)</span>\n            <span class=\"k\">if</span> <span class=\"n\">kwargs</span><span class=\"p\">:</span>\n                <span class=\"n\">keys</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;, &#39;</span><span class=\"o\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">kwargs</span><span class=\"o\">.</span><span class=\"n\">keys</span><span class=\"p\">())</span>\n                <span class=\"k\">raise</span> <span class=\"ne\">ValueError</span><span class=\"p\">(</span><span class=\"s1\">&#39;Unrecognised argument(s): </span><span class=\"si\">%s</span><span class=\"s1\">&#39;</span> <span class=\"o\">%</span> <span class=\"n\">keys</span><span class=\"p\">)</span>\n    <span class=\"k\">finally</span><span class=\"p\">:</span>\n        <span class=\"n\">_releaseLock</span><span class=\"p\">()</span></div>\n\n<span class=\"c1\">#---------------------------------------------------------------------------</span>\n<span class=\"c1\"># Utility functions at module level.</span>\n<span class=\"c1\"># Basically delegate everything to the root logger.</span>\n<span class=\"c1\">#---------------------------------------------------------------------------</span>\n\n<div class=\"viewcode-block\" id=\"getLogger\"><a class=\"viewcode-back\" href=\"../logging.html#logging.getLogger\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">getLogger</span><span class=\"p\">(</span><span class=\"n\">name</span><span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    Return a logger with the specified name, creating it if necessary.</span>\n\n<span class=\"sd\">    If no name is specified, return the root logger.</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"k\">if</span> <span class=\"n\">name</span><span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"n\">Logger</span><span class=\"o\">.</span><span class=\"n\">manager</span><span class=\"o\">.</span><span class=\"n\">getLogger</span><span class=\"p\">(</span><span class=\"n\">name</span><span class=\"p\">)</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"n\">root</span></div>\n\n<div class=\"viewcode-block\" id=\"critical\"><a class=\"viewcode-back\" href=\"../logging.html#logging.critical\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">critical</span><span class=\"p\">(</span><span class=\"n\">msg</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">args</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    Log a message with severity &#39;CRITICAL&#39; on the root logger. If the logger</span>\n<span class=\"sd\">    has no handlers, call basicConfig() to add a console handler with a</span>\n<span class=\"sd\">    pre-defined format.</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">root</span><span class=\"o\">.</span><span class=\"n\">handlers</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">basicConfig</span><span class=\"p\">()</span>\n    <span class=\"n\">root</span><span class=\"o\">.</span><span class=\"n\">critical</span><span class=\"p\">(</span><span class=\"n\">msg</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">args</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">)</span></div>\n\n<span class=\"n\">fatal</span> <span class=\"o\">=</span> <span class=\"n\">critical</span>\n\n<div class=\"viewcode-block\" id=\"error\"><a class=\"viewcode-back\" href=\"../logging.html#logging.error\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">error</span><span class=\"p\">(</span><span class=\"n\">msg</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">args</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    Log a message with severity &#39;ERROR&#39; on the root logger. If the logger has</span>\n<span class=\"sd\">    no handlers, call basicConfig() to add a console handler with a pre-defined</span>\n<span class=\"sd\">    format.</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">root</span><span class=\"o\">.</span><span class=\"n\">handlers</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">basicConfig</span><span class=\"p\">()</span>\n    <span class=\"n\">root</span><span class=\"o\">.</span><span class=\"n\">error</span><span class=\"p\">(</span><span class=\"n\">msg</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">args</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"exception\"><a class=\"viewcode-back\" href=\"../logging.html#logging.exception\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">exception</span><span class=\"p\">(</span><span class=\"n\">msg</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">args</span><span class=\"p\">,</span> <span class=\"n\">exc_info</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    Log a message with severity &#39;ERROR&#39; on the root logger, with exception</span>\n<span class=\"sd\">    information. If the logger has no handlers, basicConfig() is called to add</span>\n<span class=\"sd\">    a console handler with a pre-defined format.</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"n\">error</span><span class=\"p\">(</span><span class=\"n\">msg</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">args</span><span class=\"p\">,</span> <span class=\"n\">exc_info</span><span class=\"o\">=</span><span class=\"n\">exc_info</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"warning\"><a class=\"viewcode-back\" href=\"../logging.html#logging.warning\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">warning</span><span class=\"p\">(</span><span class=\"n\">msg</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">args</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    Log a message with severity &#39;WARNING&#39; on the root logger. If the logger has</span>\n<span class=\"sd\">    no handlers, call basicConfig() to add a console handler with a pre-defined</span>\n<span class=\"sd\">    format.</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">root</span><span class=\"o\">.</span><span class=\"n\">handlers</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">basicConfig</span><span class=\"p\">()</span>\n    <span class=\"n\">root</span><span class=\"o\">.</span><span class=\"n\">warning</span><span class=\"p\">(</span><span class=\"n\">msg</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">args</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"warn\"><a class=\"viewcode-back\" href=\"../logging.html#logging.warn\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">warn</span><span class=\"p\">(</span><span class=\"n\">msg</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">args</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">):</span>\n    <span class=\"n\">warnings</span><span class=\"o\">.</span><span class=\"n\">warn</span><span class=\"p\">(</span><span class=\"s2\">&quot;The &#39;warn&#39; function is deprecated, &quot;</span>\n        <span class=\"s2\">&quot;use &#39;warning&#39; instead&quot;</span><span class=\"p\">,</span> <span class=\"ne\">DeprecationWarning</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">)</span>\n    <span class=\"n\">warning</span><span class=\"p\">(</span><span class=\"n\">msg</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">args</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"info\"><a class=\"viewcode-back\" href=\"../logging.html#logging.info\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">info</span><span class=\"p\">(</span><span class=\"n\">msg</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">args</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    Log a message with severity &#39;INFO&#39; on the root logger. If the logger has</span>\n<span class=\"sd\">    no handlers, call basicConfig() to add a console handler with a pre-defined</span>\n<span class=\"sd\">    format.</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">root</span><span class=\"o\">.</span><span class=\"n\">handlers</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">basicConfig</span><span class=\"p\">()</span>\n    <span class=\"n\">root</span><span class=\"o\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"n\">msg</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">args</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"debug\"><a class=\"viewcode-back\" href=\"../logging.html#logging.debug\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">debug</span><span class=\"p\">(</span><span class=\"n\">msg</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">args</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    Log a message with severity &#39;DEBUG&#39; on the root logger. If the logger has</span>\n<span class=\"sd\">    no handlers, call basicConfig() to add a console handler with a pre-defined</span>\n<span class=\"sd\">    format.</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">root</span><span class=\"o\">.</span><span class=\"n\">handlers</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">basicConfig</span><span class=\"p\">()</span>\n    <span class=\"n\">root</span><span class=\"o\">.</span><span class=\"n\">debug</span><span class=\"p\">(</span><span class=\"n\">msg</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">args</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"log\"><a class=\"viewcode-back\" href=\"../logging.html#logging.log\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">log</span><span class=\"p\">(</span><span class=\"n\">level</span><span class=\"p\">,</span> <span class=\"n\">msg</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">args</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    Log &#39;msg % args&#39; with the integer severity &#39;level&#39; on the root logger. If</span>\n<span class=\"sd\">    the logger has no handlers, call basicConfig() to add a console handler</span>\n<span class=\"sd\">    with a pre-defined format.</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">root</span><span class=\"o\">.</span><span class=\"n\">handlers</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">basicConfig</span><span class=\"p\">()</span>\n    <span class=\"n\">root</span><span class=\"o\">.</span><span class=\"n\">log</span><span class=\"p\">(</span><span class=\"n\">level</span><span class=\"p\">,</span> <span class=\"n\">msg</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">args</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"disable\"><a class=\"viewcode-back\" href=\"../logging.html#logging.disable\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">disable</span><span class=\"p\">(</span><span class=\"n\">level</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    Disable all logging calls of severity &#39;level&#39; and below.</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"n\">root</span><span class=\"o\">.</span><span class=\"n\">manager</span><span class=\"o\">.</span><span class=\"n\">disable</span> <span class=\"o\">=</span> <span class=\"n\">level</span></div>\n\n<span class=\"k\">def</span> <span class=\"nf\">shutdown</span><span class=\"p\">(</span><span class=\"n\">handlerList</span><span class=\"o\">=</span><span class=\"n\">_handlerList</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    Perform any cleanup actions in the logging system (e.g. flushing</span>\n<span class=\"sd\">    buffers).</span>\n\n<span class=\"sd\">    Should be called at application exit.</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"k\">for</span> <span class=\"n\">wr</span> <span class=\"ow\">in</span> <span class=\"nb\">reversed</span><span class=\"p\">(</span><span class=\"n\">handlerList</span><span class=\"p\">[:]):</span>\n        <span class=\"c1\">#errors might occur, for example, if files are locked</span>\n        <span class=\"c1\">#we just ignore them if raiseExceptions is not set</span>\n        <span class=\"k\">try</span><span class=\"p\">:</span>\n            <span class=\"n\">h</span> <span class=\"o\">=</span> <span class=\"n\">wr</span><span class=\"p\">()</span>\n            <span class=\"k\">if</span> <span class=\"n\">h</span><span class=\"p\">:</span>\n                <span class=\"k\">try</span><span class=\"p\">:</span>\n                    <span class=\"n\">h</span><span class=\"o\">.</span><span class=\"n\">acquire</span><span class=\"p\">()</span>\n                    <span class=\"n\">h</span><span class=\"o\">.</span><span class=\"n\">flush</span><span class=\"p\">()</span>\n                    <span class=\"n\">h</span><span class=\"o\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n                <span class=\"k\">except</span> <span class=\"p\">(</span><span class=\"ne\">OSError</span><span class=\"p\">,</span> <span class=\"ne\">ValueError</span><span class=\"p\">):</span>\n                    <span class=\"c1\"># Ignore errors which might be caused</span>\n                    <span class=\"c1\"># because handlers have been closed but</span>\n                    <span class=\"c1\"># references to them are still around at</span>\n                    <span class=\"c1\"># application exit.</span>\n                    <span class=\"k\">pass</span>\n                <span class=\"k\">finally</span><span class=\"p\">:</span>\n                    <span class=\"n\">h</span><span class=\"o\">.</span><span class=\"n\">release</span><span class=\"p\">()</span>\n        <span class=\"k\">except</span><span class=\"p\">:</span> <span class=\"c1\"># ignore everything, as we&#39;re shutting down</span>\n            <span class=\"k\">if</span> <span class=\"n\">raiseExceptions</span><span class=\"p\">:</span>\n                <span class=\"k\">raise</span>\n            <span class=\"c1\">#else, swallow</span>\n\n<span class=\"c1\">#Let&#39;s try and shutdown automatically on application exit...</span>\n<span class=\"kn\">import</span> <span class=\"nn\">atexit</span>\n<span class=\"n\">atexit</span><span class=\"o\">.</span><span class=\"n\">register</span><span class=\"p\">(</span><span class=\"n\">shutdown</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># Null handler</span>\n\n<div class=\"viewcode-block\" id=\"NullHandler\"><a class=\"viewcode-back\" href=\"../logging.html#logging.NullHandler\">[文档]</a><span class=\"k\">class</span> <span class=\"nc\">NullHandler</span><span class=\"p\">(</span><span class=\"n\">Handler</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    This handler does nothing. It&#39;s intended to be used to avoid the</span>\n<span class=\"sd\">    &quot;No handlers could be found for logger XXX&quot; one-off warning. This is</span>\n<span class=\"sd\">    important for library code, which may contain code to log events. If a user</span>\n<span class=\"sd\">    of the library does not configure logging, the one-off warning might be</span>\n<span class=\"sd\">    produced; to avoid this, the library developer simply needs to instantiate</span>\n<span class=\"sd\">    a NullHandler and add it to the top-level logger of the library module or</span>\n<span class=\"sd\">    package.</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n<div class=\"viewcode-block\" id=\"NullHandler.handle\"><a class=\"viewcode-back\" href=\"../logging.html#logging.NullHandler.handle\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">handle</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">record</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;Stub.&quot;&quot;&quot;</span></div>\n\n<div class=\"viewcode-block\" id=\"NullHandler.emit\"><a class=\"viewcode-back\" href=\"../logging.html#logging.NullHandler.emit\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">emit</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">record</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;Stub.&quot;&quot;&quot;</span></div>\n\n<div class=\"viewcode-block\" id=\"NullHandler.createLock\"><a class=\"viewcode-back\" href=\"../logging.html#logging.NullHandler.createLock\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">createLock</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">lock</span> <span class=\"o\">=</span> <span class=\"kc\">None</span></div></div>\n\n<span class=\"c1\"># Warnings integration</span>\n\n<span class=\"n\">_warnings_showwarning</span> <span class=\"o\">=</span> <span class=\"kc\">None</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">_showwarning</span><span class=\"p\">(</span><span class=\"n\">message</span><span class=\"p\">,</span> <span class=\"n\">category</span><span class=\"p\">,</span> <span class=\"n\">filename</span><span class=\"p\">,</span> <span class=\"n\">lineno</span><span class=\"p\">,</span> <span class=\"n\">file</span><span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">,</span> <span class=\"n\">line</span><span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    Implementation of showwarnings which redirects to logging, which will first</span>\n<span class=\"sd\">    check to see if the file parameter is None. If a file is specified, it will</span>\n<span class=\"sd\">    delegate to the original warnings implementation of showwarning. Otherwise,</span>\n<span class=\"sd\">    it will call warnings.formatwarning and will log the resulting string to a</span>\n<span class=\"sd\">    warnings logger named &quot;py.warnings&quot; with level logging.WARNING.</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"k\">if</span> <span class=\"n\">file</span> <span class=\"ow\">is</span> <span class=\"ow\">not</span> <span class=\"kc\">None</span><span class=\"p\">:</span>\n        <span class=\"k\">if</span> <span class=\"n\">_warnings_showwarning</span> <span class=\"ow\">is</span> <span class=\"ow\">not</span> <span class=\"kc\">None</span><span class=\"p\">:</span>\n            <span class=\"n\">_warnings_showwarning</span><span class=\"p\">(</span><span class=\"n\">message</span><span class=\"p\">,</span> <span class=\"n\">category</span><span class=\"p\">,</span> <span class=\"n\">filename</span><span class=\"p\">,</span> <span class=\"n\">lineno</span><span class=\"p\">,</span> <span class=\"n\">file</span><span class=\"p\">,</span> <span class=\"n\">line</span><span class=\"p\">)</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">s</span> <span class=\"o\">=</span> <span class=\"n\">warnings</span><span class=\"o\">.</span><span class=\"n\">formatwarning</span><span class=\"p\">(</span><span class=\"n\">message</span><span class=\"p\">,</span> <span class=\"n\">category</span><span class=\"p\">,</span> <span class=\"n\">filename</span><span class=\"p\">,</span> <span class=\"n\">lineno</span><span class=\"p\">,</span> <span class=\"n\">line</span><span class=\"p\">)</span>\n        <span class=\"n\">logger</span> <span class=\"o\">=</span> <span class=\"n\">getLogger</span><span class=\"p\">(</span><span class=\"s2\">&quot;py.warnings&quot;</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">handlers</span><span class=\"p\">:</span>\n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">addHandler</span><span class=\"p\">(</span><span class=\"n\">NullHandler</span><span class=\"p\">())</span>\n        <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">warning</span><span class=\"p\">(</span><span class=\"s2\">&quot;</span><span class=\"si\">%s</span><span class=\"s2\">&quot;</span><span class=\"p\">,</span> <span class=\"n\">s</span><span class=\"p\">)</span>\n\n<div class=\"viewcode-block\" id=\"captureWarnings\"><a class=\"viewcode-back\" href=\"../logging.html#logging.captureWarnings\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">captureWarnings</span><span class=\"p\">(</span><span class=\"n\">capture</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    If capture is true, redirect all warnings to the logging package.</span>\n<span class=\"sd\">    If capture is False, ensure that warnings are not redirected to logging</span>\n<span class=\"sd\">    but to their original destinations.</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"k\">global</span> <span class=\"n\">_warnings_showwarning</span>\n    <span class=\"k\">if</span> <span class=\"n\">capture</span><span class=\"p\">:</span>\n        <span class=\"k\">if</span> <span class=\"n\">_warnings_showwarning</span> <span class=\"ow\">is</span> <span class=\"kc\">None</span><span class=\"p\">:</span>\n            <span class=\"n\">_warnings_showwarning</span> <span class=\"o\">=</span> <span class=\"n\">warnings</span><span class=\"o\">.</span><span class=\"n\">showwarning</span>\n            <span class=\"n\">warnings</span><span class=\"o\">.</span><span class=\"n\">showwarning</span> <span class=\"o\">=</span> <span class=\"n\">_showwarning</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"k\">if</span> <span class=\"n\">_warnings_showwarning</span> <span class=\"ow\">is</span> <span class=\"ow\">not</span> <span class=\"kc\">None</span><span class=\"p\">:</span>\n            <span class=\"n\">warnings</span><span class=\"o\">.</span><span class=\"n\">showwarning</span> <span class=\"o\">=</span> <span class=\"n\">_warnings_showwarning</span>\n            <span class=\"n\">_warnings_showwarning</span> <span class=\"o\">=</span> <span class=\"kc\">None</span></div>\n</pre></div>\n\n           </div>\n           \n          </div>\n          <footer>\n  \n\n  <hr/>\n\n  <div role=\"contentinfo\">\n    <p>\n        &copy; Copyright 2019, wzpan\n\n    </p>\n  </div>\n  Built with <a href=\"http://sphinx-doc.org/\">Sphinx</a> using a <a href=\"https://github.com/rtfd/sphinx_rtd_theme\">theme</a> provided by <a href=\"https://readthedocs.org\">Read the Docs</a>. \n\n</footer>\n\n        </div>\n      </div>\n\n    </section>\n\n  </div>\n  \n\n\n  <script type=\"text/javascript\">\n      jQuery(function () {\n          SphinxRtdTheme.Navigation.enable(true);\n      });\n  </script>\n\n  \n  \n    \n   \n\n</body>\n</html>"
  },
  {
    "path": "docs/_modules/plugins/Camera.html",
    "content": "\n\n<!DOCTYPE html>\n<!--[if IE 8]><html class=\"no-js lt-ie9\" lang=\"zh-CN\" > <![endif]-->\n<!--[if gt IE 8]><!--> <html class=\"no-js\" lang=\"zh-CN\" > <!--<![endif]-->\n<head>\n  <meta charset=\"utf-8\">\n  \n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  \n  <title>plugins.Camera &mdash; wukong-robot 1.2.0 文档</title>\n  \n\n  \n  \n  \n  \n\n  \n  <script type=\"text/javascript\" src=\"../../_static/js/modernizr.min.js\"></script>\n  \n    \n      <script type=\"text/javascript\" id=\"documentation_options\" data-url_root=\"../../\" src=\"../../_static/documentation_options.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/jquery.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/underscore.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/doctools.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/language_data.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/translations.js\"></script>\n    \n    <script type=\"text/javascript\" src=\"../../_static/js/theme.js\"></script>\n\n    \n\n  \n  <link rel=\"stylesheet\" href=\"../../_static/css/theme.css\" type=\"text/css\" />\n  <link rel=\"stylesheet\" href=\"../../_static/pygments.css\" type=\"text/css\" />\n    <link rel=\"index\" title=\"索引\" href=\"../../genindex.html\" />\n    <link rel=\"search\" title=\"搜索\" href=\"../../search.html\" /> \n</head>\n\n<body class=\"wy-body-for-nav\">\n\n   \n  <div class=\"wy-grid-for-nav\">\n    \n    <nav data-toggle=\"wy-nav-shift\" class=\"wy-nav-side\">\n      <div class=\"wy-side-scroll\">\n        <div class=\"wy-side-nav-search\" >\n          \n\n          \n            <a href=\"../../index.html\" class=\"icon icon-home\"> wukong-robot\n          \n\n          \n          </a>\n\n          \n            \n            \n          \n\n          \n<div role=\"search\">\n  <form id=\"rtd-search-form\" class=\"wy-form\" action=\"../../search.html\" method=\"get\">\n    <input type=\"text\" name=\"q\" placeholder=\"Search docs\" />\n    <input type=\"hidden\" name=\"check_keywords\" value=\"yes\" />\n    <input type=\"hidden\" name=\"area\" value=\"default\" />\n  </form>\n</div>\n\n          \n        </div>\n\n        <div class=\"wy-menu wy-menu-vertical\" data-spy=\"affix\" role=\"navigation\" aria-label=\"main navigation\">\n          \n            \n            \n              \n            \n            \n              <!-- Local TOC -->\n              <div class=\"local-toc\"></div>\n            \n          \n        </div>\n      </div>\n    </nav>\n\n    <section data-toggle=\"wy-nav-shift\" class=\"wy-nav-content-wrap\">\n\n      \n      <nav class=\"wy-nav-top\" aria-label=\"top navigation\">\n        \n          <i data-toggle=\"wy-nav-top\" class=\"fa fa-bars\"></i>\n          <a href=\"../../index.html\">wukong-robot</a>\n        \n      </nav>\n\n\n      <div class=\"wy-nav-content\">\n        \n        <div class=\"rst-content\">\n        \n          \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<div role=\"navigation\" aria-label=\"breadcrumbs navigation\">\n\n  <ul class=\"wy-breadcrumbs\">\n    \n      <li><a href=\"../../index.html\">Docs</a> &raquo;</li>\n        \n          <li><a href=\"../index.html\">模块代码</a> &raquo;</li>\n        \n      <li>plugins.Camera</li>\n    \n    \n      <li class=\"wy-breadcrumbs-aside\">\n        \n      </li>\n    \n  </ul>\n\n  \n  <hr/>\n</div>\n          <div role=\"main\" class=\"document\" itemscope=\"itemscope\" itemtype=\"http://schema.org/Article\">\n           <div itemprop=\"articleBody\">\n            \n  <h1>plugins.Camera 源代码</h1><div class=\"highlight\"><pre>\n<span></span><span class=\"c1\"># -*- coding: utf-8-*-</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">import</span> <span class=\"nn\">subprocess</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">from</span> <span class=\"nn\">robot</span> <span class=\"k\">import</span> <span class=\"n\">config</span><span class=\"p\">,</span> <span class=\"n\">constants</span><span class=\"p\">,</span> <span class=\"n\">logging</span>\n<span class=\"kn\">from</span> <span class=\"nn\">robot.sdk.AbstractPlugin</span> <span class=\"k\">import</span> <span class=\"n\">AbstractPlugin</span>\n\n<span class=\"n\">logger</span> <span class=\"o\">=</span> <span class=\"n\">logging</span><span class=\"o\">.</span><span class=\"n\">getLogger</span><span class=\"p\">(</span><span class=\"vm\">__name__</span><span class=\"p\">)</span>\n\n<div class=\"viewcode-block\" id=\"Plugin\"><a class=\"viewcode-back\" href=\"../../plugins.html#plugins.Camera.Plugin\">[文档]</a><span class=\"k\">class</span> <span class=\"nc\">Plugin</span><span class=\"p\">(</span><span class=\"n\">AbstractPlugin</span><span class=\"p\">):</span>\n\n    <span class=\"n\">SLUG</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;camera&quot;</span>\n\n<div class=\"viewcode-block\" id=\"Plugin.handle\"><a class=\"viewcode-back\" href=\"../../plugins.html#plugins.Camera.Plugin.handle\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">handle</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">text</span><span class=\"p\">,</span> <span class=\"n\">parsed</span><span class=\"p\">):</span>\n        <span class=\"n\">quality</span> <span class=\"o\">=</span> <span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;/camera/quality&#39;</span><span class=\"p\">,</span> <span class=\"mi\">100</span><span class=\"p\">)</span>\n        <span class=\"n\">count_down</span> <span class=\"o\">=</span> <span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;/camera/count_down&#39;</span><span class=\"p\">,</span> <span class=\"mi\">3</span><span class=\"p\">)</span>\n        <span class=\"n\">dest_path</span> <span class=\"o\">=</span> <span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;/camera/dest_path&#39;</span><span class=\"p\">,</span> <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">expanduser</span><span class=\"p\">(</span><span class=\"s1\">&#39;~/pictures&#39;</span><span class=\"p\">))</span>\n        <span class=\"n\">device</span> <span class=\"o\">=</span> <span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;/camera/device&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;/dev/video0&#39;</span><span class=\"p\">)</span>\n        <span class=\"n\">vertical_flip</span> <span class=\"o\">=</span> <span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;/camera/verical_flip&#39;</span><span class=\"p\">,</span> <span class=\"kc\">False</span><span class=\"p\">)</span>\n        <span class=\"n\">horizontal_flip</span> <span class=\"o\">=</span> <span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;/camera/horizontal_flip&#39;</span><span class=\"p\">,</span> <span class=\"kc\">False</span><span class=\"p\">)</span>\n        <span class=\"n\">sound</span> <span class=\"o\">=</span> <span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;/camera/sound&#39;</span><span class=\"p\">,</span> <span class=\"kc\">True</span><span class=\"p\">)</span>\n        <span class=\"n\">camera_type</span> <span class=\"o\">=</span> <span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;/camera/type&#39;</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">has</span><span class=\"p\">(</span><span class=\"s1\">&#39;/camera/usb_camera&#39;</span><span class=\"p\">)</span> <span class=\"ow\">and</span> <span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;/camera/usb_camera&#39;</span><span class=\"p\">):</span>\n            <span class=\"n\">camera_type</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n        <span class=\"k\">if</span> <span class=\"nb\">any</span><span class=\"p\">(</span><span class=\"n\">word</span> <span class=\"ow\">in</span> <span class=\"n\">text</span> <span class=\"k\">for</span> <span class=\"n\">word</span> <span class=\"ow\">in</span> <span class=\"p\">[</span><span class=\"sa\">u</span><span class=\"s2\">&quot;安静&quot;</span><span class=\"p\">,</span> <span class=\"sa\">u</span><span class=\"s2\">&quot;偷偷&quot;</span><span class=\"p\">,</span> <span class=\"sa\">u</span><span class=\"s2\">&quot;悄悄&quot;</span><span class=\"p\">]):</span>\n            <span class=\"n\">sound</span> <span class=\"o\">=</span> <span class=\"kc\">False</span>\n        <span class=\"k\">try</span><span class=\"p\">:</span>\n            <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">exists</span><span class=\"p\">(</span><span class=\"n\">dest_path</span><span class=\"p\">):</span>\n                <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">makedirs</span><span class=\"p\">(</span><span class=\"n\">dest_path</span><span class=\"p\">)</span>\n        <span class=\"k\">except</span> <span class=\"ne\">Exception</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">say</span><span class=\"p\">(</span><span class=\"sa\">u</span><span class=\"s2\">&quot;抱歉，照片目录创建失败&quot;</span><span class=\"p\">,</span> <span class=\"n\">cache</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">)</span>\n            <span class=\"k\">return</span>\n        <span class=\"n\">dest_file</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">dest_path</span><span class=\"p\">,</span> <span class=\"s2\">&quot;</span><span class=\"si\">%s</span><span class=\"s2\">.jpg&quot;</span> <span class=\"o\">%</span> <span class=\"n\">time</span><span class=\"o\">.</span><span class=\"n\">time</span><span class=\"p\">())</span>\n        <span class=\"k\">if</span> <span class=\"n\">camera_type</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"c1\"># usb camera</span>\n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s1\">&#39;usb camera&#39;</span><span class=\"p\">)</span>\n            <span class=\"n\">command</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s1\">&#39;fswebcam&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;--no-banner&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;-r&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;1024x765&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;-q&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;-d&#39;</span><span class=\"p\">,</span> <span class=\"n\">device</span><span class=\"p\">]</span>\n            <span class=\"k\">if</span> <span class=\"n\">vertical_flip</span><span class=\"p\">:</span>\n                <span class=\"n\">command</span><span class=\"o\">.</span><span class=\"n\">extend</span><span class=\"p\">([</span><span class=\"s1\">&#39;-s&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;v&#39;</span><span class=\"p\">])</span>\n            <span class=\"k\">if</span> <span class=\"n\">horizontal_flip</span><span class=\"p\">:</span>\n                <span class=\"n\">command</span><span class=\"o\">.</span><span class=\"n\">extend</span><span class=\"p\">([</span><span class=\"s1\">&#39;-s&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;h&#39;</span><span class=\"p\">])</span>\n            <span class=\"n\">command</span><span class=\"o\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">dest_file</span><span class=\"p\">)</span>\n        <span class=\"k\">elif</span> <span class=\"n\">camera_type</span> <span class=\"o\">==</span> <span class=\"mi\">1</span><span class=\"p\">:</span>\n            <span class=\"c1\"># Raspberry Pi 5MP</span>\n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s1\">&#39;Raspberry Pi 5MP camera&#39;</span><span class=\"p\">)</span>\n            <span class=\"n\">command</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s1\">&#39;raspistill&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;-o&#39;</span><span class=\"p\">,</span> <span class=\"n\">dest_file</span><span class=\"p\">,</span> <span class=\"s1\">&#39;-q&#39;</span><span class=\"p\">,</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">quality</span><span class=\"p\">)]</span>\n            <span class=\"k\">if</span> <span class=\"n\">count_down</span> <span class=\"o\">&gt;</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">sound</span><span class=\"p\">:</span>\n                <span class=\"n\">command</span><span class=\"o\">.</span><span class=\"n\">extend</span><span class=\"p\">([</span><span class=\"s1\">&#39;-t&#39;</span><span class=\"p\">,</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">count_down</span><span class=\"o\">*</span><span class=\"mi\">1000</span><span class=\"p\">)])</span>\n            <span class=\"k\">if</span> <span class=\"n\">vertical_flip</span><span class=\"p\">:</span>\n                <span class=\"n\">command</span><span class=\"o\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"s1\">&#39;-vf&#39;</span><span class=\"p\">)</span>\n            <span class=\"k\">if</span> <span class=\"n\">horizontal_flip</span><span class=\"p\">:</span>\n                <span class=\"n\">command</span><span class=\"o\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"s1\">&#39;-hf&#39;</span><span class=\"p\">)</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"c1\"># notebook camera</span>\n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s1\">&#39;notebook camera&#39;</span><span class=\"p\">)</span>\n            <span class=\"n\">command</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s1\">&#39;imagesnap&#39;</span><span class=\"p\">,</span> <span class=\"n\">dest_file</span><span class=\"p\">]</span>\n            <span class=\"k\">if</span> <span class=\"n\">count_down</span> <span class=\"o\">&gt;</span> <span class=\"mi\">0</span> <span class=\"ow\">and</span> <span class=\"n\">sound</span><span class=\"p\">:</span>\n                <span class=\"n\">command</span><span class=\"o\">.</span><span class=\"n\">extend</span><span class=\"p\">([</span><span class=\"s1\">&#39;-w&#39;</span><span class=\"p\">,</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">count_down</span><span class=\"p\">)])</span>\n        <span class=\"k\">if</span> <span class=\"n\">sound</span> <span class=\"ow\">and</span> <span class=\"n\">count_down</span> <span class=\"o\">&gt;</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">say</span><span class=\"p\">(</span><span class=\"sa\">u</span><span class=\"s2\">&quot;收到，</span><span class=\"si\">%d</span><span class=\"s2\">秒后启动拍照&quot;</span> <span class=\"o\">%</span> <span class=\"p\">(</span><span class=\"n\">count_down</span><span class=\"p\">),</span> <span class=\"n\">cache</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">)</span>\n            <span class=\"k\">if</span> <span class=\"n\">camera_type</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n                <span class=\"n\">time</span><span class=\"o\">.</span><span class=\"n\">sleep</span><span class=\"p\">(</span><span class=\"n\">count_down</span><span class=\"p\">)</span>\n\n        <span class=\"k\">try</span><span class=\"p\">:</span>\n            <span class=\"n\">subprocess</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"n\">command</span><span class=\"p\">,</span> <span class=\"n\">shell</span><span class=\"o\">=</span><span class=\"kc\">False</span><span class=\"p\">,</span> <span class=\"n\">check</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">)</span>\n            <span class=\"k\">if</span> <span class=\"n\">sound</span><span class=\"p\">:</span>                \n                <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">play</span><span class=\"p\">(</span><span class=\"n\">constants</span><span class=\"o\">.</span><span class=\"n\">getData</span><span class=\"p\">(</span><span class=\"s1\">&#39;camera.wav&#39;</span><span class=\"p\">))</span>\n                <span class=\"n\">photo_url</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;http://</span><span class=\"si\">{}</span><span class=\"s1\">:</span><span class=\"si\">{}</span><span class=\"s1\">/photo/</span><span class=\"si\">{}</span><span class=\"s1\">&#39;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;/server/host&#39;</span><span class=\"p\">),</span> <span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;/server/port&#39;</span><span class=\"p\">),</span> <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">basename</span><span class=\"p\">(</span><span class=\"n\">dest_file</span><span class=\"p\">))</span>\n                <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">say</span><span class=\"p\">(</span><span class=\"sa\">u</span><span class=\"s1\">&#39;拍照成功：</span><span class=\"si\">{}</span><span class=\"s1\">&#39;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">photo_url</span><span class=\"p\">),</span> <span class=\"n\">cache</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">)</span>\n        <span class=\"k\">except</span> <span class=\"n\">subprocess</span><span class=\"o\">.</span><span class=\"n\">CalledProcessError</span> <span class=\"k\">as</span> <span class=\"n\">e</span><span class=\"p\">:</span>\n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">error</span><span class=\"p\">(</span><span class=\"n\">e</span><span class=\"p\">)</span>\n            <span class=\"k\">if</span> <span class=\"n\">sound</span><span class=\"p\">:</span>\n                <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">say</span><span class=\"p\">(</span><span class=\"sa\">u</span><span class=\"s2\">&quot;拍照失败，请检查相机是否连接正确&quot;</span><span class=\"p\">,</span> <span class=\"n\">cache</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">)</span>        </div>\n\n\n<div class=\"viewcode-block\" id=\"Plugin.isValid\"><a class=\"viewcode-back\" href=\"../../plugins.html#plugins.Camera.Plugin.isValid\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">isValid</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">text</span><span class=\"p\">,</span> <span class=\"n\">parsed</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"nb\">any</span><span class=\"p\">(</span><span class=\"n\">word</span> <span class=\"ow\">in</span> <span class=\"n\">text</span> <span class=\"k\">for</span> <span class=\"n\">word</span> <span class=\"ow\">in</span> <span class=\"p\">[</span><span class=\"s2\">&quot;拍照&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;拍张照&quot;</span><span class=\"p\">])</span></div></div>\n</pre></div>\n\n           </div>\n           \n          </div>\n          <footer>\n  \n\n  <hr/>\n\n  <div role=\"contentinfo\">\n    <p>\n        &copy; Copyright 2019, wzpan\n\n    </p>\n  </div>\n  Built with <a href=\"http://sphinx-doc.org/\">Sphinx</a> using a <a href=\"https://github.com/rtfd/sphinx_rtd_theme\">theme</a> provided by <a href=\"https://readthedocs.org\">Read the Docs</a>. \n\n</footer>\n\n        </div>\n      </div>\n\n    </section>\n\n  </div>\n  \n\n\n  <script type=\"text/javascript\">\n      jQuery(function () {\n          SphinxRtdTheme.Navigation.enable(true);\n      });\n  </script>\n\n  \n  \n    \n   \n\n</body>\n</html>"
  },
  {
    "path": "docs/_modules/plugins/CleanCache.html",
    "content": "\n\n<!DOCTYPE html>\n<!--[if IE 8]><html class=\"no-js lt-ie9\" lang=\"zh-CN\" > <![endif]-->\n<!--[if gt IE 8]><!--> <html class=\"no-js\" lang=\"zh-CN\" > <!--<![endif]-->\n<head>\n  <meta charset=\"utf-8\">\n  \n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  \n  <title>plugins.CleanCache &mdash; wukong-robot 1.2.0 文档</title>\n  \n\n  \n  \n  \n  \n\n  \n  <script type=\"text/javascript\" src=\"../../_static/js/modernizr.min.js\"></script>\n  \n    \n      <script type=\"text/javascript\" id=\"documentation_options\" data-url_root=\"../../\" src=\"../../_static/documentation_options.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/jquery.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/underscore.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/doctools.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/language_data.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/translations.js\"></script>\n    \n    <script type=\"text/javascript\" src=\"../../_static/js/theme.js\"></script>\n\n    \n\n  \n  <link rel=\"stylesheet\" href=\"../../_static/css/theme.css\" type=\"text/css\" />\n  <link rel=\"stylesheet\" href=\"../../_static/pygments.css\" type=\"text/css\" />\n    <link rel=\"index\" title=\"索引\" href=\"../../genindex.html\" />\n    <link rel=\"search\" title=\"搜索\" href=\"../../search.html\" /> \n</head>\n\n<body class=\"wy-body-for-nav\">\n\n   \n  <div class=\"wy-grid-for-nav\">\n    \n    <nav data-toggle=\"wy-nav-shift\" class=\"wy-nav-side\">\n      <div class=\"wy-side-scroll\">\n        <div class=\"wy-side-nav-search\" >\n          \n\n          \n            <a href=\"../../index.html\" class=\"icon icon-home\"> wukong-robot\n          \n\n          \n          </a>\n\n          \n            \n            \n          \n\n          \n<div role=\"search\">\n  <form id=\"rtd-search-form\" class=\"wy-form\" action=\"../../search.html\" method=\"get\">\n    <input type=\"text\" name=\"q\" placeholder=\"Search docs\" />\n    <input type=\"hidden\" name=\"check_keywords\" value=\"yes\" />\n    <input type=\"hidden\" name=\"area\" value=\"default\" />\n  </form>\n</div>\n\n          \n        </div>\n\n        <div class=\"wy-menu wy-menu-vertical\" data-spy=\"affix\" role=\"navigation\" aria-label=\"main navigation\">\n          \n            \n            \n              \n            \n            \n              <!-- Local TOC -->\n              <div class=\"local-toc\"></div>\n            \n          \n        </div>\n      </div>\n    </nav>\n\n    <section data-toggle=\"wy-nav-shift\" class=\"wy-nav-content-wrap\">\n\n      \n      <nav class=\"wy-nav-top\" aria-label=\"top navigation\">\n        \n          <i data-toggle=\"wy-nav-top\" class=\"fa fa-bars\"></i>\n          <a href=\"../../index.html\">wukong-robot</a>\n        \n      </nav>\n\n\n      <div class=\"wy-nav-content\">\n        \n        <div class=\"rst-content\">\n        \n          \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<div role=\"navigation\" aria-label=\"breadcrumbs navigation\">\n\n  <ul class=\"wy-breadcrumbs\">\n    \n      <li><a href=\"../../index.html\">Docs</a> &raquo;</li>\n        \n          <li><a href=\"../index.html\">模块代码</a> &raquo;</li>\n        \n      <li>plugins.CleanCache</li>\n    \n    \n      <li class=\"wy-breadcrumbs-aside\">\n        \n      </li>\n    \n  </ul>\n\n  \n  <hr/>\n</div>\n          <div role=\"main\" class=\"document\" itemscope=\"itemscope\" itemtype=\"http://schema.org/Article\">\n           <div itemprop=\"articleBody\">\n            \n  <h1>plugins.CleanCache 源代码</h1><div class=\"highlight\"><pre>\n<span></span><span class=\"c1\"># -*- coding: utf-8-*-</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">from</span> <span class=\"nn\">robot</span> <span class=\"k\">import</span> <span class=\"n\">constants</span><span class=\"p\">,</span> <span class=\"n\">utils</span>\n<span class=\"kn\">from</span> <span class=\"nn\">robot.sdk.AbstractPlugin</span> <span class=\"k\">import</span> <span class=\"n\">AbstractPlugin</span>\n\n<div class=\"viewcode-block\" id=\"Plugin\"><a class=\"viewcode-back\" href=\"../../plugins.html#plugins.CleanCache.Plugin\">[文档]</a><span class=\"k\">class</span> <span class=\"nc\">Plugin</span><span class=\"p\">(</span><span class=\"n\">AbstractPlugin</span><span class=\"p\">):</span>\n\n    <span class=\"n\">SLUG</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;cleancache&#39;</span>\n\n<div class=\"viewcode-block\" id=\"Plugin.handle\"><a class=\"viewcode-back\" href=\"../../plugins.html#plugins.CleanCache.Plugin.handle\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">handle</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">text</span><span class=\"p\">,</span> <span class=\"n\">parsed</span><span class=\"p\">):</span>\n        <span class=\"n\">temp</span> <span class=\"o\">=</span> <span class=\"n\">constants</span><span class=\"o\">.</span><span class=\"n\">TEMP_PATH</span>\n        <span class=\"k\">for</span> <span class=\"n\">f</span> <span class=\"ow\">in</span> <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">listdir</span><span class=\"p\">(</span><span class=\"n\">temp</span><span class=\"p\">):</span>\n            <span class=\"k\">if</span> <span class=\"n\">f</span> <span class=\"o\">!=</span> <span class=\"s1\">&#39;DIR&#39;</span><span class=\"p\">:</span>\n                <span class=\"n\">utils</span><span class=\"o\">.</span><span class=\"n\">check_and_delete</span><span class=\"p\">(</span><span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">temp</span><span class=\"p\">,</span> <span class=\"n\">f</span><span class=\"p\">))</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">say</span><span class=\"p\">(</span><span class=\"sa\">u</span><span class=\"s1\">&#39;缓存目录已清空&#39;</span><span class=\"p\">,</span> <span class=\"n\">cache</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"Plugin.isValid\"><a class=\"viewcode-back\" href=\"../../plugins.html#plugins.CleanCache.Plugin.isValid\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">isValid</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">text</span><span class=\"p\">,</span> <span class=\"n\">parsed</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"nb\">any</span><span class=\"p\">(</span><span class=\"n\">word</span> <span class=\"ow\">in</span> <span class=\"n\">text</span><span class=\"o\">.</span><span class=\"n\">lower</span><span class=\"p\">()</span> <span class=\"k\">for</span> <span class=\"n\">word</span> <span class=\"ow\">in</span> <span class=\"p\">[</span><span class=\"s2\">&quot;清除缓存&quot;</span><span class=\"p\">,</span> <span class=\"sa\">u</span><span class=\"s2\">&quot;清空缓存&quot;</span><span class=\"p\">,</span> <span class=\"sa\">u</span><span class=\"s2\">&quot;清缓存&quot;</span><span class=\"p\">])</span></div></div>\n</pre></div>\n\n           </div>\n           \n          </div>\n          <footer>\n  \n\n  <hr/>\n\n  <div role=\"contentinfo\">\n    <p>\n        &copy; Copyright 2019, wzpan\n\n    </p>\n  </div>\n  Built with <a href=\"http://sphinx-doc.org/\">Sphinx</a> using a <a href=\"https://github.com/rtfd/sphinx_rtd_theme\">theme</a> provided by <a href=\"https://readthedocs.org\">Read the Docs</a>. \n\n</footer>\n\n        </div>\n      </div>\n\n    </section>\n\n  </div>\n  \n\n\n  <script type=\"text/javascript\">\n      jQuery(function () {\n          SphinxRtdTheme.Navigation.enable(true);\n      });\n  </script>\n\n  \n  \n    \n   \n\n</body>\n</html>"
  },
  {
    "path": "docs/_modules/plugins/Echo.html",
    "content": "\n\n<!DOCTYPE html>\n<!--[if IE 8]><html class=\"no-js lt-ie9\" lang=\"zh-CN\" > <![endif]-->\n<!--[if gt IE 8]><!--> <html class=\"no-js\" lang=\"zh-CN\" > <!--<![endif]-->\n<head>\n  <meta charset=\"utf-8\">\n  \n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  \n  <title>plugins.Echo &mdash; wukong-robot 1.2.0 文档</title>\n  \n\n  \n  \n  \n  \n\n  \n  <script type=\"text/javascript\" src=\"../../_static/js/modernizr.min.js\"></script>\n  \n    \n      <script type=\"text/javascript\" id=\"documentation_options\" data-url_root=\"../../\" src=\"../../_static/documentation_options.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/jquery.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/underscore.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/doctools.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/language_data.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/translations.js\"></script>\n    \n    <script type=\"text/javascript\" src=\"../../_static/js/theme.js\"></script>\n\n    \n\n  \n  <link rel=\"stylesheet\" href=\"../../_static/css/theme.css\" type=\"text/css\" />\n  <link rel=\"stylesheet\" href=\"../../_static/pygments.css\" type=\"text/css\" />\n    <link rel=\"index\" title=\"索引\" href=\"../../genindex.html\" />\n    <link rel=\"search\" title=\"搜索\" href=\"../../search.html\" /> \n</head>\n\n<body class=\"wy-body-for-nav\">\n\n   \n  <div class=\"wy-grid-for-nav\">\n    \n    <nav data-toggle=\"wy-nav-shift\" class=\"wy-nav-side\">\n      <div class=\"wy-side-scroll\">\n        <div class=\"wy-side-nav-search\" >\n          \n\n          \n            <a href=\"../../index.html\" class=\"icon icon-home\"> wukong-robot\n          \n\n          \n          </a>\n\n          \n            \n            \n          \n\n          \n<div role=\"search\">\n  <form id=\"rtd-search-form\" class=\"wy-form\" action=\"../../search.html\" method=\"get\">\n    <input type=\"text\" name=\"q\" placeholder=\"Search docs\" />\n    <input type=\"hidden\" name=\"check_keywords\" value=\"yes\" />\n    <input type=\"hidden\" name=\"area\" value=\"default\" />\n  </form>\n</div>\n\n          \n        </div>\n\n        <div class=\"wy-menu wy-menu-vertical\" data-spy=\"affix\" role=\"navigation\" aria-label=\"main navigation\">\n          \n            \n            \n              \n            \n            \n              <!-- Local TOC -->\n              <div class=\"local-toc\"></div>\n            \n          \n        </div>\n      </div>\n    </nav>\n\n    <section data-toggle=\"wy-nav-shift\" class=\"wy-nav-content-wrap\">\n\n      \n      <nav class=\"wy-nav-top\" aria-label=\"top navigation\">\n        \n          <i data-toggle=\"wy-nav-top\" class=\"fa fa-bars\"></i>\n          <a href=\"../../index.html\">wukong-robot</a>\n        \n      </nav>\n\n\n      <div class=\"wy-nav-content\">\n        \n        <div class=\"rst-content\">\n        \n          \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<div role=\"navigation\" aria-label=\"breadcrumbs navigation\">\n\n  <ul class=\"wy-breadcrumbs\">\n    \n      <li><a href=\"../../index.html\">Docs</a> &raquo;</li>\n        \n          <li><a href=\"../index.html\">模块代码</a> &raquo;</li>\n        \n      <li>plugins.Echo</li>\n    \n    \n      <li class=\"wy-breadcrumbs-aside\">\n        \n      </li>\n    \n  </ul>\n\n  \n  <hr/>\n</div>\n          <div role=\"main\" class=\"document\" itemscope=\"itemscope\" itemtype=\"http://schema.org/Article\">\n           <div itemprop=\"articleBody\">\n            \n  <h1>plugins.Echo 源代码</h1><div class=\"highlight\"><pre>\n<span></span><span class=\"c1\"># -*- coding: utf-8-*-</span>\n<span class=\"c1\"># author: wzpan</span>\n<span class=\"c1\"># 写诗</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">logging</span>\n<span class=\"kn\">from</span> <span class=\"nn\">robot.sdk.AbstractPlugin</span> <span class=\"k\">import</span> <span class=\"n\">AbstractPlugin</span>\n\n<span class=\"n\">logger</span> <span class=\"o\">=</span> <span class=\"n\">logging</span><span class=\"o\">.</span><span class=\"n\">getLogger</span><span class=\"p\">(</span><span class=\"vm\">__name__</span><span class=\"p\">)</span>\n\n<div class=\"viewcode-block\" id=\"Plugin\"><a class=\"viewcode-back\" href=\"../../plugins.html#plugins.Echo.Plugin\">[文档]</a><span class=\"k\">class</span> <span class=\"nc\">Plugin</span><span class=\"p\">(</span><span class=\"n\">AbstractPlugin</span><span class=\"p\">):</span>\n\n<div class=\"viewcode-block\" id=\"Plugin.handle\"><a class=\"viewcode-back\" href=\"../../plugins.html#plugins.Echo.Plugin.handle\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">handle</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">text</span><span class=\"p\">,</span> <span class=\"n\">parsed</span><span class=\"p\">):</span>\n        <span class=\"n\">text</span> <span class=\"o\">=</span> <span class=\"n\">text</span><span class=\"o\">.</span><span class=\"n\">lower</span><span class=\"p\">()</span><span class=\"o\">.</span><span class=\"n\">replace</span><span class=\"p\">(</span><span class=\"s1\">&#39;echo&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;&#39;</span><span class=\"p\">)</span><span class=\"o\">.</span><span class=\"n\">replace</span><span class=\"p\">(</span><span class=\"sa\">u</span><span class=\"s1\">&#39;传话&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;&#39;</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">say</span><span class=\"p\">(</span><span class=\"n\">text</span><span class=\"p\">,</span> <span class=\"n\">cache</span><span class=\"o\">=</span><span class=\"kc\">False</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"Plugin.isValid\"><a class=\"viewcode-back\" href=\"../../plugins.html#plugins.Echo.Plugin.isValid\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">isValid</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">text</span><span class=\"p\">,</span> <span class=\"n\">parsed</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"nb\">any</span><span class=\"p\">(</span><span class=\"n\">word</span> <span class=\"ow\">in</span> <span class=\"n\">text</span><span class=\"o\">.</span><span class=\"n\">lower</span><span class=\"p\">()</span> <span class=\"k\">for</span> <span class=\"n\">word</span> <span class=\"ow\">in</span> <span class=\"p\">[</span><span class=\"s2\">&quot;echo&quot;</span><span class=\"p\">,</span> <span class=\"sa\">u</span><span class=\"s2\">&quot;传话&quot;</span><span class=\"p\">])</span></div></div>\n        \n        \n</pre></div>\n\n           </div>\n           \n          </div>\n          <footer>\n  \n\n  <hr/>\n\n  <div role=\"contentinfo\">\n    <p>\n        &copy; Copyright 2019, wzpan\n\n    </p>\n  </div>\n  Built with <a href=\"http://sphinx-doc.org/\">Sphinx</a> using a <a href=\"https://github.com/rtfd/sphinx_rtd_theme\">theme</a> provided by <a href=\"https://readthedocs.org\">Read the Docs</a>. \n\n</footer>\n\n        </div>\n      </div>\n\n    </section>\n\n  </div>\n  \n\n\n  <script type=\"text/javascript\">\n      jQuery(function () {\n          SphinxRtdTheme.Navigation.enable(true);\n      });\n  </script>\n\n  \n  \n    \n   \n\n</body>\n</html>"
  },
  {
    "path": "docs/_modules/plugins/Email.html",
    "content": "\n\n<!DOCTYPE html>\n<!--[if IE 8]><html class=\"no-js lt-ie9\" lang=\"zh-CN\" > <![endif]-->\n<!--[if gt IE 8]><!--> <html class=\"no-js\" lang=\"zh-CN\" > <!--<![endif]-->\n<head>\n  <meta charset=\"utf-8\">\n  \n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  \n  <title>plugins.Email &mdash; wukong-robot 1.2.0 文档</title>\n  \n\n  \n  \n  \n  \n\n  \n  <script type=\"text/javascript\" src=\"../../_static/js/modernizr.min.js\"></script>\n  \n    \n      <script type=\"text/javascript\" id=\"documentation_options\" data-url_root=\"../../\" src=\"../../_static/documentation_options.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/jquery.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/underscore.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/doctools.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/language_data.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/translations.js\"></script>\n    \n    <script type=\"text/javascript\" src=\"../../_static/js/theme.js\"></script>\n\n    \n\n  \n  <link rel=\"stylesheet\" href=\"../../_static/css/theme.css\" type=\"text/css\" />\n  <link rel=\"stylesheet\" href=\"../../_static/pygments.css\" type=\"text/css\" />\n    <link rel=\"index\" title=\"索引\" href=\"../../genindex.html\" />\n    <link rel=\"search\" title=\"搜索\" href=\"../../search.html\" /> \n</head>\n\n<body class=\"wy-body-for-nav\">\n\n   \n  <div class=\"wy-grid-for-nav\">\n    \n    <nav data-toggle=\"wy-nav-shift\" class=\"wy-nav-side\">\n      <div class=\"wy-side-scroll\">\n        <div class=\"wy-side-nav-search\" >\n          \n\n          \n            <a href=\"../../index.html\" class=\"icon icon-home\"> wukong-robot\n          \n\n          \n          </a>\n\n          \n            \n            \n          \n\n          \n<div role=\"search\">\n  <form id=\"rtd-search-form\" class=\"wy-form\" action=\"../../search.html\" method=\"get\">\n    <input type=\"text\" name=\"q\" placeholder=\"Search docs\" />\n    <input type=\"hidden\" name=\"check_keywords\" value=\"yes\" />\n    <input type=\"hidden\" name=\"area\" value=\"default\" />\n  </form>\n</div>\n\n          \n        </div>\n\n        <div class=\"wy-menu wy-menu-vertical\" data-spy=\"affix\" role=\"navigation\" aria-label=\"main navigation\">\n          \n            \n            \n              \n            \n            \n              <!-- Local TOC -->\n              <div class=\"local-toc\"></div>\n            \n          \n        </div>\n      </div>\n    </nav>\n\n    <section data-toggle=\"wy-nav-shift\" class=\"wy-nav-content-wrap\">\n\n      \n      <nav class=\"wy-nav-top\" aria-label=\"top navigation\">\n        \n          <i data-toggle=\"wy-nav-top\" class=\"fa fa-bars\"></i>\n          <a href=\"../../index.html\">wukong-robot</a>\n        \n      </nav>\n\n\n      <div class=\"wy-nav-content\">\n        \n        <div class=\"rst-content\">\n        \n          \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<div role=\"navigation\" aria-label=\"breadcrumbs navigation\">\n\n  <ul class=\"wy-breadcrumbs\">\n    \n      <li><a href=\"../../index.html\">Docs</a> &raquo;</li>\n        \n          <li><a href=\"../index.html\">模块代码</a> &raquo;</li>\n        \n      <li>plugins.Email</li>\n    \n    \n      <li class=\"wy-breadcrumbs-aside\">\n        \n      </li>\n    \n  </ul>\n\n  \n  <hr/>\n</div>\n          <div role=\"main\" class=\"document\" itemscope=\"itemscope\" itemtype=\"http://schema.org/Article\">\n           <div itemprop=\"articleBody\">\n            \n  <h1>plugins.Email 源代码</h1><div class=\"highlight\"><pre>\n<span></span><span class=\"c1\"># -*- coding: utf-8-*-</span>\n<span class=\"kn\">import</span> <span class=\"nn\">imaplib</span>\n<span class=\"kn\">import</span> <span class=\"nn\">email</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">datetime</span>\n<span class=\"kn\">from</span> <span class=\"nn\">robot</span> <span class=\"k\">import</span> <span class=\"n\">logging</span>\n<span class=\"kn\">from</span> <span class=\"nn\">dateutil</span> <span class=\"k\">import</span> <span class=\"n\">parser</span>\n<span class=\"kn\">from</span> <span class=\"nn\">robot</span> <span class=\"k\">import</span> <span class=\"n\">config</span>\n<span class=\"kn\">from</span> <span class=\"nn\">robot.sdk.AbstractPlugin</span> <span class=\"k\">import</span> <span class=\"n\">AbstractPlugin</span>\n\n<div class=\"viewcode-block\" id=\"Plugin\"><a class=\"viewcode-back\" href=\"../../plugins.html#plugins.Email.Plugin\">[文档]</a><span class=\"k\">class</span> <span class=\"nc\">Plugin</span><span class=\"p\">(</span><span class=\"n\">AbstractPlugin</span><span class=\"p\">):</span>\n\n    <span class=\"n\">SLUG</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;email&#39;</span>\n\n<div class=\"viewcode-block\" id=\"Plugin.getSender\"><a class=\"viewcode-back\" href=\"../../plugins.html#plugins.Email.Plugin.getSender\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">getSender</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">msg</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">            Returns the best-guess sender of an email.</span>\n\n<span class=\"sd\">            Arguments:</span>\n<span class=\"sd\">            msg -- the email whose sender is desired</span>\n\n<span class=\"sd\">            Returns:</span>\n<span class=\"sd\">            Sender of the sender.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"n\">fromstr</span> <span class=\"o\">=</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">msg</span><span class=\"p\">[</span><span class=\"s2\">&quot;From&quot;</span><span class=\"p\">])</span>\n        <span class=\"n\">ls</span> <span class=\"o\">=</span> <span class=\"n\">fromstr</span><span class=\"o\">.</span><span class=\"n\">split</span><span class=\"p\">(</span><span class=\"s1\">&#39; &#39;</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">ls</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">2</span><span class=\"p\">):</span>\n            <span class=\"n\">fromname</span> <span class=\"o\">=</span> <span class=\"n\">email</span><span class=\"o\">.</span><span class=\"n\">header</span><span class=\"o\">.</span><span class=\"n\">decode_header</span><span class=\"p\">(</span><span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">ls</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span><span class=\"o\">.</span><span class=\"n\">strip</span><span class=\"p\">(</span><span class=\"s1\">&#39;</span><span class=\"se\">\\&quot;</span><span class=\"s1\">&#39;</span><span class=\"p\">))</span>\n            <span class=\"n\">sender</span> <span class=\"o\">=</span> <span class=\"n\">fromname</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n        <span class=\"k\">elif</span><span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">ls</span><span class=\"p\">)</span> <span class=\"o\">&gt;</span> <span class=\"mi\">2</span><span class=\"p\">):</span>\n            <span class=\"n\">fromname</span> <span class=\"o\">=</span> <span class=\"n\">email</span><span class=\"o\">.</span><span class=\"n\">header</span><span class=\"o\">.</span><span class=\"n\">decode_header</span><span class=\"p\">(</span><span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">fromstr</span><span class=\"p\">[:</span><span class=\"n\">fromstr</span><span class=\"o\">.</span><span class=\"n\">find</span><span class=\"p\">(</span><span class=\"s1\">&#39;&lt;&#39;</span><span class=\"p\">)])</span>\n                                                  <span class=\"o\">.</span><span class=\"n\">strip</span><span class=\"p\">(</span><span class=\"s1\">&#39;</span><span class=\"se\">\\&quot;</span><span class=\"s1\">&#39;</span><span class=\"p\">))</span>\n            <span class=\"n\">sender</span> <span class=\"o\">=</span> <span class=\"n\">fromname</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"n\">sender</span> <span class=\"o\">=</span> <span class=\"n\">msg</span><span class=\"p\">[</span><span class=\"s1\">&#39;From&#39;</span><span class=\"p\">]</span>\n        <span class=\"k\">if</span> <span class=\"nb\">isinstance</span><span class=\"p\">(</span><span class=\"n\">sender</span><span class=\"p\">,</span> <span class=\"nb\">bytes</span><span class=\"p\">):</span>\n            <span class=\"k\">try</span><span class=\"p\">:</span>\n                <span class=\"k\">return</span> <span class=\"n\">sender</span><span class=\"o\">.</span><span class=\"n\">decode</span><span class=\"p\">(</span><span class=\"s1\">&#39;utf-8&#39;</span><span class=\"p\">)</span>\n            <span class=\"k\">except</span> <span class=\"ne\">UnicodeDecodeError</span><span class=\"p\">:</span>\n                <span class=\"k\">return</span> <span class=\"n\">sender</span><span class=\"o\">.</span><span class=\"n\">decode</span><span class=\"p\">(</span><span class=\"s1\">&#39;gbk&#39;</span><span class=\"p\">)</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"k\">return</span> <span class=\"n\">sender</span></div>\n\n<div class=\"viewcode-block\" id=\"Plugin.isSelfEmail\"><a class=\"viewcode-back\" href=\"../../plugins.html#plugins.Email.Plugin.isSelfEmail\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">isSelfEmail</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">msg</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot; Whether the email is sent by the user &quot;&quot;&quot;</span>\n        <span class=\"n\">fromstr</span> <span class=\"o\">=</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">msg</span><span class=\"p\">[</span><span class=\"s2\">&quot;From&quot;</span><span class=\"p\">])</span>\n        <span class=\"n\">addr</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"n\">fromstr</span><span class=\"p\">[</span><span class=\"n\">fromstr</span><span class=\"o\">.</span><span class=\"n\">find</span><span class=\"p\">(</span><span class=\"s1\">&#39;&lt;&#39;</span><span class=\"p\">)</span><span class=\"o\">+</span><span class=\"mi\">1</span><span class=\"p\">:</span><span class=\"n\">fromstr</span><span class=\"o\">.</span><span class=\"n\">find</span><span class=\"p\">(</span><span class=\"s1\">&#39;&gt;&#39;</span><span class=\"p\">)])</span><span class=\"o\">.</span><span class=\"n\">strip</span><span class=\"p\">(</span><span class=\"s1\">&#39;</span><span class=\"se\">\\&quot;</span><span class=\"s1\">&#39;</span><span class=\"p\">)</span>\n        <span class=\"n\">address</span> <span class=\"o\">=</span> <span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">()[</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">SLUG</span><span class=\"p\">][</span><span class=\"s1\">&#39;address&#39;</span><span class=\"p\">]</span><span class=\"o\">.</span><span class=\"n\">strip</span><span class=\"p\">()</span>\n        <span class=\"k\">return</span> <span class=\"n\">addr</span> <span class=\"o\">==</span> <span class=\"n\">address</span></div>\n\n<div class=\"viewcode-block\" id=\"Plugin.getSubject\"><a class=\"viewcode-back\" href=\"../../plugins.html#plugins.Email.Plugin.getSubject\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">getSubject</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">msg</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">            Returns the title of an email</span>\n\n<span class=\"sd\">            Arguments:</span>\n<span class=\"sd\">            msg -- the email</span>\n\n<span class=\"sd\">            Returns:</span>\n<span class=\"sd\">            Title of the email.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"n\">subject</span> <span class=\"o\">=</span> <span class=\"n\">email</span><span class=\"o\">.</span><span class=\"n\">header</span><span class=\"o\">.</span><span class=\"n\">decode_header</span><span class=\"p\">(</span><span class=\"n\">msg</span><span class=\"p\">[</span><span class=\"s1\">&#39;subject&#39;</span><span class=\"p\">])</span>\n        <span class=\"k\">if</span> <span class=\"nb\">isinstance</span><span class=\"p\">(</span><span class=\"n\">subject</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">],</span> <span class=\"nb\">bytes</span><span class=\"p\">):</span>\n            <span class=\"k\">try</span><span class=\"p\">:</span>\n                <span class=\"n\">sub</span> <span class=\"o\">=</span> <span class=\"n\">subject</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"o\">.</span><span class=\"n\">decode</span><span class=\"p\">(</span><span class=\"s1\">&#39;utf-8&#39;</span><span class=\"p\">)</span>\n            <span class=\"k\">except</span> <span class=\"ne\">UnicodeDecodeError</span><span class=\"p\">:</span>\n                <span class=\"n\">sub</span> <span class=\"o\">=</span> <span class=\"n\">subject</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"o\">.</span><span class=\"n\">decode</span><span class=\"p\">(</span><span class=\"s1\">&#39;gbk&#39;</span><span class=\"p\">)</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"n\">sub</span> <span class=\"o\">=</span> <span class=\"n\">subject</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n        <span class=\"n\">to_read</span> <span class=\"o\">=</span> <span class=\"kc\">False</span>\n        <span class=\"k\">if</span> <span class=\"n\">sub</span><span class=\"o\">.</span><span class=\"n\">strip</span><span class=\"p\">()</span> <span class=\"o\">==</span> <span class=\"s1\">&#39;&#39;</span><span class=\"p\">:</span>\n            <span class=\"k\">return</span> <span class=\"s1\">&#39;&#39;</span>\n        <span class=\"n\">to_read</span> <span class=\"o\">=</span> <span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;/email/read_email_title&#39;</span><span class=\"p\">,</span> <span class=\"kc\">True</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">to_read</span><span class=\"p\">:</span>\n            <span class=\"k\">return</span> <span class=\"s1\">&#39;邮件标题为 </span><span class=\"si\">%s</span><span class=\"s1\">&#39;</span> <span class=\"o\">%</span> <span class=\"n\">sub</span>\n        <span class=\"k\">return</span> <span class=\"s1\">&#39;&#39;</span></div>\n\n<div class=\"viewcode-block\" id=\"Plugin.isNewEmail\"><a class=\"viewcode-back\" href=\"../../plugins.html#plugins.Email.Plugin.isNewEmail\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">isNewEmail</span><span class=\"p\">(</span><span class=\"n\">msg</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot; Wether an email is a new email &quot;&quot;&quot;</span>\n        <span class=\"n\">date</span> <span class=\"o\">=</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">msg</span><span class=\"p\">[</span><span class=\"s1\">&#39;Date&#39;</span><span class=\"p\">])</span>\n        <span class=\"n\">dtext</span> <span class=\"o\">=</span> <span class=\"n\">date</span><span class=\"o\">.</span><span class=\"n\">split</span><span class=\"p\">(</span><span class=\"s1\">&#39;,&#39;</span><span class=\"p\">)[</span><span class=\"mi\">1</span><span class=\"p\">]</span><span class=\"o\">.</span><span class=\"n\">split</span><span class=\"p\">(</span><span class=\"s1\">&#39;+&#39;</span><span class=\"p\">)[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"o\">.</span><span class=\"n\">strip</span><span class=\"p\">()</span>\n        <span class=\"n\">dtime</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"o\">.</span><span class=\"n\">strptime</span><span class=\"p\">(</span><span class=\"n\">dtext</span><span class=\"p\">,</span> <span class=\"s1\">&#39;</span><span class=\"si\">%d</span><span class=\"s1\"> %b %Y %H:%M:%S&#39;</span><span class=\"p\">)</span>\n        <span class=\"n\">current</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"o\">.</span><span class=\"n\">localtime</span><span class=\"p\">()</span>\n        <span class=\"n\">dt</span> <span class=\"o\">=</span> <span class=\"n\">datetime</span><span class=\"o\">.</span><span class=\"n\">datetime</span><span class=\"p\">(</span><span class=\"o\">*</span><span class=\"n\">dtime</span><span class=\"p\">[:</span><span class=\"mi\">6</span><span class=\"p\">])</span>\n        <span class=\"n\">cr</span> <span class=\"o\">=</span> <span class=\"n\">datetime</span><span class=\"o\">.</span><span class=\"n\">datetime</span><span class=\"p\">(</span><span class=\"o\">*</span><span class=\"n\">current</span><span class=\"p\">[:</span><span class=\"mi\">6</span><span class=\"p\">])</span>\n        <span class=\"k\">return</span> <span class=\"p\">(</span><span class=\"n\">cr</span> <span class=\"o\">-</span> <span class=\"n\">dt</span><span class=\"p\">)</span><span class=\"o\">.</span><span class=\"n\">days</span> <span class=\"o\">==</span> <span class=\"mi\">0</span></div>\n\n<div class=\"viewcode-block\" id=\"Plugin.getDate\"><a class=\"viewcode-back\" href=\"../../plugins.html#plugins.Email.Plugin.getDate\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">getDate</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">email</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"n\">parser</span><span class=\"o\">.</span><span class=\"n\">parse</span><span class=\"p\">(</span><span class=\"n\">email</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;date&#39;</span><span class=\"p\">))</span></div>\n\n<div class=\"viewcode-block\" id=\"Plugin.getMostRecentDate\"><a class=\"viewcode-back\" href=\"../../plugins.html#plugins.Email.Plugin.getMostRecentDate\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">getMostRecentDate</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">emails</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">            Returns the most recent date of any email in the list provided.</span>\n\n<span class=\"sd\">            Arguments:</span>\n<span class=\"sd\">            emails -- a list of emails to check</span>\n\n<span class=\"sd\">            Returns:</span>\n<span class=\"sd\">            Date of the most recent email.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"n\">dates</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">getDate</span><span class=\"p\">(</span><span class=\"n\">e</span><span class=\"p\">)</span> <span class=\"k\">for</span> <span class=\"n\">e</span> <span class=\"ow\">in</span> <span class=\"n\">emails</span><span class=\"p\">]</span>\n        <span class=\"n\">dates</span><span class=\"o\">.</span><span class=\"n\">sort</span><span class=\"p\">(</span><span class=\"n\">reverse</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">dates</span><span class=\"p\">:</span>\n            <span class=\"k\">return</span> <span class=\"n\">dates</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n        <span class=\"k\">return</span> <span class=\"kc\">None</span></div>\n\n<div class=\"viewcode-block\" id=\"Plugin.fetchUnreadEmails\"><a class=\"viewcode-back\" href=\"../../plugins.html#plugins.Email.Plugin.fetchUnreadEmails\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">fetchUnreadEmails</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">since</span><span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">,</span> <span class=\"n\">markRead</span><span class=\"o\">=</span><span class=\"kc\">False</span><span class=\"p\">,</span> <span class=\"n\">limit</span><span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">            Fetches a list of unread email objects from a user&#39;s email inbox.</span>\n\n<span class=\"sd\">            Arguments:</span>\n<span class=\"sd\">            since -- if provided, no emails before this date will be returned</span>\n<span class=\"sd\">            markRead -- if True, marks all returned emails as read in target inbox</span>\n\n<span class=\"sd\">            Returns:</span>\n<span class=\"sd\">            A list of unread email objects.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"n\">logger</span> <span class=\"o\">=</span> <span class=\"n\">logging</span><span class=\"o\">.</span><span class=\"n\">getLogger</span><span class=\"p\">(</span><span class=\"vm\">__name__</span><span class=\"p\">)</span>\n        <span class=\"n\">profile</span> <span class=\"o\">=</span> <span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">()</span>\n        <span class=\"n\">conn</span> <span class=\"o\">=</span> <span class=\"n\">imaplib</span><span class=\"o\">.</span><span class=\"n\">IMAP4</span><span class=\"p\">(</span><span class=\"n\">profile</span><span class=\"p\">[</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">SLUG</span><span class=\"p\">][</span><span class=\"s1\">&#39;imap_server&#39;</span><span class=\"p\">],</span>\n                             <span class=\"n\">profile</span><span class=\"p\">[</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">SLUG</span><span class=\"p\">][</span><span class=\"s1\">&#39;imap_port&#39;</span><span class=\"p\">])</span>\n        <span class=\"n\">conn</span><span class=\"o\">.</span><span class=\"n\">debug</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n\n        <span class=\"n\">msgs</span> <span class=\"o\">=</span> <span class=\"p\">[]</span>\n        <span class=\"k\">try</span><span class=\"p\">:</span>\n            <span class=\"n\">conn</span><span class=\"o\">.</span><span class=\"n\">login</span><span class=\"p\">(</span><span class=\"n\">profile</span><span class=\"p\">[</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">SLUG</span><span class=\"p\">][</span><span class=\"s1\">&#39;address&#39;</span><span class=\"p\">],</span> <span class=\"n\">profile</span><span class=\"p\">[</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">SLUG</span><span class=\"p\">][</span><span class=\"s1\">&#39;password&#39;</span><span class=\"p\">])</span>\n            <span class=\"n\">conn</span><span class=\"o\">.</span><span class=\"n\">select</span><span class=\"p\">(</span><span class=\"n\">readonly</span><span class=\"o\">=</span><span class=\"p\">(</span><span class=\"ow\">not</span> <span class=\"n\">markRead</span><span class=\"p\">))</span>\n            <span class=\"p\">(</span><span class=\"n\">retcode</span><span class=\"p\">,</span> <span class=\"n\">messages</span><span class=\"p\">)</span> <span class=\"o\">=</span> <span class=\"n\">conn</span><span class=\"o\">.</span><span class=\"n\">search</span><span class=\"p\">(</span><span class=\"kc\">None</span><span class=\"p\">,</span> <span class=\"s1\">&#39;(UNSEEN)&#39;</span><span class=\"p\">)</span>\n        <span class=\"k\">except</span> <span class=\"ne\">Exception</span><span class=\"p\">:</span>\n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">warning</span><span class=\"p\">(</span><span class=\"s2\">&quot;抱歉，您的邮箱账户验证失败了，请检查下配置&quot;</span><span class=\"p\">)</span>\n            <span class=\"k\">return</span> <span class=\"kc\">None</span>\n\n        <span class=\"k\">if</span> <span class=\"n\">retcode</span> <span class=\"o\">==</span> <span class=\"s1\">&#39;OK&#39;</span> <span class=\"ow\">and</span> <span class=\"n\">messages</span> <span class=\"o\">!=</span> <span class=\"p\">[</span><span class=\"sa\">b</span><span class=\"s1\">&#39;&#39;</span><span class=\"p\">]:</span>\n            <span class=\"n\">numUnread</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">messages</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"o\">.</span><span class=\"n\">split</span><span class=\"p\">(</span><span class=\"sa\">b</span><span class=\"s1\">&#39; &#39;</span><span class=\"p\">))</span>\n            <span class=\"k\">if</span> <span class=\"n\">limit</span> <span class=\"ow\">and</span> <span class=\"n\">numUnread</span> <span class=\"o\">&gt;</span> <span class=\"n\">limit</span><span class=\"p\">:</span>\n                <span class=\"k\">return</span> <span class=\"n\">numUnread</span>\n\n            <span class=\"k\">for</span> <span class=\"n\">num</span> <span class=\"ow\">in</span> <span class=\"n\">messages</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"o\">.</span><span class=\"n\">split</span><span class=\"p\">(</span><span class=\"sa\">b</span><span class=\"s1\">&#39; &#39;</span><span class=\"p\">):</span>\n                <span class=\"c1\"># parse email RFC822 format</span>\n                <span class=\"n\">ret</span><span class=\"p\">,</span> <span class=\"n\">data</span> <span class=\"o\">=</span> <span class=\"n\">conn</span><span class=\"o\">.</span><span class=\"n\">fetch</span><span class=\"p\">(</span><span class=\"n\">num</span><span class=\"p\">,</span> <span class=\"s1\">&#39;(RFC822)&#39;</span><span class=\"p\">)</span>\n                <span class=\"k\">if</span> <span class=\"n\">data</span> <span class=\"ow\">is</span> <span class=\"kc\">None</span><span class=\"p\">:</span>\n                    <span class=\"k\">continue</span>\n                <span class=\"n\">msg</span> <span class=\"o\">=</span> <span class=\"n\">email</span><span class=\"o\">.</span><span class=\"n\">message_from_string</span><span class=\"p\">(</span><span class=\"n\">data</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">][</span><span class=\"mi\">1</span><span class=\"p\">]</span><span class=\"o\">.</span><span class=\"n\">decode</span><span class=\"p\">(</span><span class=\"s1\">&#39;utf-8&#39;</span><span class=\"p\">))</span>\n\n                <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">since</span> <span class=\"ow\">or</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">getDate</span><span class=\"p\">(</span><span class=\"n\">msg</span><span class=\"p\">)</span> <span class=\"o\">&gt;</span> <span class=\"n\">since</span><span class=\"p\">:</span>\n                    <span class=\"n\">msgs</span><span class=\"o\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">msg</span><span class=\"p\">)</span>\n\n        <span class=\"n\">conn</span><span class=\"o\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n        <span class=\"n\">conn</span><span class=\"o\">.</span><span class=\"n\">logout</span><span class=\"p\">()</span>\n\n        <span class=\"k\">return</span> <span class=\"n\">msgs</span></div>\n    \n\n<div class=\"viewcode-block\" id=\"Plugin.handle\"><a class=\"viewcode-back\" href=\"../../plugins.html#plugins.Email.Plugin.handle\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">handle</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">text</span><span class=\"p\">,</span> <span class=\"n\">parsed</span><span class=\"p\">):</span>\n        <span class=\"n\">msgs</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">fetchUnreadEmails</span><span class=\"p\">(</span><span class=\"n\">limit</span><span class=\"o\">=</span><span class=\"mi\">5</span><span class=\"p\">)</span>\n\n        <span class=\"k\">if</span> <span class=\"n\">msgs</span> <span class=\"ow\">is</span> <span class=\"kc\">None</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">say</span><span class=\"p\">(</span>\n                <span class=\"sa\">u</span><span class=\"s2\">&quot;抱歉，您的邮箱账户验证失败了&quot;</span><span class=\"p\">,</span> <span class=\"n\">cache</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">)</span>\n            <span class=\"k\">return</span>\n\n        <span class=\"k\">if</span> <span class=\"nb\">isinstance</span><span class=\"p\">(</span><span class=\"n\">msgs</span><span class=\"p\">,</span> <span class=\"nb\">int</span><span class=\"p\">):</span>\n            <span class=\"n\">response</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;您有 </span><span class=\"si\">%d</span><span class=\"s2\"> 封未读邮件&quot;</span> <span class=\"o\">%</span> <span class=\"n\">msgs</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">say</span><span class=\"p\">(</span><span class=\"n\">response</span><span class=\"p\">,</span> <span class=\"n\">cache</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">)</span>\n            <span class=\"k\">return</span>\n\n        <span class=\"n\">senders</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">getSender</span><span class=\"p\">(</span><span class=\"n\">e</span><span class=\"p\">))</span> <span class=\"k\">for</span> <span class=\"n\">e</span> <span class=\"ow\">in</span> <span class=\"n\">msgs</span><span class=\"p\">]</span>\n\n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">senders</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">say</span><span class=\"p\">(</span><span class=\"sa\">u</span><span class=\"s2\">&quot;您没有未读邮件，真棒！&quot;</span><span class=\"p\">,</span> <span class=\"n\">cache</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">)</span>\n        <span class=\"k\">elif</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">senders</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">1</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">say</span><span class=\"p\">(</span><span class=\"sa\">u</span><span class=\"s2\">&quot;您有来自 </span><span class=\"si\">{}</span><span class=\"s2\"> 的未读邮件。</span><span class=\"si\">{}</span><span class=\"s2\">&quot;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">senders</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">],</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">getSubject</span><span class=\"p\">(</span><span class=\"n\">msgs</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])))</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"n\">response</span> <span class=\"o\">=</span> <span class=\"sa\">u</span><span class=\"s2\">&quot;您有 </span><span class=\"si\">%d</span><span class=\"s2\"> 封未读邮件&quot;</span> <span class=\"o\">%</span> <span class=\"nb\">len</span><span class=\"p\">(</span>\n                <span class=\"n\">senders</span><span class=\"p\">)</span>\n            <span class=\"n\">unique_senders</span> <span class=\"o\">=</span> <span class=\"nb\">list</span><span class=\"p\">(</span><span class=\"nb\">set</span><span class=\"p\">(</span><span class=\"n\">senders</span><span class=\"p\">))</span>\n            <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">unique_senders</span><span class=\"p\">)</span> <span class=\"o\">&gt;</span> <span class=\"mi\">1</span><span class=\"p\">:</span>\n                <span class=\"n\">unique_senders</span><span class=\"p\">[</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;, &#39;</span> <span class=\"o\">+</span> <span class=\"n\">unique_senders</span><span class=\"p\">[</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n                <span class=\"n\">response</span> <span class=\"o\">+=</span> <span class=\"s2\">&quot;。这些邮件的发件人包括：&quot;</span>\n                <span class=\"n\">response</span> <span class=\"o\">+=</span> <span class=\"s1\">&#39; 和 &#39;</span><span class=\"o\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">senders</span><span class=\"p\">)</span>\n            <span class=\"k\">else</span><span class=\"p\">:</span>\n                <span class=\"n\">response</span> <span class=\"o\">+=</span> <span class=\"s2\">&quot;，邮件都来自 &quot;</span> <span class=\"o\">+</span> <span class=\"n\">unique_senders</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">say</span><span class=\"p\">(</span><span class=\"n\">response</span><span class=\"p\">)</span></div>\n\n\n<div class=\"viewcode-block\" id=\"Plugin.isValid\"><a class=\"viewcode-back\" href=\"../../plugins.html#plugins.Email.Plugin.isValid\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">isValid</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">text</span><span class=\"p\">,</span> <span class=\"n\">parsed</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"nb\">any</span><span class=\"p\">(</span><span class=\"n\">word</span> <span class=\"ow\">in</span> <span class=\"n\">text</span> <span class=\"k\">for</span> <span class=\"n\">word</span> <span class=\"ow\">in</span> <span class=\"p\">[</span><span class=\"sa\">u</span><span class=\"s1\">&#39;邮箱&#39;</span><span class=\"p\">,</span> <span class=\"sa\">u</span><span class=\"s1\">&#39;邮件&#39;</span><span class=\"p\">])</span></div></div>\n</pre></div>\n\n           </div>\n           \n          </div>\n          <footer>\n  \n\n  <hr/>\n\n  <div role=\"contentinfo\">\n    <p>\n        &copy; Copyright 2019, wzpan\n\n    </p>\n  </div>\n  Built with <a href=\"http://sphinx-doc.org/\">Sphinx</a> using a <a href=\"https://github.com/rtfd/sphinx_rtd_theme\">theme</a> provided by <a href=\"https://readthedocs.org\">Read the Docs</a>. \n\n</footer>\n\n        </div>\n      </div>\n\n    </section>\n\n  </div>\n  \n\n\n  <script type=\"text/javascript\">\n      jQuery(function () {\n          SphinxRtdTheme.Navigation.enable(true);\n      });\n  </script>\n\n  \n  \n    \n   \n\n</body>\n</html>"
  },
  {
    "path": "docs/_modules/plugins/Geek.html",
    "content": "\n\n<!DOCTYPE html>\n<!--[if IE 8]><html class=\"no-js lt-ie9\" lang=\"zh-CN\" > <![endif]-->\n<!--[if gt IE 8]><!--> <html class=\"no-js\" lang=\"zh-CN\" > <!--<![endif]-->\n<head>\n  <meta charset=\"utf-8\">\n  \n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  \n  <title>plugins.Geek &mdash; wukong-robot 1.2.0 文档</title>\n  \n\n  \n  \n  \n  \n\n  \n  <script type=\"text/javascript\" src=\"../../_static/js/modernizr.min.js\"></script>\n  \n    \n      <script type=\"text/javascript\" id=\"documentation_options\" data-url_root=\"../../\" src=\"../../_static/documentation_options.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/jquery.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/underscore.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/doctools.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/language_data.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/translations.js\"></script>\n    \n    <script type=\"text/javascript\" src=\"../../_static/js/theme.js\"></script>\n\n    \n\n  \n  <link rel=\"stylesheet\" href=\"../../_static/css/theme.css\" type=\"text/css\" />\n  <link rel=\"stylesheet\" href=\"../../_static/pygments.css\" type=\"text/css\" />\n    <link rel=\"index\" title=\"索引\" href=\"../../genindex.html\" />\n    <link rel=\"search\" title=\"搜索\" href=\"../../search.html\" /> \n</head>\n\n<body class=\"wy-body-for-nav\">\n\n   \n  <div class=\"wy-grid-for-nav\">\n    \n    <nav data-toggle=\"wy-nav-shift\" class=\"wy-nav-side\">\n      <div class=\"wy-side-scroll\">\n        <div class=\"wy-side-nav-search\" >\n          \n\n          \n            <a href=\"../../index.html\" class=\"icon icon-home\"> wukong-robot\n          \n\n          \n          </a>\n\n          \n            \n            \n          \n\n          \n<div role=\"search\">\n  <form id=\"rtd-search-form\" class=\"wy-form\" action=\"../../search.html\" method=\"get\">\n    <input type=\"text\" name=\"q\" placeholder=\"Search docs\" />\n    <input type=\"hidden\" name=\"check_keywords\" value=\"yes\" />\n    <input type=\"hidden\" name=\"area\" value=\"default\" />\n  </form>\n</div>\n\n          \n        </div>\n\n        <div class=\"wy-menu wy-menu-vertical\" data-spy=\"affix\" role=\"navigation\" aria-label=\"main navigation\">\n          \n            \n            \n              \n            \n            \n              <!-- Local TOC -->\n              <div class=\"local-toc\"></div>\n            \n          \n        </div>\n      </div>\n    </nav>\n\n    <section data-toggle=\"wy-nav-shift\" class=\"wy-nav-content-wrap\">\n\n      \n      <nav class=\"wy-nav-top\" aria-label=\"top navigation\">\n        \n          <i data-toggle=\"wy-nav-top\" class=\"fa fa-bars\"></i>\n          <a href=\"../../index.html\">wukong-robot</a>\n        \n      </nav>\n\n\n      <div class=\"wy-nav-content\">\n        \n        <div class=\"rst-content\">\n        \n          \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<div role=\"navigation\" aria-label=\"breadcrumbs navigation\">\n\n  <ul class=\"wy-breadcrumbs\">\n    \n      <li><a href=\"../../index.html\">Docs</a> &raquo;</li>\n        \n          <li><a href=\"../index.html\">模块代码</a> &raquo;</li>\n        \n      <li>plugins.Geek</li>\n    \n    \n      <li class=\"wy-breadcrumbs-aside\">\n        \n      </li>\n    \n  </ul>\n\n  \n  <hr/>\n</div>\n          <div role=\"main\" class=\"document\" itemscope=\"itemscope\" itemtype=\"http://schema.org/Article\">\n           <div itemprop=\"articleBody\">\n            \n  <h1>plugins.Geek 源代码</h1><div class=\"highlight\"><pre>\n<span></span><span class=\"c1\"># -*- coding: utf-8-*-</span>\n<span class=\"kn\">from</span> <span class=\"nn\">robot</span> <span class=\"k\">import</span> <span class=\"n\">logging</span>\n<span class=\"kn\">from</span> <span class=\"nn\">robot.sdk.AbstractPlugin</span> <span class=\"k\">import</span> <span class=\"n\">AbstractPlugin</span>\n\n<span class=\"n\">logger</span> <span class=\"o\">=</span> <span class=\"n\">logging</span><span class=\"o\">.</span><span class=\"n\">getLogger</span><span class=\"p\">(</span><span class=\"vm\">__name__</span><span class=\"p\">)</span>\n\n<div class=\"viewcode-block\" id=\"Plugin\"><a class=\"viewcode-back\" href=\"../../plugins.html#plugins.Geek.Plugin\">[文档]</a><span class=\"k\">class</span> <span class=\"nc\">Plugin</span><span class=\"p\">(</span><span class=\"n\">AbstractPlugin</span><span class=\"p\">):</span>\n\n    <span class=\"n\">IS_IMMERSIVE</span> <span class=\"o\">=</span> <span class=\"kc\">True</span>  <span class=\"c1\"># 这是个沉浸式技能</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">con</span><span class=\"p\">):</span>\n        <span class=\"nb\">super</span><span class=\"p\">(</span><span class=\"n\">Plugin</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">)</span><span class=\"o\">.</span><span class=\"fm\">__init__</span><span class=\"p\">(</span><span class=\"n\">con</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">silent_count</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n\n<div class=\"viewcode-block\" id=\"Plugin.handle\"><a class=\"viewcode-back\" href=\"../../plugins.html#plugins.Geek.Plugin.handle\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">handle</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">text</span><span class=\"p\">,</span> <span class=\"n\">parsed</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"nb\">any</span> <span class=\"p\">(</span><span class=\"n\">word</span> <span class=\"ow\">in</span> <span class=\"n\">text</span> <span class=\"k\">for</span> <span class=\"n\">word</span> <span class=\"ow\">in</span> <span class=\"p\">[</span><span class=\"s1\">&#39;开启&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;激活&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;开始&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;进入&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;打开&#39;</span><span class=\"p\">]):</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">silent_count</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">say</span><span class=\"p\">(</span><span class=\"s1\">&#39;进入极客模式&#39;</span><span class=\"p\">,</span> <span class=\"n\">cache</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">,</span> <span class=\"n\">onCompleted</span><span class=\"o\">=</span><span class=\"k\">lambda</span><span class=\"p\">:</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">onAsk</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">activeListen</span><span class=\"p\">(</span><span class=\"n\">silent</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">)))</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">say</span><span class=\"p\">(</span><span class=\"s1\">&#39;退出极客模式&#39;</span><span class=\"p\">,</span> <span class=\"n\">cache</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"Plugin.onAsk\"><a class=\"viewcode-back\" href=\"../../plugins.html#plugins.Geek.Plugin.onAsk\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">onAsk</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"nb\">input</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"nb\">input</span><span class=\"p\">:</span>\n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">debug</span><span class=\"p\">(</span><span class=\"s1\">&#39;input: </span><span class=\"si\">{}</span><span class=\"s1\">&#39;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"nb\">input</span><span class=\"p\">))</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">silent_count</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">con</span><span class=\"o\">.</span><span class=\"n\">doResponse</span><span class=\"p\">(</span><span class=\"nb\">input</span><span class=\"p\">)</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">silent_count</span> <span class=\"o\">+=</span> <span class=\"mi\">1</span>\n            <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">silent_count</span> <span class=\"o\">&gt;=</span> <span class=\"mi\">5</span><span class=\"p\">:</span>\n                <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">say</span><span class=\"p\">(</span><span class=\"s1\">&#39;退出极客模式&#39;</span><span class=\"p\">,</span> <span class=\"n\">cache</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">)</span>\n                <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">clearImmersive</span><span class=\"p\">()</span>\n            <span class=\"k\">else</span><span class=\"p\">:</span>\n                <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">onAsk</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">activeListen</span><span class=\"p\">(</span><span class=\"n\">silent</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">))</span></div>\n\n<div class=\"viewcode-block\" id=\"Plugin.restore\"><a class=\"viewcode-back\" href=\"../../plugins.html#plugins.Geek.Plugin.restore\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">restore</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">debug</span><span class=\"p\">(</span><span class=\"s1\">&#39;restore&#39;</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">onAsk</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">activeListen</span><span class=\"p\">(</span><span class=\"n\">silent</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">))</span></div>\n\n<div class=\"viewcode-block\" id=\"Plugin.isValidImmersive\"><a class=\"viewcode-back\" href=\"../../plugins.html#plugins.Geek.Plugin.isValidImmersive\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">isValidImmersive</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">text</span><span class=\"p\">,</span> <span class=\"n\">parsed</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"s1\">&#39;模式&#39;</span> <span class=\"ow\">in</span> <span class=\"n\">text</span> <span class=\"ow\">and</span> \\\n            <span class=\"nb\">any</span><span class=\"p\">(</span><span class=\"n\">word</span> <span class=\"ow\">in</span> <span class=\"n\">text</span> <span class=\"k\">for</span> <span class=\"n\">word</span> <span class=\"ow\">in</span> <span class=\"p\">[</span><span class=\"s1\">&#39;即刻&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;即可&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;极客&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;即客&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;集团&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;集客&#39;</span><span class=\"p\">])</span> <span class=\"ow\">and</span> \\\n            <span class=\"nb\">any</span><span class=\"p\">(</span><span class=\"n\">word</span> <span class=\"ow\">in</span> <span class=\"n\">text</span> <span class=\"k\">for</span> <span class=\"n\">word</span> <span class=\"ow\">in</span> <span class=\"p\">[</span><span class=\"s1\">&#39;退出&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;结束&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;停止&#39;</span><span class=\"p\">])</span></div>\n\n<div class=\"viewcode-block\" id=\"Plugin.isValid\"><a class=\"viewcode-back\" href=\"../../plugins.html#plugins.Geek.Plugin.isValid\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">isValid</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">text</span><span class=\"p\">,</span> <span class=\"n\">parsed</span><span class=\"p\">):</span>        \n        <span class=\"k\">return</span> <span class=\"s1\">&#39;模式&#39;</span> <span class=\"ow\">in</span> <span class=\"n\">text</span> <span class=\"ow\">and</span> \\\n            <span class=\"nb\">any</span><span class=\"p\">(</span><span class=\"n\">word</span> <span class=\"ow\">in</span> <span class=\"n\">text</span> <span class=\"k\">for</span> <span class=\"n\">word</span> <span class=\"ow\">in</span> <span class=\"p\">[</span><span class=\"s1\">&#39;即刻&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;即可&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;即客&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;集团&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;极客&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;集客&#39;</span><span class=\"p\">])</span> <span class=\"ow\">and</span> \\\n            <span class=\"nb\">any</span> <span class=\"p\">(</span><span class=\"n\">word</span> <span class=\"ow\">in</span> <span class=\"n\">text</span> <span class=\"k\">for</span> <span class=\"n\">word</span> <span class=\"ow\">in</span> <span class=\"p\">[</span><span class=\"s1\">&#39;开启&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;激活&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;开始&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;进入&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;打开&#39;</span><span class=\"p\">])</span></div></div>\n\n</pre></div>\n\n           </div>\n           \n          </div>\n          <footer>\n  \n\n  <hr/>\n\n  <div role=\"contentinfo\">\n    <p>\n        &copy; Copyright 2019, wzpan\n\n    </p>\n  </div>\n  Built with <a href=\"http://sphinx-doc.org/\">Sphinx</a> using a <a href=\"https://github.com/rtfd/sphinx_rtd_theme\">theme</a> provided by <a href=\"https://readthedocs.org\">Read the Docs</a>. \n\n</footer>\n\n        </div>\n      </div>\n\n    </section>\n\n  </div>\n  \n\n\n  <script type=\"text/javascript\">\n      jQuery(function () {\n          SphinxRtdTheme.Navigation.enable(true);\n      });\n  </script>\n\n  \n  \n    \n   \n\n</body>\n</html>"
  },
  {
    "path": "docs/_modules/plugins/LocalPlayer.html",
    "content": "\n\n<!DOCTYPE html>\n<!--[if IE 8]><html class=\"no-js lt-ie9\" lang=\"zh-CN\" > <![endif]-->\n<!--[if gt IE 8]><!--> <html class=\"no-js\" lang=\"zh-CN\" > <!--<![endif]-->\n<head>\n  <meta charset=\"utf-8\">\n  \n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  \n  <title>plugins.LocalPlayer &mdash; wukong-robot 1.2.0 文档</title>\n  \n\n  \n  \n  \n  \n\n  \n  <script type=\"text/javascript\" src=\"../../_static/js/modernizr.min.js\"></script>\n  \n    \n      <script type=\"text/javascript\" id=\"documentation_options\" data-url_root=\"../../\" src=\"../../_static/documentation_options.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/jquery.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/underscore.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/doctools.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/language_data.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/translations.js\"></script>\n    \n    <script type=\"text/javascript\" src=\"../../_static/js/theme.js\"></script>\n\n    \n\n  \n  <link rel=\"stylesheet\" href=\"../../_static/css/theme.css\" type=\"text/css\" />\n  <link rel=\"stylesheet\" href=\"../../_static/pygments.css\" type=\"text/css\" />\n    <link rel=\"index\" title=\"索引\" href=\"../../genindex.html\" />\n    <link rel=\"search\" title=\"搜索\" href=\"../../search.html\" /> \n</head>\n\n<body class=\"wy-body-for-nav\">\n\n   \n  <div class=\"wy-grid-for-nav\">\n    \n    <nav data-toggle=\"wy-nav-shift\" class=\"wy-nav-side\">\n      <div class=\"wy-side-scroll\">\n        <div class=\"wy-side-nav-search\" >\n          \n\n          \n            <a href=\"../../index.html\" class=\"icon icon-home\"> wukong-robot\n          \n\n          \n          </a>\n\n          \n            \n            \n          \n\n          \n<div role=\"search\">\n  <form id=\"rtd-search-form\" class=\"wy-form\" action=\"../../search.html\" method=\"get\">\n    <input type=\"text\" name=\"q\" placeholder=\"Search docs\" />\n    <input type=\"hidden\" name=\"check_keywords\" value=\"yes\" />\n    <input type=\"hidden\" name=\"area\" value=\"default\" />\n  </form>\n</div>\n\n          \n        </div>\n\n        <div class=\"wy-menu wy-menu-vertical\" data-spy=\"affix\" role=\"navigation\" aria-label=\"main navigation\">\n          \n            \n            \n              \n            \n            \n              <!-- Local TOC -->\n              <div class=\"local-toc\"></div>\n            \n          \n        </div>\n      </div>\n    </nav>\n\n    <section data-toggle=\"wy-nav-shift\" class=\"wy-nav-content-wrap\">\n\n      \n      <nav class=\"wy-nav-top\" aria-label=\"top navigation\">\n        \n          <i data-toggle=\"wy-nav-top\" class=\"fa fa-bars\"></i>\n          <a href=\"../../index.html\">wukong-robot</a>\n        \n      </nav>\n\n\n      <div class=\"wy-nav-content\">\n        \n        <div class=\"rst-content\">\n        \n          \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<div role=\"navigation\" aria-label=\"breadcrumbs navigation\">\n\n  <ul class=\"wy-breadcrumbs\">\n    \n      <li><a href=\"../../index.html\">Docs</a> &raquo;</li>\n        \n          <li><a href=\"../index.html\">模块代码</a> &raquo;</li>\n        \n      <li>plugins.LocalPlayer</li>\n    \n    \n      <li class=\"wy-breadcrumbs-aside\">\n        \n      </li>\n    \n  </ul>\n\n  \n  <hr/>\n</div>\n          <div role=\"main\" class=\"document\" itemscope=\"itemscope\" itemtype=\"http://schema.org/Article\">\n           <div itemprop=\"articleBody\">\n            \n  <h1>plugins.LocalPlayer 源代码</h1><div class=\"highlight\"><pre>\n<span></span><span class=\"c1\"># -*- coding: utf-8-*-</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">from</span> <span class=\"nn\">robot</span> <span class=\"k\">import</span> <span class=\"n\">config</span><span class=\"p\">,</span> <span class=\"n\">logging</span>\n<span class=\"kn\">from</span> <span class=\"nn\">robot.Player</span> <span class=\"k\">import</span> <span class=\"n\">MusicPlayer</span>\n<span class=\"kn\">from</span> <span class=\"nn\">robot.sdk.AbstractPlugin</span> <span class=\"k\">import</span> <span class=\"n\">AbstractPlugin</span>\n\n<span class=\"n\">logger</span> <span class=\"o\">=</span> <span class=\"n\">logging</span><span class=\"o\">.</span><span class=\"n\">getLogger</span><span class=\"p\">(</span><span class=\"vm\">__name__</span><span class=\"p\">)</span>\n\n<div class=\"viewcode-block\" id=\"Plugin\"><a class=\"viewcode-back\" href=\"../../plugins.html#plugins.LocalPlayer.Plugin\">[文档]</a><span class=\"k\">class</span> <span class=\"nc\">Plugin</span><span class=\"p\">(</span><span class=\"n\">AbstractPlugin</span><span class=\"p\">):</span>\n\n    <span class=\"n\">IS_IMMERSIVE</span> <span class=\"o\">=</span> <span class=\"kc\">True</span>  <span class=\"c1\"># 这是个沉浸式技能</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">con</span><span class=\"p\">):</span>\n        <span class=\"nb\">super</span><span class=\"p\">(</span><span class=\"n\">Plugin</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">)</span><span class=\"o\">.</span><span class=\"fm\">__init__</span><span class=\"p\">(</span><span class=\"n\">con</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">player</span> <span class=\"o\">=</span> <span class=\"kc\">None</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">song_list</span> <span class=\"o\">=</span> <span class=\"kc\">None</span>        \n\n<div class=\"viewcode-block\" id=\"Plugin.get_song_list\"><a class=\"viewcode-back\" href=\"../../plugins.html#plugins.LocalPlayer.Plugin.get_song_list\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">get_song_list</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">path</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">exists</span><span class=\"p\">(</span><span class=\"n\">path</span><span class=\"p\">)</span> <span class=\"ow\">or</span> \\\n           <span class=\"ow\">not</span> <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">isdir</span><span class=\"p\">(</span><span class=\"n\">path</span><span class=\"p\">):</span>\n            <span class=\"k\">return</span> <span class=\"p\">[]</span>\n        <span class=\"n\">song_list</span> <span class=\"o\">=</span> <span class=\"nb\">list</span><span class=\"p\">(</span><span class=\"nb\">filter</span><span class=\"p\">(</span><span class=\"k\">lambda</span> <span class=\"n\">d</span><span class=\"p\">:</span> <span class=\"n\">d</span><span class=\"o\">.</span><span class=\"n\">endswith</span><span class=\"p\">(</span><span class=\"s1\">&#39;.mp3&#39;</span><span class=\"p\">),</span> <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">listdir</span><span class=\"p\">(</span><span class=\"n\">path</span><span class=\"p\">)))</span>\n        <span class=\"k\">return</span> <span class=\"p\">[</span><span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">path</span><span class=\"p\">,</span> <span class=\"n\">song</span><span class=\"p\">)</span> <span class=\"k\">for</span> <span class=\"n\">song</span> <span class=\"ow\">in</span> <span class=\"n\">song_list</span><span class=\"p\">]</span></div>\n\n<div class=\"viewcode-block\" id=\"Plugin.init_music_player\"><a class=\"viewcode-back\" href=\"../../plugins.html#plugins.LocalPlayer.Plugin.init_music_player\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">init_music_player</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">song_list</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">get_song_list</span><span class=\"p\">(</span><span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;/LocalPlayer/path&#39;</span><span class=\"p\">))</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">song_list</span> <span class=\"o\">==</span> <span class=\"kc\">None</span><span class=\"p\">:</span>\n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">error</span><span class=\"p\">(</span><span class=\"s1\">&#39;</span><span class=\"si\">{}</span><span class=\"s1\"> 插件配置有误&#39;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">SLUG</span><span class=\"p\">))</span>\n        <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s1\">&#39;本地音乐列表：</span><span class=\"si\">{}</span><span class=\"s1\">&#39;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">song_list</span><span class=\"p\">))</span>\n        <span class=\"k\">return</span> <span class=\"n\">MusicPlayer</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">song_list</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"Plugin.handle\"><a class=\"viewcode-back\" href=\"../../plugins.html#plugins.LocalPlayer.Plugin.handle\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">handle</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">text</span><span class=\"p\">,</span> <span class=\"n\">parsed</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">player</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">player</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">init_music_player</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">song_list</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">clearImmersive</span><span class=\"p\">()</span>  <span class=\"c1\"># 去掉沉浸式</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">say</span><span class=\"p\">(</span><span class=\"s1\">&#39;本地音乐目录并没有音乐文件，播放失败&#39;</span><span class=\"p\">)</span>\n            <span class=\"k\">return</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">nlu</span><span class=\"o\">.</span><span class=\"n\">hasIntent</span><span class=\"p\">(</span><span class=\"n\">parsed</span><span class=\"p\">,</span> <span class=\"s1\">&#39;MUSICRANK&#39;</span><span class=\"p\">):</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">player</span><span class=\"o\">.</span><span class=\"n\">play</span><span class=\"p\">()</span>\n        <span class=\"k\">elif</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">nlu</span><span class=\"o\">.</span><span class=\"n\">hasIntent</span><span class=\"p\">(</span><span class=\"n\">parsed</span><span class=\"p\">,</span> <span class=\"s1\">&#39;CHANGE_TO_NEXT&#39;</span><span class=\"p\">):</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">player</span><span class=\"o\">.</span><span class=\"n\">next</span><span class=\"p\">()</span>\n        <span class=\"k\">elif</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">nlu</span><span class=\"o\">.</span><span class=\"n\">hasIntent</span><span class=\"p\">(</span><span class=\"n\">parsed</span><span class=\"p\">,</span> <span class=\"s1\">&#39;CHANGE_TO_LAST&#39;</span><span class=\"p\">):</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">player</span><span class=\"o\">.</span><span class=\"n\">prev</span><span class=\"p\">()</span>\n        <span class=\"k\">elif</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">nlu</span><span class=\"o\">.</span><span class=\"n\">hasIntent</span><span class=\"p\">(</span><span class=\"n\">parsed</span><span class=\"p\">,</span> <span class=\"s1\">&#39;CHANGE_VOL&#39;</span><span class=\"p\">):</span>\n            <span class=\"n\">slots</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">nlu</span><span class=\"o\">.</span><span class=\"n\">getSlots</span><span class=\"p\">(</span><span class=\"n\">parsed</span><span class=\"p\">,</span> <span class=\"s1\">&#39;CHANGE_VOL&#39;</span><span class=\"p\">)</span>\n            <span class=\"k\">for</span> <span class=\"n\">slot</span> <span class=\"ow\">in</span> <span class=\"n\">slots</span><span class=\"p\">:</span>\n                <span class=\"k\">if</span> <span class=\"n\">slot</span><span class=\"p\">[</span><span class=\"s1\">&#39;name&#39;</span><span class=\"p\">]</span> <span class=\"o\">==</span> <span class=\"s1\">&#39;user_d&#39;</span><span class=\"p\">:</span>\n                    <span class=\"n\">word</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">nlu</span><span class=\"o\">.</span><span class=\"n\">getSlotWords</span><span class=\"p\">(</span><span class=\"n\">parsed</span><span class=\"p\">,</span> <span class=\"s1\">&#39;CHANGE_VOL&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;user_d&#39;</span><span class=\"p\">)[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n                    <span class=\"k\">if</span> <span class=\"n\">word</span> <span class=\"o\">==</span> <span class=\"s1\">&#39;--HIGHER--&#39;</span><span class=\"p\">:</span>\n                        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">player</span><span class=\"o\">.</span><span class=\"n\">turnUp</span><span class=\"p\">()</span>\n                    <span class=\"k\">else</span><span class=\"p\">:</span>\n                        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">player</span><span class=\"o\">.</span><span class=\"n\">turnDown</span><span class=\"p\">()</span>\n                    <span class=\"k\">return</span>\n                <span class=\"k\">elif</span> <span class=\"n\">slot</span><span class=\"p\">[</span><span class=\"s1\">&#39;name&#39;</span><span class=\"p\">]</span> <span class=\"o\">==</span> <span class=\"s1\">&#39;user_vd&#39;</span><span class=\"p\">:</span>\n                    <span class=\"n\">word</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">nlu</span><span class=\"o\">.</span><span class=\"n\">getSlotWords</span><span class=\"p\">(</span><span class=\"n\">parsed</span><span class=\"p\">,</span> <span class=\"s1\">&#39;CHANGE_VOL&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;user_vd&#39;</span><span class=\"p\">)[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n                    <span class=\"k\">if</span> <span class=\"n\">word</span> <span class=\"o\">==</span> <span class=\"s1\">&#39;--LOUDER--&#39;</span><span class=\"p\">:</span>\n                        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">player</span><span class=\"o\">.</span><span class=\"n\">turnUp</span><span class=\"p\">()</span>\n                    <span class=\"k\">else</span><span class=\"p\">:</span>\n                        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">player</span><span class=\"o\">.</span><span class=\"n\">turnDown</span><span class=\"p\">()</span>\n\n        <span class=\"k\">elif</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">nlu</span><span class=\"o\">.</span><span class=\"n\">hasIntent</span><span class=\"p\">(</span><span class=\"n\">parsed</span><span class=\"p\">,</span> <span class=\"s1\">&#39;PAUSE&#39;</span><span class=\"p\">):</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">player</span><span class=\"o\">.</span><span class=\"n\">pause</span><span class=\"p\">()</span>\n        <span class=\"k\">elif</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">nlu</span><span class=\"o\">.</span><span class=\"n\">hasIntent</span><span class=\"p\">(</span><span class=\"n\">parsed</span><span class=\"p\">,</span> <span class=\"s1\">&#39;CONTINUE&#39;</span><span class=\"p\">):</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">player</span><span class=\"o\">.</span><span class=\"n\">resume</span><span class=\"p\">()</span>\n        <span class=\"k\">elif</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">nlu</span><span class=\"o\">.</span><span class=\"n\">hasIntent</span><span class=\"p\">(</span><span class=\"n\">parsed</span><span class=\"p\">,</span> <span class=\"s1\">&#39;CLOSE_MUSIC&#39;</span><span class=\"p\">):</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">player</span><span class=\"o\">.</span><span class=\"n\">stop</span><span class=\"p\">()</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">clearImmersive</span><span class=\"p\">()</span>  <span class=\"c1\"># 去掉沉浸式</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">say</span><span class=\"p\">(</span><span class=\"s1\">&#39;没听懂你的意思呢，要停止播放，请说停止播放&#39;</span><span class=\"p\">,</span> <span class=\"n\">wait</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">)</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">player</span><span class=\"o\">.</span><span class=\"n\">resume</span><span class=\"p\">()</span></div>\n\n<div class=\"viewcode-block\" id=\"Plugin.pause\"><a class=\"viewcode-back\" href=\"../../plugins.html#plugins.LocalPlayer.Plugin.pause\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">pause</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">player</span><span class=\"o\">.</span><span class=\"n\">stop</span><span class=\"p\">()</span></div>\n\n<div class=\"viewcode-block\" id=\"Plugin.restore\"><a class=\"viewcode-back\" href=\"../../plugins.html#plugins.LocalPlayer.Plugin.restore\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">restore</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">player</span> <span class=\"ow\">and</span> <span class=\"ow\">not</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">player</span><span class=\"o\">.</span><span class=\"n\">is_pausing</span><span class=\"p\">():</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">player</span><span class=\"o\">.</span><span class=\"n\">resume</span><span class=\"p\">()</span></div>\n\n<div class=\"viewcode-block\" id=\"Plugin.isValidImmersive\"><a class=\"viewcode-back\" href=\"../../plugins.html#plugins.LocalPlayer.Plugin.isValidImmersive\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">isValidImmersive</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">text</span><span class=\"p\">,</span> <span class=\"n\">parsed</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"nb\">any</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">nlu</span><span class=\"o\">.</span><span class=\"n\">hasIntent</span><span class=\"p\">(</span><span class=\"n\">parsed</span><span class=\"p\">,</span> <span class=\"n\">intent</span><span class=\"p\">)</span> <span class=\"k\">for</span> <span class=\"n\">intent</span> <span class=\"ow\">in</span> <span class=\"p\">[</span><span class=\"s1\">&#39;CHANGE_TO_LAST&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;CHANGE_TO_NEXT&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;CHANGE_VOL&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;CLOSE_MUSIC&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;PAUSE&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;CONTINUE&#39;</span><span class=\"p\">])</span></div>\n\n<div class=\"viewcode-block\" id=\"Plugin.isValid\"><a class=\"viewcode-back\" href=\"../../plugins.html#plugins.LocalPlayer.Plugin.isValid\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">isValid</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">text</span><span class=\"p\">,</span> <span class=\"n\">parsed</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"s2\">&quot;本地音乐&quot;</span> <span class=\"ow\">in</span> <span class=\"n\">text</span></div></div>\n\n</pre></div>\n\n           </div>\n           \n          </div>\n          <footer>\n  \n\n  <hr/>\n\n  <div role=\"contentinfo\">\n    <p>\n        &copy; Copyright 2019, wzpan\n\n    </p>\n  </div>\n  Built with <a href=\"http://sphinx-doc.org/\">Sphinx</a> using a <a href=\"https://github.com/rtfd/sphinx_rtd_theme\">theme</a> provided by <a href=\"https://readthedocs.org\">Read the Docs</a>. \n\n</footer>\n\n        </div>\n      </div>\n\n    </section>\n\n  </div>\n  \n\n\n  <script type=\"text/javascript\">\n      jQuery(function () {\n          SphinxRtdTheme.Navigation.enable(true);\n      });\n  </script>\n\n  \n  \n    \n   \n\n</body>\n</html>"
  },
  {
    "path": "docs/_modules/plugins/Poem.html",
    "content": "\n\n<!DOCTYPE html>\n<!--[if IE 8]><html class=\"no-js lt-ie9\" lang=\"zh-CN\" > <![endif]-->\n<!--[if gt IE 8]><!--> <html class=\"no-js\" lang=\"zh-CN\" > <!--<![endif]-->\n<head>\n  <meta charset=\"utf-8\">\n  \n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  \n  <title>plugins.Poem &mdash; wukong-robot 1.2.0 文档</title>\n  \n\n  \n  \n  \n  \n\n  \n  <script type=\"text/javascript\" src=\"../../_static/js/modernizr.min.js\"></script>\n  \n    \n      <script type=\"text/javascript\" id=\"documentation_options\" data-url_root=\"../../\" src=\"../../_static/documentation_options.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/jquery.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/underscore.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/doctools.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/language_data.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/translations.js\"></script>\n    \n    <script type=\"text/javascript\" src=\"../../_static/js/theme.js\"></script>\n\n    \n\n  \n  <link rel=\"stylesheet\" href=\"../../_static/css/theme.css\" type=\"text/css\" />\n  <link rel=\"stylesheet\" href=\"../../_static/pygments.css\" type=\"text/css\" />\n    <link rel=\"index\" title=\"索引\" href=\"../../genindex.html\" />\n    <link rel=\"search\" title=\"搜索\" href=\"../../search.html\" /> \n</head>\n\n<body class=\"wy-body-for-nav\">\n\n   \n  <div class=\"wy-grid-for-nav\">\n    \n    <nav data-toggle=\"wy-nav-shift\" class=\"wy-nav-side\">\n      <div class=\"wy-side-scroll\">\n        <div class=\"wy-side-nav-search\" >\n          \n\n          \n            <a href=\"../../index.html\" class=\"icon icon-home\"> wukong-robot\n          \n\n          \n          </a>\n\n          \n            \n            \n          \n\n          \n<div role=\"search\">\n  <form id=\"rtd-search-form\" class=\"wy-form\" action=\"../../search.html\" method=\"get\">\n    <input type=\"text\" name=\"q\" placeholder=\"Search docs\" />\n    <input type=\"hidden\" name=\"check_keywords\" value=\"yes\" />\n    <input type=\"hidden\" name=\"area\" value=\"default\" />\n  </form>\n</div>\n\n          \n        </div>\n\n        <div class=\"wy-menu wy-menu-vertical\" data-spy=\"affix\" role=\"navigation\" aria-label=\"main navigation\">\n          \n            \n            \n              \n            \n            \n              <!-- Local TOC -->\n              <div class=\"local-toc\"></div>\n            \n          \n        </div>\n      </div>\n    </nav>\n\n    <section data-toggle=\"wy-nav-shift\" class=\"wy-nav-content-wrap\">\n\n      \n      <nav class=\"wy-nav-top\" aria-label=\"top navigation\">\n        \n          <i data-toggle=\"wy-nav-top\" class=\"fa fa-bars\"></i>\n          <a href=\"../../index.html\">wukong-robot</a>\n        \n      </nav>\n\n\n      <div class=\"wy-nav-content\">\n        \n        <div class=\"rst-content\">\n        \n          \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<div role=\"navigation\" aria-label=\"breadcrumbs navigation\">\n\n  <ul class=\"wy-breadcrumbs\">\n    \n      <li><a href=\"../../index.html\">Docs</a> &raquo;</li>\n        \n          <li><a href=\"../index.html\">模块代码</a> &raquo;</li>\n        \n      <li>plugins.Poem</li>\n    \n    \n      <li class=\"wy-breadcrumbs-aside\">\n        \n      </li>\n    \n  </ul>\n\n  \n  <hr/>\n</div>\n          <div role=\"main\" class=\"document\" itemscope=\"itemscope\" itemtype=\"http://schema.org/Article\">\n           <div itemprop=\"articleBody\">\n            \n  <h1>plugins.Poem 源代码</h1><div class=\"highlight\"><pre>\n<span></span><span class=\"c1\"># -*- coding: utf-8-*-</span>\n<span class=\"c1\"># author: wzpan</span>\n<span class=\"c1\"># 写诗</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">logging</span>\n<span class=\"kn\">from</span> <span class=\"nn\">robot.sdk.AbstractPlugin</span> <span class=\"k\">import</span> <span class=\"n\">AbstractPlugin</span>\n\n<span class=\"n\">INTENT</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;BUILT_POEM&quot;</span>\n\n<span class=\"n\">logger</span> <span class=\"o\">=</span> <span class=\"n\">logging</span><span class=\"o\">.</span><span class=\"n\">getLogger</span><span class=\"p\">(</span><span class=\"vm\">__name__</span><span class=\"p\">)</span>\n\n<div class=\"viewcode-block\" id=\"Plugin\"><a class=\"viewcode-back\" href=\"../../plugins.html#plugins.Poem.Plugin\">[文档]</a><span class=\"k\">class</span> <span class=\"nc\">Plugin</span><span class=\"p\">(</span><span class=\"n\">AbstractPlugin</span><span class=\"p\">):</span>\n\n    <span class=\"n\">SLUG</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;poem&quot;</span>\n\n<div class=\"viewcode-block\" id=\"Plugin.handle\"><a class=\"viewcode-back\" href=\"../../plugins.html#plugins.Poem.Plugin.handle\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">handle</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">text</span><span class=\"p\">,</span> <span class=\"n\">parsed</span><span class=\"p\">):</span>\n        <span class=\"k\">try</span><span class=\"p\">:</span>\n            <span class=\"n\">responds</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">nlu</span><span class=\"o\">.</span><span class=\"n\">getSay</span><span class=\"p\">(</span><span class=\"n\">parsed</span><span class=\"p\">,</span> <span class=\"n\">INTENT</span><span class=\"p\">)</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">say</span><span class=\"p\">(</span><span class=\"n\">responds</span><span class=\"p\">,</span> <span class=\"n\">cache</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">)</span>\n        <span class=\"k\">except</span> <span class=\"ne\">Exception</span> <span class=\"k\">as</span> <span class=\"n\">e</span><span class=\"p\">:</span>\n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">error</span><span class=\"p\">(</span><span class=\"n\">e</span><span class=\"p\">)</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">say</span><span class=\"p\">(</span><span class=\"s1\">&#39;抱歉，写诗插件出问题了，请稍后再试&#39;</span><span class=\"p\">,</span> <span class=\"n\">cache</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"Plugin.isValid\"><a class=\"viewcode-back\" href=\"../../plugins.html#plugins.Poem.Plugin.isValid\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">isValid</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">text</span><span class=\"p\">,</span> <span class=\"n\">parsed</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">nlu</span><span class=\"o\">.</span><span class=\"n\">hasIntent</span><span class=\"p\">(</span><span class=\"n\">parsed</span><span class=\"p\">,</span> <span class=\"n\">INTENT</span><span class=\"p\">)</span> <span class=\"ow\">and</span> <span class=\"s1\">&#39;写&#39;</span> <span class=\"ow\">in</span> <span class=\"n\">text</span> <span class=\"ow\">and</span> <span class=\"s1\">&#39;诗&#39;</span> <span class=\"ow\">in</span> <span class=\"n\">text</span></div></div>\n        \n        \n</pre></div>\n\n           </div>\n           \n          </div>\n          <footer>\n  \n\n  <hr/>\n\n  <div role=\"contentinfo\">\n    <p>\n        &copy; Copyright 2019, wzpan\n\n    </p>\n  </div>\n  Built with <a href=\"http://sphinx-doc.org/\">Sphinx</a> using a <a href=\"https://github.com/rtfd/sphinx_rtd_theme\">theme</a> provided by <a href=\"https://readthedocs.org\">Read the Docs</a>. \n\n</footer>\n\n        </div>\n      </div>\n\n    </section>\n\n  </div>\n  \n\n\n  <script type=\"text/javascript\">\n      jQuery(function () {\n          SphinxRtdTheme.Navigation.enable(true);\n      });\n  </script>\n\n  \n  \n    \n   \n\n</body>\n</html>"
  },
  {
    "path": "docs/_modules/robot/AI.html",
    "content": "\n\n<!DOCTYPE html>\n<!--[if IE 8]><html class=\"no-js lt-ie9\" lang=\"zh-CN\" > <![endif]-->\n<!--[if gt IE 8]><!--> <html class=\"no-js\" lang=\"zh-CN\" > <!--<![endif]-->\n<head>\n  <meta charset=\"utf-8\">\n  \n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  \n  <title>robot.AI &mdash; wukong-robot 1.2.0 文档</title>\n  \n\n  \n  \n  \n  \n\n  \n  <script type=\"text/javascript\" src=\"../../_static/js/modernizr.min.js\"></script>\n  \n    \n      <script type=\"text/javascript\" id=\"documentation_options\" data-url_root=\"../../\" src=\"../../_static/documentation_options.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/jquery.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/underscore.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/doctools.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/language_data.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/translations.js\"></script>\n    \n    <script type=\"text/javascript\" src=\"../../_static/js/theme.js\"></script>\n\n    \n\n  \n  <link rel=\"stylesheet\" href=\"../../_static/css/theme.css\" type=\"text/css\" />\n  <link rel=\"stylesheet\" href=\"../../_static/pygments.css\" type=\"text/css\" />\n    <link rel=\"index\" title=\"索引\" href=\"../../genindex.html\" />\n    <link rel=\"search\" title=\"搜索\" href=\"../../search.html\" /> \n</head>\n\n<body class=\"wy-body-for-nav\">\n\n   \n  <div class=\"wy-grid-for-nav\">\n    \n    <nav data-toggle=\"wy-nav-shift\" class=\"wy-nav-side\">\n      <div class=\"wy-side-scroll\">\n        <div class=\"wy-side-nav-search\" >\n          \n\n          \n            <a href=\"../../index.html\" class=\"icon icon-home\"> wukong-robot\n          \n\n          \n          </a>\n\n          \n            \n            \n          \n\n          \n<div role=\"search\">\n  <form id=\"rtd-search-form\" class=\"wy-form\" action=\"../../search.html\" method=\"get\">\n    <input type=\"text\" name=\"q\" placeholder=\"Search docs\" />\n    <input type=\"hidden\" name=\"check_keywords\" value=\"yes\" />\n    <input type=\"hidden\" name=\"area\" value=\"default\" />\n  </form>\n</div>\n\n          \n        </div>\n\n        <div class=\"wy-menu wy-menu-vertical\" data-spy=\"affix\" role=\"navigation\" aria-label=\"main navigation\">\n          \n            \n            \n              \n            \n            \n              <!-- Local TOC -->\n              <div class=\"local-toc\"></div>\n            \n          \n        </div>\n      </div>\n    </nav>\n\n    <section data-toggle=\"wy-nav-shift\" class=\"wy-nav-content-wrap\">\n\n      \n      <nav class=\"wy-nav-top\" aria-label=\"top navigation\">\n        \n          <i data-toggle=\"wy-nav-top\" class=\"fa fa-bars\"></i>\n          <a href=\"../../index.html\">wukong-robot</a>\n        \n      </nav>\n\n\n      <div class=\"wy-nav-content\">\n        \n        <div class=\"rst-content\">\n        \n          \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<div role=\"navigation\" aria-label=\"breadcrumbs navigation\">\n\n  <ul class=\"wy-breadcrumbs\">\n    \n      <li><a href=\"../../index.html\">Docs</a> &raquo;</li>\n        \n          <li><a href=\"../index.html\">模块代码</a> &raquo;</li>\n        \n      <li>robot.AI</li>\n    \n    \n      <li class=\"wy-breadcrumbs-aside\">\n        \n      </li>\n    \n  </ul>\n\n  \n  <hr/>\n</div>\n          <div role=\"main\" class=\"document\" itemscope=\"itemscope\" itemtype=\"http://schema.org/Article\">\n           <div itemprop=\"articleBody\">\n            \n  <h1>robot.AI 源代码</h1><div class=\"highlight\"><pre>\n<span></span><span class=\"c1\"># -*- coding: utf-8-*-</span>\n<span class=\"kn\">import</span> <span class=\"nn\">requests</span>\n<span class=\"kn\">import</span> <span class=\"nn\">json</span>\n<span class=\"kn\">from</span> <span class=\"nn\">robot</span> <span class=\"k\">import</span> <span class=\"n\">logging</span>\n<span class=\"kn\">from</span> <span class=\"nn\">robot</span> <span class=\"k\">import</span> <span class=\"n\">config</span>\n<span class=\"kn\">from</span> <span class=\"nn\">uuid</span> <span class=\"k\">import</span> <span class=\"n\">getnode</span> <span class=\"k\">as</span> <span class=\"n\">get_mac</span>\n<span class=\"kn\">from</span> <span class=\"nn\">abc</span> <span class=\"k\">import</span> <span class=\"n\">ABCMeta</span><span class=\"p\">,</span> <span class=\"n\">abstractmethod</span>\n\n<span class=\"n\">logger</span> <span class=\"o\">=</span> <span class=\"n\">logging</span><span class=\"o\">.</span><span class=\"n\">getLogger</span><span class=\"p\">(</span><span class=\"vm\">__name__</span><span class=\"p\">)</span>\n\n<div class=\"viewcode-block\" id=\"AbstractRobot\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.AI.AbstractRobot\">[文档]</a><span class=\"k\">class</span> <span class=\"nc\">AbstractRobot</span><span class=\"p\">(</span><span class=\"nb\">object</span><span class=\"p\">):</span>\n\n    <span class=\"n\">__metaclass__</span> <span class=\"o\">=</span> <span class=\"n\">ABCMeta</span>\n\n<div class=\"viewcode-block\" id=\"AbstractRobot.get_instance\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.AI.AbstractRobot.get_instance\">[文档]</a>    <span class=\"nd\">@classmethod</span>\n    <span class=\"k\">def</span> <span class=\"nf\">get_instance</span><span class=\"p\">(</span><span class=\"bp\">cls</span><span class=\"p\">):</span>\n        <span class=\"n\">profile</span> <span class=\"o\">=</span> <span class=\"bp\">cls</span><span class=\"o\">.</span><span class=\"n\">get_config</span><span class=\"p\">()</span>\n        <span class=\"n\">instance</span> <span class=\"o\">=</span> <span class=\"bp\">cls</span><span class=\"p\">(</span><span class=\"o\">**</span><span class=\"n\">profile</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span> <span class=\"n\">instance</span></div>\n\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">):</span>\n        <span class=\"k\">pass</span>\n\n<div class=\"viewcode-block\" id=\"AbstractRobot.chat\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.AI.AbstractRobot.chat\">[文档]</a>    <span class=\"nd\">@abstractmethod</span>\n    <span class=\"k\">def</span> <span class=\"nf\">chat</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">texts</span><span class=\"p\">):</span>\n        <span class=\"k\">pass</span></div></div>\n\n\n<div class=\"viewcode-block\" id=\"TulingRobot\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.AI.TulingRobot\">[文档]</a><span class=\"k\">class</span> <span class=\"nc\">TulingRobot</span><span class=\"p\">(</span><span class=\"n\">AbstractRobot</span><span class=\"p\">):</span>\n\n    <span class=\"n\">SLUG</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;tuling&quot;</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">tuling_key</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        图灵机器人</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"nb\">super</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"vm\">__class__</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">)</span><span class=\"o\">.</span><span class=\"fm\">__init__</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">tuling_key</span> <span class=\"o\">=</span> <span class=\"n\">tuling_key</span>\n\n<div class=\"viewcode-block\" id=\"TulingRobot.get_config\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.AI.TulingRobot.get_config\">[文档]</a>    <span class=\"nd\">@classmethod</span>\n    <span class=\"k\">def</span> <span class=\"nf\">get_config</span><span class=\"p\">(</span><span class=\"bp\">cls</span><span class=\"p\">):</span>\n        <span class=\"c1\"># Try to get ali_yuyin config from config</span>\n        <span class=\"k\">return</span> <span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;tuling&#39;</span><span class=\"p\">,</span> <span class=\"p\">{})</span></div>\n\n<div class=\"viewcode-block\" id=\"TulingRobot.chat\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.AI.TulingRobot.chat\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">chat</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">texts</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        使用图灵机器人聊天</span>\n\n<span class=\"sd\">        Arguments:</span>\n<span class=\"sd\">        texts -- user input, typically speech, to be parsed by a module</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"n\">msg</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;&#39;</span><span class=\"o\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">texts</span><span class=\"p\">)</span>\n        <span class=\"k\">try</span><span class=\"p\">:</span>\n            <span class=\"n\">url</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;http://www.tuling123.com/openapi/api&quot;</span>\n            <span class=\"n\">userid</span> <span class=\"o\">=</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">get_mac</span><span class=\"p\">())[:</span><span class=\"mi\">32</span><span class=\"p\">]</span>\n            <span class=\"n\">body</span> <span class=\"o\">=</span> <span class=\"p\">{</span><span class=\"s1\">&#39;key&#39;</span><span class=\"p\">:</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">tuling_key</span><span class=\"p\">,</span> <span class=\"s1\">&#39;info&#39;</span><span class=\"p\">:</span> <span class=\"n\">msg</span><span class=\"p\">,</span> <span class=\"s1\">&#39;userid&#39;</span><span class=\"p\">:</span> <span class=\"n\">userid</span><span class=\"p\">}</span>\n            <span class=\"n\">r</span> <span class=\"o\">=</span> <span class=\"n\">requests</span><span class=\"o\">.</span><span class=\"n\">post</span><span class=\"p\">(</span><span class=\"n\">url</span><span class=\"p\">,</span> <span class=\"n\">data</span><span class=\"o\">=</span><span class=\"n\">body</span><span class=\"p\">)</span>\n            <span class=\"n\">respond</span> <span class=\"o\">=</span> <span class=\"n\">json</span><span class=\"o\">.</span><span class=\"n\">loads</span><span class=\"p\">(</span><span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">text</span><span class=\"p\">)</span>\n            <span class=\"n\">result</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;&#39;</span>\n            <span class=\"k\">if</span> <span class=\"n\">respond</span><span class=\"p\">[</span><span class=\"s1\">&#39;code&#39;</span><span class=\"p\">]</span> <span class=\"o\">==</span> <span class=\"mi\">100000</span><span class=\"p\">:</span>\n                <span class=\"n\">result</span> <span class=\"o\">=</span> <span class=\"n\">respond</span><span class=\"p\">[</span><span class=\"s1\">&#39;text&#39;</span><span class=\"p\">]</span><span class=\"o\">.</span><span class=\"n\">replace</span><span class=\"p\">(</span><span class=\"s1\">&#39;&lt;br&gt;&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;  &#39;</span><span class=\"p\">)</span>\n                <span class=\"n\">result</span> <span class=\"o\">=</span> <span class=\"n\">result</span><span class=\"o\">.</span><span class=\"n\">replace</span><span class=\"p\">(</span><span class=\"sa\">u</span><span class=\"s1\">&#39;</span><span class=\"se\">\\xa0</span><span class=\"s1\">&#39;</span><span class=\"p\">,</span> <span class=\"sa\">u</span><span class=\"s1\">&#39; &#39;</span><span class=\"p\">)</span>\n            <span class=\"k\">elif</span> <span class=\"n\">respond</span><span class=\"p\">[</span><span class=\"s1\">&#39;code&#39;</span><span class=\"p\">]</span> <span class=\"o\">==</span> <span class=\"mi\">200000</span><span class=\"p\">:</span>\n                <span class=\"n\">result</span> <span class=\"o\">=</span> <span class=\"n\">respond</span><span class=\"p\">[</span><span class=\"s1\">&#39;url&#39;</span><span class=\"p\">]</span>\n            <span class=\"k\">elif</span> <span class=\"n\">respond</span><span class=\"p\">[</span><span class=\"s1\">&#39;code&#39;</span><span class=\"p\">]</span> <span class=\"o\">==</span> <span class=\"mi\">302000</span><span class=\"p\">:</span>\n                <span class=\"k\">for</span> <span class=\"n\">k</span> <span class=\"ow\">in</span> <span class=\"n\">respond</span><span class=\"p\">[</span><span class=\"s1\">&#39;list&#39;</span><span class=\"p\">]:</span>\n                    <span class=\"n\">result</span> <span class=\"o\">=</span> <span class=\"n\">result</span> <span class=\"o\">+</span> <span class=\"sa\">u</span><span class=\"s2\">&quot;【&quot;</span> <span class=\"o\">+</span> <span class=\"n\">k</span><span class=\"p\">[</span><span class=\"s1\">&#39;source&#39;</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"sa\">u</span><span class=\"s2\">&quot;】 &quot;</span> <span class=\"o\">+</span>\\\n                        <span class=\"n\">k</span><span class=\"p\">[</span><span class=\"s1\">&#39;article&#39;</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"s2\">&quot;</span><span class=\"se\">\\t</span><span class=\"s2\">&quot;</span> <span class=\"o\">+</span> <span class=\"n\">k</span><span class=\"p\">[</span><span class=\"s1\">&#39;detailurl&#39;</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"s2\">&quot;</span><span class=\"se\">\\n</span><span class=\"s2\">&quot;</span>\n            <span class=\"k\">else</span><span class=\"p\">:</span>\n                <span class=\"n\">result</span> <span class=\"o\">=</span> <span class=\"n\">respond</span><span class=\"p\">[</span><span class=\"s1\">&#39;text&#39;</span><span class=\"p\">]</span><span class=\"o\">.</span><span class=\"n\">replace</span><span class=\"p\">(</span><span class=\"s1\">&#39;&lt;br&gt;&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;  &#39;</span><span class=\"p\">)</span>\n                <span class=\"n\">result</span> <span class=\"o\">=</span> <span class=\"n\">result</span><span class=\"o\">.</span><span class=\"n\">replace</span><span class=\"p\">(</span><span class=\"sa\">u</span><span class=\"s1\">&#39;</span><span class=\"se\">\\xa0</span><span class=\"s1\">&#39;</span><span class=\"p\">,</span> <span class=\"sa\">u</span><span class=\"s1\">&#39; &#39;</span><span class=\"p\">)</span>\n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s1\">&#39;</span><span class=\"si\">{}</span><span class=\"s1\"> 回答：</span><span class=\"si\">{}</span><span class=\"s1\">&#39;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">SLUG</span><span class=\"p\">,</span> <span class=\"n\">result</span><span class=\"p\">))</span>\n            <span class=\"k\">return</span> <span class=\"n\">result</span>\n        <span class=\"k\">except</span> <span class=\"ne\">Exception</span><span class=\"p\">:</span>\n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">critical</span><span class=\"p\">(</span><span class=\"s2\">&quot;Tuling robot failed to responsed for </span><span class=\"si\">%r</span><span class=\"s2\">&quot;</span><span class=\"p\">,</span>\n                                  <span class=\"n\">msg</span><span class=\"p\">,</span> <span class=\"n\">exc_info</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">)</span>            \n            <span class=\"k\">return</span> <span class=\"s2\">&quot;抱歉, 我的大脑短路了，请稍后再试试.&quot;</span></div></div>\n\n\n<div class=\"viewcode-block\" id=\"Emotibot\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.AI.Emotibot\">[文档]</a><span class=\"k\">class</span> <span class=\"nc\">Emotibot</span><span class=\"p\">(</span><span class=\"n\">AbstractRobot</span><span class=\"p\">):</span>\n\n    <span class=\"n\">SLUG</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;emotibot&quot;</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">appid</span><span class=\"p\">,</span> <span class=\"n\">location</span><span class=\"p\">,</span> <span class=\"n\">more</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Emotibot机器人</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"nb\">super</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"vm\">__class__</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">)</span><span class=\"o\">.</span><span class=\"fm\">__init__</span><span class=\"p\">()</span>        \n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">appid</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">location</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">more</span> <span class=\"o\">=</span> <span class=\"n\">appid</span><span class=\"p\">,</span> <span class=\"n\">location</span><span class=\"p\">,</span> <span class=\"n\">more</span>\n\n<div class=\"viewcode-block\" id=\"Emotibot.get_config\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.AI.Emotibot.get_config\">[文档]</a>    <span class=\"nd\">@classmethod</span>\n    <span class=\"k\">def</span> <span class=\"nf\">get_config</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"n\">appid</span> <span class=\"o\">=</span> <span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;/emotibot/appid&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;&#39;</span><span class=\"p\">)</span>\n        <span class=\"n\">location</span> <span class=\"o\">=</span> <span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;location&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;深圳&#39;</span><span class=\"p\">)</span>\n        <span class=\"n\">more</span> <span class=\"o\">=</span> <span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;active_mode&#39;</span><span class=\"p\">,</span> <span class=\"kc\">False</span><span class=\"p\">)</span>        \n        <span class=\"k\">return</span> <span class=\"p\">{</span>\n            <span class=\"s1\">&#39;appid&#39;</span><span class=\"p\">:</span> <span class=\"n\">appid</span><span class=\"p\">,</span>\n            <span class=\"s1\">&#39;location&#39;</span><span class=\"p\">:</span> <span class=\"n\">location</span><span class=\"p\">,</span>\n            <span class=\"s1\">&#39;more&#39;</span><span class=\"p\">:</span> <span class=\"n\">more</span>\n        <span class=\"p\">}</span></div>\n\n<div class=\"viewcode-block\" id=\"Emotibot.chat\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.AI.Emotibot.chat\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">chat</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">texts</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        使用Emotibot机器人聊天</span>\n\n<span class=\"sd\">        Arguments:</span>\n<span class=\"sd\">        texts -- user input, typically speech, to be parsed by a module</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"n\">msg</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;&#39;</span><span class=\"o\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">texts</span><span class=\"p\">)</span>\n        <span class=\"k\">try</span><span class=\"p\">:</span>\n            <span class=\"n\">url</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;http://idc.emotibot.com/api/ApiKey/openapi.php&quot;</span>\n            <span class=\"n\">userid</span> <span class=\"o\">=</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">get_mac</span><span class=\"p\">())[:</span><span class=\"mi\">32</span><span class=\"p\">]</span>\n            <span class=\"n\">register_data</span> <span class=\"o\">=</span> <span class=\"p\">{</span>\n                <span class=\"s2\">&quot;cmd&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;chat&quot;</span><span class=\"p\">,</span>\n                <span class=\"s2\">&quot;appid&quot;</span><span class=\"p\">:</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">appid</span><span class=\"p\">,</span>\n                <span class=\"s2\">&quot;userid&quot;</span><span class=\"p\">:</span> <span class=\"n\">userid</span><span class=\"p\">,</span>\n                <span class=\"s2\">&quot;text&quot;</span><span class=\"p\">:</span> <span class=\"n\">msg</span><span class=\"p\">,</span>\n                <span class=\"s2\">&quot;location&quot;</span><span class=\"p\">:</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">location</span>\n            <span class=\"p\">}</span>\n            <span class=\"n\">r</span> <span class=\"o\">=</span> <span class=\"n\">requests</span><span class=\"o\">.</span><span class=\"n\">post</span><span class=\"p\">(</span><span class=\"n\">url</span><span class=\"p\">,</span> <span class=\"n\">params</span><span class=\"o\">=</span><span class=\"n\">register_data</span><span class=\"p\">)</span>\n            <span class=\"n\">jsondata</span> <span class=\"o\">=</span> <span class=\"n\">json</span><span class=\"o\">.</span><span class=\"n\">loads</span><span class=\"p\">(</span><span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">text</span><span class=\"p\">)</span>\n            <span class=\"n\">result</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;&#39;</span>\n            <span class=\"n\">responds</span> <span class=\"o\">=</span> <span class=\"p\">[]</span>\n            <span class=\"k\">if</span> <span class=\"n\">jsondata</span><span class=\"p\">[</span><span class=\"s1\">&#39;return&#39;</span><span class=\"p\">]</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n                <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">more</span><span class=\"p\">:</span>\n                    <span class=\"n\">datas</span> <span class=\"o\">=</span> <span class=\"n\">jsondata</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;data&#39;</span><span class=\"p\">)</span>\n                    <span class=\"k\">for</span> <span class=\"n\">data</span> <span class=\"ow\">in</span> <span class=\"n\">datas</span><span class=\"p\">:</span>\n                        <span class=\"k\">if</span> <span class=\"n\">data</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;type&#39;</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"s1\">&#39;text&#39;</span><span class=\"p\">:</span>\n                            <span class=\"n\">responds</span><span class=\"o\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">data</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;value&#39;</span><span class=\"p\">))</span>\n                <span class=\"k\">else</span><span class=\"p\">:</span>\n                    <span class=\"n\">responds</span><span class=\"o\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">jsondata</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;data&#39;</span><span class=\"p\">)[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;value&#39;</span><span class=\"p\">))</span>\n                <span class=\"n\">result</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;</span><span class=\"se\">\\n</span><span class=\"s1\">&#39;</span><span class=\"o\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">responds</span><span class=\"p\">)</span>\n            <span class=\"k\">else</span><span class=\"p\">:</span>\n                <span class=\"n\">result</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;抱歉, 我的大脑短路了，请稍后再试试.&quot;</span>\n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s1\">&#39;</span><span class=\"si\">{}</span><span class=\"s1\"> 回答：</span><span class=\"si\">{}</span><span class=\"s1\">&#39;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">SLUG</span><span class=\"p\">,</span> <span class=\"n\">result</span><span class=\"p\">))</span>            \n            <span class=\"k\">return</span> <span class=\"n\">result</span>\n        <span class=\"k\">except</span> <span class=\"ne\">Exception</span><span class=\"p\">:</span>\n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">critical</span><span class=\"p\">(</span><span class=\"s2\">&quot;Emotibot failed to responsed for </span><span class=\"si\">%r</span><span class=\"s2\">&quot;</span><span class=\"p\">,</span>\n                                  <span class=\"n\">msg</span><span class=\"p\">,</span> <span class=\"n\">exc_info</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">)</span>\n            <span class=\"k\">return</span> <span class=\"s2\">&quot;抱歉, 我的大脑短路了，请稍后再试试.&quot;</span></div></div>\n\n\n\n\n<div class=\"viewcode-block\" id=\"get_robot_by_slug\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.AI.get_robot_by_slug\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">get_robot_by_slug</span><span class=\"p\">(</span><span class=\"n\">slug</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    Returns:</span>\n<span class=\"sd\">        A robot implementation available on the current platform</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">slug</span> <span class=\"ow\">or</span> <span class=\"nb\">type</span><span class=\"p\">(</span><span class=\"n\">slug</span><span class=\"p\">)</span> <span class=\"ow\">is</span> <span class=\"ow\">not</span> <span class=\"nb\">str</span><span class=\"p\">:</span>\n        <span class=\"k\">raise</span> <span class=\"ne\">TypeError</span><span class=\"p\">(</span><span class=\"s2\">&quot;Invalid slug &#39;</span><span class=\"si\">%s</span><span class=\"s2\">&#39;&quot;</span><span class=\"p\">,</span> <span class=\"n\">slug</span><span class=\"p\">)</span>\n\n    <span class=\"n\">selected_robots</span> <span class=\"o\">=</span> <span class=\"nb\">list</span><span class=\"p\">(</span><span class=\"nb\">filter</span><span class=\"p\">(</span><span class=\"k\">lambda</span> <span class=\"n\">robot</span><span class=\"p\">:</span> <span class=\"nb\">hasattr</span><span class=\"p\">(</span><span class=\"n\">robot</span><span class=\"p\">,</span> <span class=\"s2\">&quot;SLUG&quot;</span><span class=\"p\">)</span> <span class=\"ow\">and</span>\n                             <span class=\"n\">robot</span><span class=\"o\">.</span><span class=\"n\">SLUG</span> <span class=\"o\">==</span> <span class=\"n\">slug</span><span class=\"p\">,</span> <span class=\"n\">get_robots</span><span class=\"p\">()))</span>\n    <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">selected_robots</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"k\">raise</span> <span class=\"ne\">ValueError</span><span class=\"p\">(</span><span class=\"s2\">&quot;No robot found for slug &#39;</span><span class=\"si\">%s</span><span class=\"s2\">&#39;&quot;</span> <span class=\"o\">%</span> <span class=\"n\">slug</span><span class=\"p\">)</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">selected_robots</span><span class=\"p\">)</span> <span class=\"o\">&gt;</span> <span class=\"mi\">1</span><span class=\"p\">:</span>\n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">warning</span><span class=\"p\">(</span><span class=\"s2\">&quot;WARNING: Multiple robots found for slug &#39;</span><span class=\"si\">%s</span><span class=\"s2\">&#39;. &quot;</span> <span class=\"o\">+</span>\n                  <span class=\"s2\">&quot;This is most certainly a bug.&quot;</span> <span class=\"o\">%</span> <span class=\"n\">slug</span><span class=\"p\">)</span>        \n        <span class=\"n\">robot</span> <span class=\"o\">=</span> <span class=\"n\">selected_robots</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n        <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s2\">&quot;使用 </span><span class=\"si\">{}</span><span class=\"s2\"> 对话机器人&quot;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">robot</span><span class=\"o\">.</span><span class=\"n\">SLUG</span><span class=\"p\">))</span>\n        <span class=\"k\">return</span> <span class=\"n\">robot</span><span class=\"o\">.</span><span class=\"n\">get_instance</span><span class=\"p\">()</span></div>\n\n\n<div class=\"viewcode-block\" id=\"get_robots\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.AI.get_robots\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">get_robots</span><span class=\"p\">():</span>\n    <span class=\"k\">def</span> <span class=\"nf\">get_subclasses</span><span class=\"p\">(</span><span class=\"bp\">cls</span><span class=\"p\">):</span>\n        <span class=\"n\">subclasses</span> <span class=\"o\">=</span> <span class=\"nb\">set</span><span class=\"p\">()</span>\n        <span class=\"k\">for</span> <span class=\"n\">subclass</span> <span class=\"ow\">in</span> <span class=\"bp\">cls</span><span class=\"o\">.</span><span class=\"n\">__subclasses__</span><span class=\"p\">():</span>\n            <span class=\"n\">subclasses</span><span class=\"o\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">subclass</span><span class=\"p\">)</span>\n            <span class=\"n\">subclasses</span><span class=\"o\">.</span><span class=\"n\">update</span><span class=\"p\">(</span><span class=\"n\">get_subclasses</span><span class=\"p\">(</span><span class=\"n\">subclass</span><span class=\"p\">))</span>\n        <span class=\"k\">return</span> <span class=\"n\">subclasses</span>\n    <span class=\"k\">return</span> <span class=\"p\">[</span><span class=\"n\">robot</span> <span class=\"k\">for</span> <span class=\"n\">robot</span> <span class=\"ow\">in</span>\n            <span class=\"nb\">list</span><span class=\"p\">(</span><span class=\"n\">get_subclasses</span><span class=\"p\">(</span><span class=\"n\">AbstractRobot</span><span class=\"p\">))</span>\n            <span class=\"k\">if</span> <span class=\"nb\">hasattr</span><span class=\"p\">(</span><span class=\"n\">robot</span><span class=\"p\">,</span> <span class=\"s1\">&#39;SLUG&#39;</span><span class=\"p\">)</span> <span class=\"ow\">and</span> <span class=\"n\">robot</span><span class=\"o\">.</span><span class=\"n\">SLUG</span><span class=\"p\">]</span></div>\n</pre></div>\n\n           </div>\n           \n          </div>\n          <footer>\n  \n\n  <hr/>\n\n  <div role=\"contentinfo\">\n    <p>\n        &copy; Copyright 2019, wzpan\n\n    </p>\n  </div>\n  Built with <a href=\"http://sphinx-doc.org/\">Sphinx</a> using a <a href=\"https://github.com/rtfd/sphinx_rtd_theme\">theme</a> provided by <a href=\"https://readthedocs.org\">Read the Docs</a>. \n\n</footer>\n\n        </div>\n      </div>\n\n    </section>\n\n  </div>\n  \n\n\n  <script type=\"text/javascript\">\n      jQuery(function () {\n          SphinxRtdTheme.Navigation.enable(true);\n      });\n  </script>\n\n  \n  \n    \n   \n\n</body>\n</html>"
  },
  {
    "path": "docs/_modules/robot/ASR.html",
    "content": "\n\n<!DOCTYPE html>\n<!--[if IE 8]><html class=\"no-js lt-ie9\" lang=\"zh-CN\" > <![endif]-->\n<!--[if gt IE 8]><!--> <html class=\"no-js\" lang=\"zh-CN\" > <!--<![endif]-->\n<head>\n  <meta charset=\"utf-8\">\n  \n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  \n  <title>robot.ASR &mdash; wukong-robot 1.2.0 文档</title>\n  \n\n  \n  \n  \n  \n\n  \n  <script type=\"text/javascript\" src=\"../../_static/js/modernizr.min.js\"></script>\n  \n    \n      <script type=\"text/javascript\" id=\"documentation_options\" data-url_root=\"../../\" src=\"../../_static/documentation_options.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/jquery.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/underscore.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/doctools.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/language_data.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/translations.js\"></script>\n    \n    <script type=\"text/javascript\" src=\"../../_static/js/theme.js\"></script>\n\n    \n\n  \n  <link rel=\"stylesheet\" href=\"../../_static/css/theme.css\" type=\"text/css\" />\n  <link rel=\"stylesheet\" href=\"../../_static/pygments.css\" type=\"text/css\" />\n    <link rel=\"index\" title=\"索引\" href=\"../../genindex.html\" />\n    <link rel=\"search\" title=\"搜索\" href=\"../../search.html\" /> \n</head>\n\n<body class=\"wy-body-for-nav\">\n\n   \n  <div class=\"wy-grid-for-nav\">\n    \n    <nav data-toggle=\"wy-nav-shift\" class=\"wy-nav-side\">\n      <div class=\"wy-side-scroll\">\n        <div class=\"wy-side-nav-search\" >\n          \n\n          \n            <a href=\"../../index.html\" class=\"icon icon-home\"> wukong-robot\n          \n\n          \n          </a>\n\n          \n            \n            \n          \n\n          \n<div role=\"search\">\n  <form id=\"rtd-search-form\" class=\"wy-form\" action=\"../../search.html\" method=\"get\">\n    <input type=\"text\" name=\"q\" placeholder=\"Search docs\" />\n    <input type=\"hidden\" name=\"check_keywords\" value=\"yes\" />\n    <input type=\"hidden\" name=\"area\" value=\"default\" />\n  </form>\n</div>\n\n          \n        </div>\n\n        <div class=\"wy-menu wy-menu-vertical\" data-spy=\"affix\" role=\"navigation\" aria-label=\"main navigation\">\n          \n            \n            \n              \n            \n            \n              <!-- Local TOC -->\n              <div class=\"local-toc\"></div>\n            \n          \n        </div>\n      </div>\n    </nav>\n\n    <section data-toggle=\"wy-nav-shift\" class=\"wy-nav-content-wrap\">\n\n      \n      <nav class=\"wy-nav-top\" aria-label=\"top navigation\">\n        \n          <i data-toggle=\"wy-nav-top\" class=\"fa fa-bars\"></i>\n          <a href=\"../../index.html\">wukong-robot</a>\n        \n      </nav>\n\n\n      <div class=\"wy-nav-content\">\n        \n        <div class=\"rst-content\">\n        \n          \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<div role=\"navigation\" aria-label=\"breadcrumbs navigation\">\n\n  <ul class=\"wy-breadcrumbs\">\n    \n      <li><a href=\"../../index.html\">Docs</a> &raquo;</li>\n        \n          <li><a href=\"../index.html\">模块代码</a> &raquo;</li>\n        \n      <li>robot.ASR</li>\n    \n    \n      <li class=\"wy-breadcrumbs-aside\">\n        \n      </li>\n    \n  </ul>\n\n  \n  <hr/>\n</div>\n          <div role=\"main\" class=\"document\" itemscope=\"itemscope\" itemtype=\"http://schema.org/Article\">\n           <div itemprop=\"articleBody\">\n            \n  <h1>robot.ASR 源代码</h1><div class=\"highlight\"><pre>\n<span></span><span class=\"c1\"># -*- coding: utf-8-*-</span>\n<span class=\"kn\">import</span> <span class=\"nn\">json</span>\n<span class=\"kn\">from</span> <span class=\"nn\">aip</span> <span class=\"k\">import</span> <span class=\"n\">AipSpeech</span>\n<span class=\"kn\">from</span> <span class=\"nn\">.sdk</span> <span class=\"k\">import</span> <span class=\"n\">TencentSpeech</span><span class=\"p\">,</span> <span class=\"n\">AliSpeech</span><span class=\"p\">,</span> <span class=\"n\">XunfeiSpeech</span>\n<span class=\"kn\">from</span> <span class=\"nn\">.</span> <span class=\"k\">import</span> <span class=\"n\">utils</span><span class=\"p\">,</span> <span class=\"n\">config</span>\n<span class=\"kn\">from</span> <span class=\"nn\">robot</span> <span class=\"k\">import</span> <span class=\"n\">logging</span>\n<span class=\"kn\">from</span> <span class=\"nn\">abc</span> <span class=\"k\">import</span> <span class=\"n\">ABCMeta</span><span class=\"p\">,</span> <span class=\"n\">abstractmethod</span>\n\n<span class=\"n\">logger</span> <span class=\"o\">=</span> <span class=\"n\">logging</span><span class=\"o\">.</span><span class=\"n\">getLogger</span><span class=\"p\">(</span><span class=\"vm\">__name__</span><span class=\"p\">)</span>\n\n<div class=\"viewcode-block\" id=\"AbstractASR\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.ASR.AbstractASR\">[文档]</a><span class=\"k\">class</span> <span class=\"nc\">AbstractASR</span><span class=\"p\">(</span><span class=\"nb\">object</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    Generic parent class for all ASR engines</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n\n    <span class=\"n\">__metaclass__</span> <span class=\"o\">=</span> <span class=\"n\">ABCMeta</span>\n\n<div class=\"viewcode-block\" id=\"AbstractASR.get_config\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.ASR.AbstractASR.get_config\">[文档]</a>    <span class=\"nd\">@classmethod</span>\n    <span class=\"k\">def</span> <span class=\"nf\">get_config</span><span class=\"p\">(</span><span class=\"bp\">cls</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"p\">{}</span></div>\n\n<div class=\"viewcode-block\" id=\"AbstractASR.get_instance\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.ASR.AbstractASR.get_instance\">[文档]</a>    <span class=\"nd\">@classmethod</span>\n    <span class=\"k\">def</span> <span class=\"nf\">get_instance</span><span class=\"p\">(</span><span class=\"bp\">cls</span><span class=\"p\">):</span>\n        <span class=\"n\">profile</span> <span class=\"o\">=</span> <span class=\"bp\">cls</span><span class=\"o\">.</span><span class=\"n\">get_config</span><span class=\"p\">()</span>\n        <span class=\"n\">instance</span> <span class=\"o\">=</span> <span class=\"bp\">cls</span><span class=\"p\">(</span><span class=\"o\">**</span><span class=\"n\">profile</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span> <span class=\"n\">instance</span></div>\n\n<div class=\"viewcode-block\" id=\"AbstractASR.transcribe\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.ASR.AbstractASR.transcribe\">[文档]</a>    <span class=\"nd\">@abstractmethod</span>\n    <span class=\"k\">def</span> <span class=\"nf\">transcribe</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">fp</span><span class=\"p\">):</span>\n        <span class=\"k\">pass</span></div></div>\n\n\n<div class=\"viewcode-block\" id=\"BaiduASR\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.ASR.BaiduASR\">[文档]</a><span class=\"k\">class</span> <span class=\"nc\">BaiduASR</span><span class=\"p\">(</span><span class=\"n\">AbstractASR</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    百度的语音识别API.</span>\n<span class=\"sd\">    dev_pid:</span>\n<span class=\"sd\">        - 1936: 普通话远场</span>\n<span class=\"sd\">        - 1536：普通话(支持简单的英文识别)</span>\n<span class=\"sd\">        - 1537：普通话(纯中文识别)</span>\n<span class=\"sd\">        - 1737：英语</span>\n<span class=\"sd\">        - 1637：粤语</span>\n<span class=\"sd\">        - 1837：四川话</span>\n<span class=\"sd\">    要使用本模块, 首先到 yuyin.baidu.com 注册一个开发者账号,</span>\n<span class=\"sd\">    之后创建一个新应用, 然后在应用管理的&quot;查看key&quot;中获得 API Key 和 Secret Key</span>\n<span class=\"sd\">    填入 config.xml 中.</span>\n<span class=\"sd\">    ...</span>\n<span class=\"sd\">        baidu_yuyin: </span>\n<span class=\"sd\">            appid: &#39;9670645&#39;</span>\n<span class=\"sd\">            api_key: &#39;qg4haN8b2bGvFtCbBGqhrmZy&#39;</span>\n<span class=\"sd\">            secret_key: &#39;585d4eccb50d306c401d7df138bb02e7&#39;</span>\n<span class=\"sd\">        ...</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n\n    <span class=\"n\">SLUG</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;baidu-asr&quot;</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">appid</span><span class=\"p\">,</span> <span class=\"n\">api_key</span><span class=\"p\">,</span> <span class=\"n\">secret_key</span><span class=\"p\">,</span> <span class=\"n\">dev_pid</span><span class=\"o\">=</span><span class=\"mi\">1936</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">args</span><span class=\"p\">):</span>\n        <span class=\"nb\">super</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"vm\">__class__</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">)</span><span class=\"o\">.</span><span class=\"fm\">__init__</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">client</span> <span class=\"o\">=</span> <span class=\"n\">AipSpeech</span><span class=\"p\">(</span><span class=\"n\">appid</span><span class=\"p\">,</span> <span class=\"n\">api_key</span><span class=\"p\">,</span> <span class=\"n\">secret_key</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">dev_pid</span> <span class=\"o\">=</span> <span class=\"n\">dev_pid</span>\n\n<div class=\"viewcode-block\" id=\"BaiduASR.get_config\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.ASR.BaiduASR.get_config\">[文档]</a>    <span class=\"nd\">@classmethod</span>\n    <span class=\"k\">def</span> <span class=\"nf\">get_config</span><span class=\"p\">(</span><span class=\"bp\">cls</span><span class=\"p\">):</span>\n        <span class=\"c1\"># Try to get baidu_yuyin config from config</span>\n        <span class=\"k\">return</span> <span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;baidu_yuyin&#39;</span><span class=\"p\">,</span> <span class=\"p\">{})</span></div>\n\n<div class=\"viewcode-block\" id=\"BaiduASR.transcribe\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.ASR.BaiduASR.transcribe\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">transcribe</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">fp</span><span class=\"p\">):</span>\n        <span class=\"c1\"># 识别本地文件</span>\n        <span class=\"n\">pcm</span> <span class=\"o\">=</span> <span class=\"n\">utils</span><span class=\"o\">.</span><span class=\"n\">get_pcm_from_wav</span><span class=\"p\">(</span><span class=\"n\">fp</span><span class=\"p\">)</span>\n        <span class=\"n\">res</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">client</span><span class=\"o\">.</span><span class=\"n\">asr</span><span class=\"p\">(</span><span class=\"n\">pcm</span><span class=\"p\">,</span> <span class=\"s1\">&#39;pcm&#39;</span><span class=\"p\">,</span> <span class=\"mi\">16000</span><span class=\"p\">,</span> <span class=\"p\">{</span>\n            <span class=\"s1\">&#39;dev_pid&#39;</span><span class=\"p\">:</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">dev_pid</span><span class=\"p\">,</span>\n        <span class=\"p\">})</span>\n        <span class=\"k\">if</span> <span class=\"n\">res</span><span class=\"p\">[</span><span class=\"s1\">&#39;err_no&#39;</span><span class=\"p\">]</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s1\">&#39;</span><span class=\"si\">{}</span><span class=\"s1\"> 语音识别到了：</span><span class=\"si\">{}</span><span class=\"s1\">&#39;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">SLUG</span><span class=\"p\">,</span> <span class=\"n\">res</span><span class=\"p\">[</span><span class=\"s1\">&#39;result&#39;</span><span class=\"p\">]))</span>\n            <span class=\"k\">return</span> <span class=\"s1\">&#39;&#39;</span><span class=\"o\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">res</span><span class=\"p\">[</span><span class=\"s1\">&#39;result&#39;</span><span class=\"p\">])</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s1\">&#39;</span><span class=\"si\">{}</span><span class=\"s1\"> 语音识别出错了: </span><span class=\"si\">{}</span><span class=\"s1\">&#39;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">SLUG</span><span class=\"p\">,</span> <span class=\"n\">res</span><span class=\"p\">[</span><span class=\"s1\">&#39;err_msg&#39;</span><span class=\"p\">]))</span>\n            <span class=\"k\">return</span> <span class=\"s1\">&#39;&#39;</span></div></div>\n\n\n<div class=\"viewcode-block\" id=\"TencentASR\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.ASR.TencentASR\">[文档]</a><span class=\"k\">class</span> <span class=\"nc\">TencentASR</span><span class=\"p\">(</span><span class=\"n\">AbstractASR</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    腾讯的语音识别API.</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n\n    <span class=\"n\">SLUG</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;tencent-asr&quot;</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">appid</span><span class=\"p\">,</span> <span class=\"n\">secretid</span><span class=\"p\">,</span> <span class=\"n\">secret_key</span><span class=\"p\">,</span> <span class=\"n\">region</span><span class=\"o\">=</span><span class=\"s1\">&#39;ap-guangzhou&#39;</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">args</span><span class=\"p\">):</span>\n        <span class=\"nb\">super</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"vm\">__class__</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">)</span><span class=\"o\">.</span><span class=\"fm\">__init__</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">engine</span> <span class=\"o\">=</span> <span class=\"n\">TencentSpeech</span><span class=\"o\">.</span><span class=\"n\">tencentSpeech</span><span class=\"p\">(</span><span class=\"n\">secret_key</span><span class=\"p\">,</span> <span class=\"n\">secretid</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">region</span> <span class=\"o\">=</span> <span class=\"n\">region</span>\n\n<div class=\"viewcode-block\" id=\"TencentASR.get_config\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.ASR.TencentASR.get_config\">[文档]</a>    <span class=\"nd\">@classmethod</span>\n    <span class=\"k\">def</span> <span class=\"nf\">get_config</span><span class=\"p\">(</span><span class=\"bp\">cls</span><span class=\"p\">):</span>\n        <span class=\"c1\"># Try to get tencent_yuyin config from config</span>\n        <span class=\"k\">return</span> <span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;tencent_yuyin&#39;</span><span class=\"p\">,</span> <span class=\"p\">{})</span></div>\n\n<div class=\"viewcode-block\" id=\"TencentASR.transcribe\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.ASR.TencentASR.transcribe\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">transcribe</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">fp</span><span class=\"p\">):</span>\n        <span class=\"n\">mp3_path</span> <span class=\"o\">=</span> <span class=\"n\">utils</span><span class=\"o\">.</span><span class=\"n\">convert_wav_to_mp3</span><span class=\"p\">(</span><span class=\"n\">fp</span><span class=\"p\">)</span>\n        <span class=\"n\">r</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">engine</span><span class=\"o\">.</span><span class=\"n\">ASR</span><span class=\"p\">(</span><span class=\"n\">mp3_path</span><span class=\"p\">,</span> <span class=\"s1\">&#39;mp3&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;1&#39;</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">region</span><span class=\"p\">)</span>\n        <span class=\"n\">utils</span><span class=\"o\">.</span><span class=\"n\">check_and_delete</span><span class=\"p\">(</span><span class=\"n\">mp3_path</span><span class=\"p\">)</span>\n        <span class=\"n\">res</span> <span class=\"o\">=</span> <span class=\"n\">json</span><span class=\"o\">.</span><span class=\"n\">loads</span><span class=\"p\">(</span><span class=\"n\">r</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"s1\">&#39;Response&#39;</span> <span class=\"ow\">in</span> <span class=\"n\">res</span> <span class=\"ow\">and</span> <span class=\"s1\">&#39;Result&#39;</span> <span class=\"ow\">in</span> <span class=\"n\">res</span><span class=\"p\">[</span><span class=\"s1\">&#39;Response&#39;</span><span class=\"p\">]:</span>\n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s1\">&#39;</span><span class=\"si\">{}</span><span class=\"s1\"> 语音识别到了：</span><span class=\"si\">{}</span><span class=\"s1\">&#39;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">SLUG</span><span class=\"p\">,</span> <span class=\"n\">res</span><span class=\"p\">[</span><span class=\"s1\">&#39;Response&#39;</span><span class=\"p\">][</span><span class=\"s1\">&#39;Result&#39;</span><span class=\"p\">]))</span>\n            <span class=\"k\">return</span> <span class=\"n\">res</span><span class=\"p\">[</span><span class=\"s1\">&#39;Response&#39;</span><span class=\"p\">][</span><span class=\"s1\">&#39;Result&#39;</span><span class=\"p\">]</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">critical</span><span class=\"p\">(</span><span class=\"s1\">&#39;</span><span class=\"si\">{}</span><span class=\"s1\"> 语音识别出错了&#39;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">SLUG</span><span class=\"p\">),</span> <span class=\"n\">exc_info</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">)</span>\n            <span class=\"k\">return</span> <span class=\"s1\">&#39;&#39;</span></div></div>\n\n\n<div class=\"viewcode-block\" id=\"XunfeiASR\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.ASR.XunfeiASR\">[文档]</a><span class=\"k\">class</span> <span class=\"nc\">XunfeiASR</span><span class=\"p\">(</span><span class=\"n\">AbstractASR</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    科大讯飞的语音识别API.</span>\n<span class=\"sd\">    外网ip查询：https://ip.51240.com/</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n\n    <span class=\"n\">SLUG</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;xunfei-asr&quot;</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">appid</span><span class=\"p\">,</span> <span class=\"n\">asr_api_key</span><span class=\"p\">,</span> <span class=\"n\">asr_api_secret</span><span class=\"p\">,</span> <span class=\"n\">tts_api_key</span><span class=\"p\">,</span> <span class=\"n\">voice</span><span class=\"o\">=</span><span class=\"s1\">&#39;xiaoyan&#39;</span><span class=\"p\">):</span>\n        <span class=\"nb\">super</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"vm\">__class__</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">)</span><span class=\"o\">.</span><span class=\"fm\">__init__</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">appid</span> <span class=\"o\">=</span> <span class=\"n\">appid</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">api_key</span> <span class=\"o\">=</span> <span class=\"n\">asr_api_key</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">api_secret</span> <span class=\"o\">=</span> <span class=\"n\">asr_api_secret</span>\n\n<div class=\"viewcode-block\" id=\"XunfeiASR.get_config\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.ASR.XunfeiASR.get_config\">[文档]</a>    <span class=\"nd\">@classmethod</span>\n    <span class=\"k\">def</span> <span class=\"nf\">get_config</span><span class=\"p\">(</span><span class=\"bp\">cls</span><span class=\"p\">):</span>\n        <span class=\"c1\"># Try to get xunfei_yuyin config from config</span>\n        <span class=\"k\">return</span> <span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;xunfei_yuyin&#39;</span><span class=\"p\">,</span> <span class=\"p\">{})</span></div>\n\n<div class=\"viewcode-block\" id=\"XunfeiASR.transcribe\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.ASR.XunfeiASR.transcribe\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">transcribe</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">fp</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"n\">XunfeiSpeech</span><span class=\"o\">.</span><span class=\"n\">transcribe</span><span class=\"p\">(</span><span class=\"n\">fp</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">appid</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">api_key</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">api_secret</span><span class=\"p\">)</span></div></div>\n\n\n<div class=\"viewcode-block\" id=\"AliASR\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.ASR.AliASR\">[文档]</a><span class=\"k\">class</span> <span class=\"nc\">AliASR</span><span class=\"p\">(</span><span class=\"n\">AbstractASR</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    阿里的语音识别API.</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n\n    <span class=\"n\">SLUG</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;ali-asr&quot;</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">appKey</span><span class=\"p\">,</span> <span class=\"n\">token</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">args</span><span class=\"p\">):</span>\n        <span class=\"nb\">super</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"vm\">__class__</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">)</span><span class=\"o\">.</span><span class=\"fm\">__init__</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">appKey</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">token</span> <span class=\"o\">=</span> <span class=\"n\">appKey</span><span class=\"p\">,</span> <span class=\"n\">token</span>\n\n<div class=\"viewcode-block\" id=\"AliASR.get_config\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.ASR.AliASR.get_config\">[文档]</a>    <span class=\"nd\">@classmethod</span>\n    <span class=\"k\">def</span> <span class=\"nf\">get_config</span><span class=\"p\">(</span><span class=\"bp\">cls</span><span class=\"p\">):</span>\n        <span class=\"c1\"># Try to get ali_yuyin config from config</span>\n        <span class=\"k\">return</span> <span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;ali_yuyin&#39;</span><span class=\"p\">,</span> <span class=\"p\">{})</span></div>\n\n<div class=\"viewcode-block\" id=\"AliASR.transcribe\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.ASR.AliASR.transcribe\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">transcribe</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">fp</span><span class=\"p\">):</span>\n        <span class=\"n\">result</span> <span class=\"o\">=</span> <span class=\"n\">AliSpeech</span><span class=\"o\">.</span><span class=\"n\">asr</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">appKey</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">token</span><span class=\"p\">,</span> <span class=\"n\">fp</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">result</span> <span class=\"ow\">is</span> <span class=\"ow\">not</span> <span class=\"kc\">None</span><span class=\"p\">:</span>\n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s1\">&#39;</span><span class=\"si\">{}</span><span class=\"s1\"> 语音识别到了：</span><span class=\"si\">{}</span><span class=\"s1\">&#39;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">SLUG</span><span class=\"p\">,</span> <span class=\"n\">result</span><span class=\"p\">))</span>\n            <span class=\"k\">return</span> <span class=\"n\">result</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">critical</span><span class=\"p\">(</span><span class=\"s1\">&#39;</span><span class=\"si\">{}</span><span class=\"s1\"> 语音识别出错了&#39;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">SLUG</span><span class=\"p\">),</span> <span class=\"n\">exc_info</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">)</span>\n            <span class=\"k\">return</span> <span class=\"s1\">&#39;&#39;</span></div></div>\n\n\n<div class=\"viewcode-block\" id=\"get_engine_by_slug\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.ASR.get_engine_by_slug\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">get_engine_by_slug</span><span class=\"p\">(</span><span class=\"n\">slug</span><span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    Returns:</span>\n<span class=\"sd\">        An ASR Engine implementation available on the current platform</span>\n\n<span class=\"sd\">    Raises:</span>\n<span class=\"sd\">        ValueError if no speaker implementation is supported on this platform</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n\n    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">slug</span> <span class=\"ow\">or</span> <span class=\"nb\">type</span><span class=\"p\">(</span><span class=\"n\">slug</span><span class=\"p\">)</span> <span class=\"ow\">is</span> <span class=\"ow\">not</span> <span class=\"nb\">str</span><span class=\"p\">:</span>\n        <span class=\"k\">raise</span> <span class=\"ne\">TypeError</span><span class=\"p\">(</span><span class=\"s2\">&quot;无效的 ASR slug &#39;</span><span class=\"si\">%s</span><span class=\"s2\">&#39;&quot;</span><span class=\"p\">,</span> <span class=\"n\">slug</span><span class=\"p\">)</span>\n\n    <span class=\"n\">selected_engines</span> <span class=\"o\">=</span> <span class=\"nb\">list</span><span class=\"p\">(</span><span class=\"nb\">filter</span><span class=\"p\">(</span><span class=\"k\">lambda</span> <span class=\"n\">engine</span><span class=\"p\">:</span> <span class=\"nb\">hasattr</span><span class=\"p\">(</span><span class=\"n\">engine</span><span class=\"p\">,</span> <span class=\"s2\">&quot;SLUG&quot;</span><span class=\"p\">)</span> <span class=\"ow\">and</span>\n                              <span class=\"n\">engine</span><span class=\"o\">.</span><span class=\"n\">SLUG</span> <span class=\"o\">==</span> <span class=\"n\">slug</span><span class=\"p\">,</span> <span class=\"n\">get_engines</span><span class=\"p\">()))</span>\n\n    <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">selected_engines</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"k\">raise</span> <span class=\"ne\">ValueError</span><span class=\"p\">(</span><span class=\"s2\">&quot;错误：找不到名为 </span><span class=\"si\">{}</span><span class=\"s2\"> 的 ASR 引擎&quot;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">slug</span><span class=\"p\">))</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">selected_engines</span><span class=\"p\">)</span> <span class=\"o\">&gt;</span> <span class=\"mi\">1</span><span class=\"p\">:</span>\n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">warning</span><span class=\"p\">(</span><span class=\"s2\">&quot;注意: 有多个 ASR 名称与指定的引擎名 </span><span class=\"si\">{}</span><span class=\"s2\"> 匹配&quot;</span><span class=\"p\">)</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">slug</span><span class=\"p\">)</span>\n        <span class=\"n\">engine</span> <span class=\"o\">=</span> <span class=\"n\">selected_engines</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n        <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s2\">&quot;使用 </span><span class=\"si\">{}</span><span class=\"s2\"> ASR 引擎&quot;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">engine</span><span class=\"o\">.</span><span class=\"n\">SLUG</span><span class=\"p\">))</span>\n        <span class=\"k\">return</span> <span class=\"n\">engine</span><span class=\"o\">.</span><span class=\"n\">get_instance</span><span class=\"p\">()</span></div>\n\n\n<div class=\"viewcode-block\" id=\"get_engines\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.ASR.get_engines\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">get_engines</span><span class=\"p\">():</span>\n    <span class=\"k\">def</span> <span class=\"nf\">get_subclasses</span><span class=\"p\">(</span><span class=\"bp\">cls</span><span class=\"p\">):</span>\n        <span class=\"n\">subclasses</span> <span class=\"o\">=</span> <span class=\"nb\">set</span><span class=\"p\">()</span>\n        <span class=\"k\">for</span> <span class=\"n\">subclass</span> <span class=\"ow\">in</span> <span class=\"bp\">cls</span><span class=\"o\">.</span><span class=\"n\">__subclasses__</span><span class=\"p\">():</span>\n            <span class=\"n\">subclasses</span><span class=\"o\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">subclass</span><span class=\"p\">)</span>\n            <span class=\"n\">subclasses</span><span class=\"o\">.</span><span class=\"n\">update</span><span class=\"p\">(</span><span class=\"n\">get_subclasses</span><span class=\"p\">(</span><span class=\"n\">subclass</span><span class=\"p\">))</span>\n        <span class=\"k\">return</span> <span class=\"n\">subclasses</span>\n    <span class=\"k\">return</span> <span class=\"p\">[</span><span class=\"n\">engine</span> <span class=\"k\">for</span> <span class=\"n\">engine</span> <span class=\"ow\">in</span>\n            <span class=\"nb\">list</span><span class=\"p\">(</span><span class=\"n\">get_subclasses</span><span class=\"p\">(</span><span class=\"n\">AbstractASR</span><span class=\"p\">))</span>\n            <span class=\"k\">if</span> <span class=\"nb\">hasattr</span><span class=\"p\">(</span><span class=\"n\">engine</span><span class=\"p\">,</span> <span class=\"s1\">&#39;SLUG&#39;</span><span class=\"p\">)</span> <span class=\"ow\">and</span> <span class=\"n\">engine</span><span class=\"o\">.</span><span class=\"n\">SLUG</span><span class=\"p\">]</span></div>\n</pre></div>\n\n           </div>\n           \n          </div>\n          <footer>\n  \n\n  <hr/>\n\n  <div role=\"contentinfo\">\n    <p>\n        &copy; Copyright 2019, wzpan\n\n    </p>\n  </div>\n  Built with <a href=\"http://sphinx-doc.org/\">Sphinx</a> using a <a href=\"https://github.com/rtfd/sphinx_rtd_theme\">theme</a> provided by <a href=\"https://readthedocs.org\">Read the Docs</a>. \n\n</footer>\n\n        </div>\n      </div>\n\n    </section>\n\n  </div>\n  \n\n\n  <script type=\"text/javascript\">\n      jQuery(function () {\n          SphinxRtdTheme.Navigation.enable(true);\n      });\n  </script>\n\n  \n  \n    \n   \n\n</body>\n</html>"
  },
  {
    "path": "docs/_modules/robot/Brain.html",
    "content": "\n\n<!DOCTYPE html>\n<!--[if IE 8]><html class=\"no-js lt-ie9\" lang=\"zh-CN\" > <![endif]-->\n<!--[if gt IE 8]><!--> <html class=\"no-js\" lang=\"zh-CN\" > <!--<![endif]-->\n<head>\n  <meta charset=\"utf-8\">\n  \n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  \n  <title>robot.Brain &mdash; wukong-robot 1.2.0 文档</title>\n  \n\n  \n  \n  \n  \n\n  \n  <script type=\"text/javascript\" src=\"../../_static/js/modernizr.min.js\"></script>\n  \n    \n      <script type=\"text/javascript\" id=\"documentation_options\" data-url_root=\"../../\" src=\"../../_static/documentation_options.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/jquery.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/underscore.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/doctools.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/language_data.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/translations.js\"></script>\n    \n    <script type=\"text/javascript\" src=\"../../_static/js/theme.js\"></script>\n\n    \n\n  \n  <link rel=\"stylesheet\" href=\"../../_static/css/theme.css\" type=\"text/css\" />\n  <link rel=\"stylesheet\" href=\"../../_static/pygments.css\" type=\"text/css\" />\n    <link rel=\"index\" title=\"索引\" href=\"../../genindex.html\" />\n    <link rel=\"search\" title=\"搜索\" href=\"../../search.html\" /> \n</head>\n\n<body class=\"wy-body-for-nav\">\n\n   \n  <div class=\"wy-grid-for-nav\">\n    \n    <nav data-toggle=\"wy-nav-shift\" class=\"wy-nav-side\">\n      <div class=\"wy-side-scroll\">\n        <div class=\"wy-side-nav-search\" >\n          \n\n          \n            <a href=\"../../index.html\" class=\"icon icon-home\"> wukong-robot\n          \n\n          \n          </a>\n\n          \n            \n            \n          \n\n          \n<div role=\"search\">\n  <form id=\"rtd-search-form\" class=\"wy-form\" action=\"../../search.html\" method=\"get\">\n    <input type=\"text\" name=\"q\" placeholder=\"Search docs\" />\n    <input type=\"hidden\" name=\"check_keywords\" value=\"yes\" />\n    <input type=\"hidden\" name=\"area\" value=\"default\" />\n  </form>\n</div>\n\n          \n        </div>\n\n        <div class=\"wy-menu wy-menu-vertical\" data-spy=\"affix\" role=\"navigation\" aria-label=\"main navigation\">\n          \n            \n            \n              \n            \n            \n              <!-- Local TOC -->\n              <div class=\"local-toc\"></div>\n            \n          \n        </div>\n      </div>\n    </nav>\n\n    <section data-toggle=\"wy-nav-shift\" class=\"wy-nav-content-wrap\">\n\n      \n      <nav class=\"wy-nav-top\" aria-label=\"top navigation\">\n        \n          <i data-toggle=\"wy-nav-top\" class=\"fa fa-bars\"></i>\n          <a href=\"../../index.html\">wukong-robot</a>\n        \n      </nav>\n\n\n      <div class=\"wy-nav-content\">\n        \n        <div class=\"rst-content\">\n        \n          \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<div role=\"navigation\" aria-label=\"breadcrumbs navigation\">\n\n  <ul class=\"wy-breadcrumbs\">\n    \n      <li><a href=\"../../index.html\">Docs</a> &raquo;</li>\n        \n          <li><a href=\"../index.html\">模块代码</a> &raquo;</li>\n        \n      <li>robot.Brain</li>\n    \n    \n      <li class=\"wy-breadcrumbs-aside\">\n        \n      </li>\n    \n  </ul>\n\n  \n  <hr/>\n</div>\n          <div role=\"main\" class=\"document\" itemscope=\"itemscope\" itemtype=\"http://schema.org/Article\">\n           <div itemprop=\"articleBody\">\n            \n  <h1>robot.Brain 源代码</h1><div class=\"highlight\"><pre>\n<span></span><span class=\"c1\"># -*- coding: utf-8-*-</span>\n<span class=\"kn\">from</span> <span class=\"nn\">robot</span> <span class=\"k\">import</span> <span class=\"n\">logging</span>\n<span class=\"kn\">from</span> <span class=\"nn\">.</span> <span class=\"k\">import</span> <span class=\"n\">plugin_loader</span>\n\n<span class=\"n\">logger</span> <span class=\"o\">=</span> <span class=\"n\">logging</span><span class=\"o\">.</span><span class=\"n\">getLogger</span><span class=\"p\">(</span><span class=\"vm\">__name__</span><span class=\"p\">)</span>\n\n<div class=\"viewcode-block\" id=\"Brain\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.Brain.Brain\">[文档]</a><span class=\"k\">class</span> <span class=\"nc\">Brain</span><span class=\"p\">(</span><span class=\"nb\">object</span><span class=\"p\">):</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">conversation</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        大脑模块，负责处理技能的匹配和响应</span>\n\n<span class=\"sd\">        参数：</span>\n<span class=\"sd\">        conversation -- 管理对话</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">conversation</span> <span class=\"o\">=</span> <span class=\"n\">conversation</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">plugins</span> <span class=\"o\">=</span> <span class=\"n\">plugin_loader</span><span class=\"o\">.</span><span class=\"n\">get_plugins</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">conversation</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">handling</span> <span class=\"o\">=</span> <span class=\"kc\">False</span>\n\n<div class=\"viewcode-block\" id=\"Brain.isImmersive\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.Brain.Brain.isImmersive\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">isImmersive</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">plugin</span><span class=\"p\">,</span> <span class=\"n\">text</span><span class=\"p\">,</span> <span class=\"n\">parsed</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">conversation</span><span class=\"o\">.</span><span class=\"n\">getImmersiveMode</span><span class=\"p\">()</span> <span class=\"o\">==</span> <span class=\"n\">plugin</span><span class=\"o\">.</span><span class=\"n\">SLUG</span> <span class=\"ow\">and</span> \\\n            <span class=\"n\">plugin</span><span class=\"o\">.</span><span class=\"n\">isValidImmersive</span><span class=\"p\">(</span><span class=\"n\">text</span><span class=\"p\">,</span> <span class=\"n\">parsed</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"Brain.printPlugins\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.Brain.Brain.printPlugins\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">printPlugins</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"n\">plugin_list</span> <span class=\"o\">=</span> <span class=\"p\">[]</span>\n        <span class=\"k\">for</span> <span class=\"n\">plugin</span> <span class=\"ow\">in</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">plugins</span><span class=\"p\">:</span>\n            <span class=\"n\">plugin_list</span><span class=\"o\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">plugin</span><span class=\"o\">.</span><span class=\"n\">SLUG</span><span class=\"p\">)</span>\n        <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s1\">&#39;已激活插件：</span><span class=\"si\">{}</span><span class=\"s1\">&#39;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">plugin_list</span><span class=\"p\">))</span></div>\n\n<div class=\"viewcode-block\" id=\"Brain.query\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.Brain.Brain.query\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">query</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">text</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        query 模块</span>\n\n<span class=\"sd\">        Arguments:</span>\n<span class=\"sd\">        text -- 用户输入</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n\n        <span class=\"n\">args</span> <span class=\"o\">=</span> <span class=\"p\">{</span>\n            <span class=\"s2\">&quot;service_id&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;S13442&quot;</span><span class=\"p\">,</span>\n            <span class=\"s2\">&quot;api_key&quot;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;w5v7gUV3iPGsGntcM84PtOOM&#39;</span><span class=\"p\">,</span>\n            <span class=\"s2\">&quot;secret_key&quot;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;KffXwW6E1alcGplcabcNs63Li6GvvnfL&#39;</span>\n        <span class=\"p\">}</span>\n        <span class=\"n\">parsed</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">conversation</span><span class=\"o\">.</span><span class=\"n\">doParse</span><span class=\"p\">(</span><span class=\"n\">text</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">args</span><span class=\"p\">)</span>\n\n        <span class=\"k\">for</span> <span class=\"n\">plugin</span> <span class=\"ow\">in</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">plugins</span><span class=\"p\">:</span>\n            <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">plugin</span><span class=\"o\">.</span><span class=\"n\">isValid</span><span class=\"p\">(</span><span class=\"n\">text</span><span class=\"p\">,</span> <span class=\"n\">parsed</span><span class=\"p\">)</span> <span class=\"ow\">and</span> <span class=\"ow\">not</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">isImmersive</span><span class=\"p\">(</span><span class=\"n\">plugin</span><span class=\"p\">,</span> <span class=\"n\">text</span><span class=\"p\">,</span> <span class=\"n\">parsed</span><span class=\"p\">):</span>\n                <span class=\"k\">continue</span>\n\n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s2\">&quot;&#39;</span><span class=\"si\">{}</span><span class=\"s2\">&#39; 命中技能 </span><span class=\"si\">{}</span><span class=\"s2\">&quot;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">text</span><span class=\"p\">,</span> <span class=\"n\">plugin</span><span class=\"o\">.</span><span class=\"n\">SLUG</span><span class=\"p\">))</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">conversation</span><span class=\"o\">.</span><span class=\"n\">matchPlugin</span> <span class=\"o\">=</span> <span class=\"n\">plugin</span><span class=\"o\">.</span><span class=\"n\">SLUG</span>\n\n            <span class=\"k\">if</span> <span class=\"n\">plugin</span><span class=\"o\">.</span><span class=\"n\">IS_IMMERSIVE</span><span class=\"p\">:</span>\n                <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">conversation</span><span class=\"o\">.</span><span class=\"n\">setImmersiveMode</span><span class=\"p\">(</span><span class=\"n\">plugin</span><span class=\"o\">.</span><span class=\"n\">SLUG</span><span class=\"p\">)</span>\n\n            <span class=\"n\">continueHandle</span> <span class=\"o\">=</span> <span class=\"kc\">False</span>\n            <span class=\"k\">try</span><span class=\"p\">:</span>\n                <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">handling</span> <span class=\"o\">=</span> <span class=\"kc\">True</span>\n                <span class=\"n\">continueHandle</span> <span class=\"o\">=</span> <span class=\"n\">plugin</span><span class=\"o\">.</span><span class=\"n\">handle</span><span class=\"p\">(</span><span class=\"n\">text</span><span class=\"p\">,</span> <span class=\"n\">parsed</span><span class=\"p\">)</span>\n                <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">handling</span> <span class=\"o\">=</span> <span class=\"kc\">False</span>                \n            <span class=\"k\">except</span> <span class=\"ne\">Exception</span><span class=\"p\">:</span>\n                <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">critical</span><span class=\"p\">(</span><span class=\"s1\">&#39;Failed to execute plugin&#39;</span><span class=\"p\">,</span>\n                                   <span class=\"n\">exc_info</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">)</span>\n                <span class=\"n\">reply</span> <span class=\"o\">=</span> <span class=\"sa\">u</span><span class=\"s2\">&quot;抱歉，插件</span><span class=\"si\">{}</span><span class=\"s2\">出故障了，晚点再试试吧&quot;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">plugin</span><span class=\"o\">.</span><span class=\"n\">SLUG</span><span class=\"p\">)</span>\n                <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">conversation</span><span class=\"o\">.</span><span class=\"n\">say</span><span class=\"p\">(</span><span class=\"n\">reply</span><span class=\"p\">,</span> <span class=\"n\">plugin</span><span class=\"o\">=</span><span class=\"n\">plugin</span><span class=\"o\">.</span><span class=\"n\">SLUG</span><span class=\"p\">)</span>\n            <span class=\"k\">else</span><span class=\"p\">:</span>\n                <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">debug</span><span class=\"p\">(</span><span class=\"s2\">&quot;Handling of phrase &#39;</span><span class=\"si\">%s</span><span class=\"s2\">&#39; by &quot;</span> <span class=\"o\">+</span>\n                                   <span class=\"s2\">&quot;plugin &#39;</span><span class=\"si\">%s</span><span class=\"s2\">&#39; completed&quot;</span><span class=\"p\">,</span> <span class=\"n\">text</span><span class=\"p\">,</span>\n                                   <span class=\"n\">plugin</span><span class=\"o\">.</span><span class=\"n\">SLUG</span><span class=\"p\">)</span>                    \n            <span class=\"k\">finally</span><span class=\"p\">:</span>\n                <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">continueHandle</span><span class=\"p\">:</span>\n                    <span class=\"k\">return</span> <span class=\"kc\">True</span>\n\n        <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">debug</span><span class=\"p\">(</span><span class=\"s2\">&quot;No plugin was able to handle phrase </span><span class=\"si\">{}</span><span class=\"s2\"> &quot;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">text</span><span class=\"p\">))</span>\n        <span class=\"k\">return</span> <span class=\"kc\">False</span></div>\n\n<div class=\"viewcode-block\" id=\"Brain.restore\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.Brain.Brain.restore\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">restore</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot; 恢复某个技能的处理 &quot;&quot;&quot;</span>\n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">conversation</span><span class=\"o\">.</span><span class=\"n\">immersiveMode</span><span class=\"p\">:</span>\n            <span class=\"k\">return</span>\n        <span class=\"k\">for</span> <span class=\"n\">plugin</span> <span class=\"ow\">in</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">plugins</span><span class=\"p\">:</span>\n            <span class=\"k\">if</span> <span class=\"n\">plugin</span><span class=\"o\">.</span><span class=\"n\">SLUG</span> <span class=\"o\">==</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">conversation</span><span class=\"o\">.</span><span class=\"n\">immersiveMode</span> <span class=\"ow\">and</span> <span class=\"n\">plugin</span><span class=\"o\">.</span><span class=\"n\">restore</span><span class=\"p\">:</span>\n                <span class=\"n\">plugin</span><span class=\"o\">.</span><span class=\"n\">restore</span><span class=\"p\">()</span></div>\n\n<div class=\"viewcode-block\" id=\"Brain.pause\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.Brain.Brain.pause\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">pause</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot; 暂停某个技能的处理 &quot;&quot;&quot;</span>\n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">conversation</span><span class=\"o\">.</span><span class=\"n\">immersiveMode</span><span class=\"p\">:</span>\n            <span class=\"k\">return</span>\n        <span class=\"k\">for</span> <span class=\"n\">plugin</span> <span class=\"ow\">in</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">plugins</span><span class=\"p\">:</span>\n            <span class=\"k\">if</span> <span class=\"n\">plugin</span><span class=\"o\">.</span><span class=\"n\">SLUG</span> <span class=\"o\">==</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">conversation</span><span class=\"o\">.</span><span class=\"n\">immersiveMode</span> <span class=\"ow\">and</span> <span class=\"n\">plugin</span><span class=\"o\">.</span><span class=\"n\">pause</span><span class=\"p\">:</span>\n                <span class=\"n\">plugin</span><span class=\"o\">.</span><span class=\"n\">pause</span><span class=\"p\">()</span></div>\n\n<div class=\"viewcode-block\" id=\"Brain.understand\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.Brain.Brain.understand\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">understand</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">fp</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">conversation</span> <span class=\"ow\">and</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">conversation</span><span class=\"o\">.</span><span class=\"n\">asr</span><span class=\"p\">:</span>\n            <span class=\"k\">return</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">conversation</span><span class=\"o\">.</span><span class=\"n\">asr</span><span class=\"o\">.</span><span class=\"n\">transcribe</span><span class=\"p\">(</span><span class=\"n\">fp</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span> <span class=\"kc\">None</span></div>\n\n<div class=\"viewcode-block\" id=\"Brain.say\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.Brain.Brain.say\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">say</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">msg</span><span class=\"p\">,</span> <span class=\"n\">cache</span><span class=\"o\">=</span><span class=\"kc\">False</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">conversation</span> <span class=\"ow\">and</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">conversation</span><span class=\"o\">.</span><span class=\"n\">tts</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">conversation</span><span class=\"o\">.</span><span class=\"n\">tts</span><span class=\"o\">.</span><span class=\"n\">say</span><span class=\"p\">(</span><span class=\"n\">msg</span><span class=\"p\">,</span> <span class=\"n\">cache</span><span class=\"p\">)</span></div></div>\n\n    \n            \n</pre></div>\n\n           </div>\n           \n          </div>\n          <footer>\n  \n\n  <hr/>\n\n  <div role=\"contentinfo\">\n    <p>\n        &copy; Copyright 2019, wzpan\n\n    </p>\n  </div>\n  Built with <a href=\"http://sphinx-doc.org/\">Sphinx</a> using a <a href=\"https://github.com/rtfd/sphinx_rtd_theme\">theme</a> provided by <a href=\"https://readthedocs.org\">Read the Docs</a>. \n\n</footer>\n\n        </div>\n      </div>\n\n    </section>\n\n  </div>\n  \n\n\n  <script type=\"text/javascript\">\n      jQuery(function () {\n          SphinxRtdTheme.Navigation.enable(true);\n      });\n  </script>\n\n  \n  \n    \n   \n\n</body>\n</html>"
  },
  {
    "path": "docs/_modules/robot/ConfigMonitor.html",
    "content": "\n\n<!DOCTYPE html>\n<!--[if IE 8]><html class=\"no-js lt-ie9\" lang=\"zh-CN\" > <![endif]-->\n<!--[if gt IE 8]><!--> <html class=\"no-js\" lang=\"zh-CN\" > <!--<![endif]-->\n<head>\n  <meta charset=\"utf-8\">\n  \n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  \n  <title>robot.ConfigMonitor &mdash; wukong-robot 1.2.0 文档</title>\n  \n\n  \n  \n  \n  \n\n  \n  <script type=\"text/javascript\" src=\"../../_static/js/modernizr.min.js\"></script>\n  \n    \n      <script type=\"text/javascript\" id=\"documentation_options\" data-url_root=\"../../\" src=\"../../_static/documentation_options.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/jquery.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/underscore.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/doctools.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/language_data.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/translations.js\"></script>\n    \n    <script type=\"text/javascript\" src=\"../../_static/js/theme.js\"></script>\n\n    \n\n  \n  <link rel=\"stylesheet\" href=\"../../_static/css/theme.css\" type=\"text/css\" />\n  <link rel=\"stylesheet\" href=\"../../_static/pygments.css\" type=\"text/css\" />\n    <link rel=\"index\" title=\"索引\" href=\"../../genindex.html\" />\n    <link rel=\"search\" title=\"搜索\" href=\"../../search.html\" /> \n</head>\n\n<body class=\"wy-body-for-nav\">\n\n   \n  <div class=\"wy-grid-for-nav\">\n    \n    <nav data-toggle=\"wy-nav-shift\" class=\"wy-nav-side\">\n      <div class=\"wy-side-scroll\">\n        <div class=\"wy-side-nav-search\" >\n          \n\n          \n            <a href=\"../../index.html\" class=\"icon icon-home\"> wukong-robot\n          \n\n          \n          </a>\n\n          \n            \n            \n          \n\n          \n<div role=\"search\">\n  <form id=\"rtd-search-form\" class=\"wy-form\" action=\"../../search.html\" method=\"get\">\n    <input type=\"text\" name=\"q\" placeholder=\"Search docs\" />\n    <input type=\"hidden\" name=\"check_keywords\" value=\"yes\" />\n    <input type=\"hidden\" name=\"area\" value=\"default\" />\n  </form>\n</div>\n\n          \n        </div>\n\n        <div class=\"wy-menu wy-menu-vertical\" data-spy=\"affix\" role=\"navigation\" aria-label=\"main navigation\">\n          \n            \n            \n              \n            \n            \n              <!-- Local TOC -->\n              <div class=\"local-toc\"></div>\n            \n          \n        </div>\n      </div>\n    </nav>\n\n    <section data-toggle=\"wy-nav-shift\" class=\"wy-nav-content-wrap\">\n\n      \n      <nav class=\"wy-nav-top\" aria-label=\"top navigation\">\n        \n          <i data-toggle=\"wy-nav-top\" class=\"fa fa-bars\"></i>\n          <a href=\"../../index.html\">wukong-robot</a>\n        \n      </nav>\n\n\n      <div class=\"wy-nav-content\">\n        \n        <div class=\"rst-content\">\n        \n          \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<div role=\"navigation\" aria-label=\"breadcrumbs navigation\">\n\n  <ul class=\"wy-breadcrumbs\">\n    \n      <li><a href=\"../../index.html\">Docs</a> &raquo;</li>\n        \n          <li><a href=\"../index.html\">模块代码</a> &raquo;</li>\n        \n      <li>robot.ConfigMonitor</li>\n    \n    \n      <li class=\"wy-breadcrumbs-aside\">\n        \n      </li>\n    \n  </ul>\n\n  \n  <hr/>\n</div>\n          <div role=\"main\" class=\"document\" itemscope=\"itemscope\" itemtype=\"http://schema.org/Article\">\n           <div itemprop=\"articleBody\">\n            \n  <h1>robot.ConfigMonitor 源代码</h1><div class=\"highlight\"><pre>\n<span></span><span class=\"c1\"># -*- coding: utf-8-*-</span>\n\n<span class=\"kn\">from</span> <span class=\"nn\">robot</span> <span class=\"k\">import</span> <span class=\"n\">config</span>\n<span class=\"kn\">from</span> <span class=\"nn\">watchdog.events</span> <span class=\"k\">import</span> <span class=\"n\">FileSystemEventHandler</span>\n\n<div class=\"viewcode-block\" id=\"ConfigMonitor\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.ConfigMonitor.ConfigMonitor\">[文档]</a><span class=\"k\">class</span> <span class=\"nc\">ConfigMonitor</span><span class=\"p\">(</span><span class=\"n\">FileSystemEventHandler</span><span class=\"p\">):</span>\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">conversation</span><span class=\"p\">):</span>\n        <span class=\"n\">FileSystemEventHandler</span><span class=\"o\">.</span><span class=\"fm\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_conversation</span> <span class=\"o\">=</span> <span class=\"n\">conversation</span>\n\n    <span class=\"c1\"># 文件修改</span>\n<div class=\"viewcode-block\" id=\"ConfigMonitor.on_modified\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.ConfigMonitor.ConfigMonitor.on_modified\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">on_modified</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">event</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">event</span><span class=\"o\">.</span><span class=\"n\">is_directory</span><span class=\"p\">:</span>\n            <span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">reload</span><span class=\"p\">()</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_conversation</span><span class=\"o\">.</span><span class=\"n\">reload</span><span class=\"p\">()</span></div></div>\n</pre></div>\n\n           </div>\n           \n          </div>\n          <footer>\n  \n\n  <hr/>\n\n  <div role=\"contentinfo\">\n    <p>\n        &copy; Copyright 2019, wzpan\n\n    </p>\n  </div>\n  Built with <a href=\"http://sphinx-doc.org/\">Sphinx</a> using a <a href=\"https://github.com/rtfd/sphinx_rtd_theme\">theme</a> provided by <a href=\"https://readthedocs.org\">Read the Docs</a>. \n\n</footer>\n\n        </div>\n      </div>\n\n    </section>\n\n  </div>\n  \n\n\n  <script type=\"text/javascript\">\n      jQuery(function () {\n          SphinxRtdTheme.Navigation.enable(true);\n      });\n  </script>\n\n  \n  \n    \n   \n\n</body>\n</html>"
  },
  {
    "path": "docs/_modules/robot/Conversation.html",
    "content": "\n\n<!DOCTYPE html>\n<!--[if IE 8]><html class=\"no-js lt-ie9\" lang=\"zh-CN\" > <![endif]-->\n<!--[if gt IE 8]><!--> <html class=\"no-js\" lang=\"zh-CN\" > <!--<![endif]-->\n<head>\n  <meta charset=\"utf-8\">\n  \n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  \n  <title>robot.Conversation &mdash; wukong-robot 1.2.0 文档</title>\n  \n\n  \n  \n  \n  \n\n  \n  <script type=\"text/javascript\" src=\"../../_static/js/modernizr.min.js\"></script>\n  \n    \n      <script type=\"text/javascript\" id=\"documentation_options\" data-url_root=\"../../\" src=\"../../_static/documentation_options.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/jquery.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/underscore.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/doctools.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/language_data.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/translations.js\"></script>\n    \n    <script type=\"text/javascript\" src=\"../../_static/js/theme.js\"></script>\n\n    \n\n  \n  <link rel=\"stylesheet\" href=\"../../_static/css/theme.css\" type=\"text/css\" />\n  <link rel=\"stylesheet\" href=\"../../_static/pygments.css\" type=\"text/css\" />\n    <link rel=\"index\" title=\"索引\" href=\"../../genindex.html\" />\n    <link rel=\"search\" title=\"搜索\" href=\"../../search.html\" /> \n</head>\n\n<body class=\"wy-body-for-nav\">\n\n   \n  <div class=\"wy-grid-for-nav\">\n    \n    <nav data-toggle=\"wy-nav-shift\" class=\"wy-nav-side\">\n      <div class=\"wy-side-scroll\">\n        <div class=\"wy-side-nav-search\" >\n          \n\n          \n            <a href=\"../../index.html\" class=\"icon icon-home\"> wukong-robot\n          \n\n          \n          </a>\n\n          \n            \n            \n          \n\n          \n<div role=\"search\">\n  <form id=\"rtd-search-form\" class=\"wy-form\" action=\"../../search.html\" method=\"get\">\n    <input type=\"text\" name=\"q\" placeholder=\"Search docs\" />\n    <input type=\"hidden\" name=\"check_keywords\" value=\"yes\" />\n    <input type=\"hidden\" name=\"area\" value=\"default\" />\n  </form>\n</div>\n\n          \n        </div>\n\n        <div class=\"wy-menu wy-menu-vertical\" data-spy=\"affix\" role=\"navigation\" aria-label=\"main navigation\">\n          \n            \n            \n              \n            \n            \n              <!-- Local TOC -->\n              <div class=\"local-toc\"></div>\n            \n          \n        </div>\n      </div>\n    </nav>\n\n    <section data-toggle=\"wy-nav-shift\" class=\"wy-nav-content-wrap\">\n\n      \n      <nav class=\"wy-nav-top\" aria-label=\"top navigation\">\n        \n          <i data-toggle=\"wy-nav-top\" class=\"fa fa-bars\"></i>\n          <a href=\"../../index.html\">wukong-robot</a>\n        \n      </nav>\n\n\n      <div class=\"wy-nav-content\">\n        \n        <div class=\"rst-content\">\n        \n          \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<div role=\"navigation\" aria-label=\"breadcrumbs navigation\">\n\n  <ul class=\"wy-breadcrumbs\">\n    \n      <li><a href=\"../../index.html\">Docs</a> &raquo;</li>\n        \n          <li><a href=\"../index.html\">模块代码</a> &raquo;</li>\n        \n      <li>robot.Conversation</li>\n    \n    \n      <li class=\"wy-breadcrumbs-aside\">\n        \n      </li>\n    \n  </ul>\n\n  \n  <hr/>\n</div>\n          <div role=\"main\" class=\"document\" itemscope=\"itemscope\" itemtype=\"http://schema.org/Article\">\n           <div itemprop=\"articleBody\">\n            \n  <h1>robot.Conversation 源代码</h1><div class=\"highlight\"><pre>\n<span></span><span class=\"c1\"># -*- coding: utf-8-*-</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span> \n<span class=\"kn\">import</span> <span class=\"nn\">uuid</span>\n<span class=\"kn\">import</span> <span class=\"nn\">cProfile</span>\n<span class=\"kn\">import</span> <span class=\"nn\">pstats</span>\n<span class=\"kn\">import</span> <span class=\"nn\">io</span>\n<span class=\"kn\">import</span> <span class=\"nn\">re</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">from</span> <span class=\"nn\">robot.Brain</span> <span class=\"k\">import</span> <span class=\"n\">Brain</span>\n<span class=\"kn\">from</span> <span class=\"nn\">snowboy</span> <span class=\"k\">import</span> <span class=\"n\">snowboydecoder</span>\n<span class=\"kn\">from</span> <span class=\"nn\">robot</span> <span class=\"k\">import</span> <span class=\"n\">logging</span><span class=\"p\">,</span> <span class=\"n\">ASR</span><span class=\"p\">,</span> <span class=\"n\">TTS</span><span class=\"p\">,</span> <span class=\"n\">NLU</span><span class=\"p\">,</span> <span class=\"n\">AI</span><span class=\"p\">,</span> <span class=\"n\">Player</span><span class=\"p\">,</span> <span class=\"n\">config</span><span class=\"p\">,</span> <span class=\"n\">constants</span><span class=\"p\">,</span> <span class=\"n\">utils</span><span class=\"p\">,</span> <span class=\"n\">statistic</span>\n\n\n<span class=\"n\">logger</span> <span class=\"o\">=</span> <span class=\"n\">logging</span><span class=\"o\">.</span><span class=\"n\">getLogger</span><span class=\"p\">(</span><span class=\"vm\">__name__</span><span class=\"p\">)</span>\n\n<div class=\"viewcode-block\" id=\"Conversation\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.Conversation.Conversation\">[文档]</a><span class=\"k\">class</span> <span class=\"nc\">Conversation</span><span class=\"p\">(</span><span class=\"nb\">object</span><span class=\"p\">):</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">profiling</span><span class=\"o\">=</span><span class=\"kc\">False</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">reload</span><span class=\"p\">()</span>\n        <span class=\"c1\"># 历史会话消息</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">history</span> <span class=\"o\">=</span> <span class=\"p\">[]</span>\n        <span class=\"c1\"># 沉浸模式，处于这个模式下，被打断后将自动恢复这个技能</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">matchPlugin</span> <span class=\"o\">=</span> <span class=\"kc\">None</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">immersiveMode</span> <span class=\"o\">=</span> <span class=\"kc\">None</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">isRecording</span> <span class=\"o\">=</span> <span class=\"kc\">False</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">profiling</span> <span class=\"o\">=</span> <span class=\"n\">profiling</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">onSay</span> <span class=\"o\">=</span> <span class=\"kc\">None</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">hasPardon</span> <span class=\"o\">=</span> <span class=\"kc\">False</span>\n\n<div class=\"viewcode-block\" id=\"Conversation.getHistory\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.Conversation.Conversation.getHistory\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">getHistory</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">history</span></div>\n\n<div class=\"viewcode-block\" id=\"Conversation.interrupt\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.Conversation.Conversation.interrupt\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">interrupt</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">player</span> <span class=\"ow\">is</span> <span class=\"ow\">not</span> <span class=\"kc\">None</span> <span class=\"ow\">and</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">player</span><span class=\"o\">.</span><span class=\"n\">is_playing</span><span class=\"p\">():</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">player</span><span class=\"o\">.</span><span class=\"n\">stop</span><span class=\"p\">()</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">player</span> <span class=\"o\">=</span> <span class=\"kc\">None</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">immersiveMode</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">brain</span><span class=\"o\">.</span><span class=\"n\">pause</span><span class=\"p\">()</span></div>\n\n<div class=\"viewcode-block\" id=\"Conversation.reload\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.Conversation.Conversation.reload\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">reload</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot; 重新初始化 &quot;&quot;&quot;</span>\n        <span class=\"k\">try</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">asr</span> <span class=\"o\">=</span> <span class=\"n\">ASR</span><span class=\"o\">.</span><span class=\"n\">get_engine_by_slug</span><span class=\"p\">(</span><span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;asr_engine&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;tencent-asr&#39;</span><span class=\"p\">))</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">ai</span> <span class=\"o\">=</span> <span class=\"n\">AI</span><span class=\"o\">.</span><span class=\"n\">get_robot_by_slug</span><span class=\"p\">(</span><span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;robot&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;tuling&#39;</span><span class=\"p\">))</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">tts</span> <span class=\"o\">=</span> <span class=\"n\">TTS</span><span class=\"o\">.</span><span class=\"n\">get_engine_by_slug</span><span class=\"p\">(</span><span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;tts_engine&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;baidu-tts&#39;</span><span class=\"p\">))</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">nlu</span> <span class=\"o\">=</span> <span class=\"n\">NLU</span><span class=\"o\">.</span><span class=\"n\">get_engine_by_slug</span><span class=\"p\">(</span><span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;nlu_engine&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;unit&#39;</span><span class=\"p\">))</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">player</span> <span class=\"o\">=</span> <span class=\"kc\">None</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">brain</span> <span class=\"o\">=</span> <span class=\"n\">Brain</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">)</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">brain</span><span class=\"o\">.</span><span class=\"n\">printPlugins</span><span class=\"p\">()</span>\n        <span class=\"k\">except</span> <span class=\"ne\">Exception</span> <span class=\"k\">as</span> <span class=\"n\">e</span><span class=\"p\">:</span>\n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">critical</span><span class=\"p\">(</span><span class=\"s2\">&quot;对话初始化失败：</span><span class=\"si\">{}</span><span class=\"s2\">&quot;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">e</span><span class=\"p\">))</span></div>\n\n<div class=\"viewcode-block\" id=\"Conversation.checkRestore\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.Conversation.Conversation.checkRestore\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">checkRestore</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">immersiveMode</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">brain</span><span class=\"o\">.</span><span class=\"n\">restore</span><span class=\"p\">()</span></div>\n\n<div class=\"viewcode-block\" id=\"Conversation.doResponse\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.Conversation.Conversation.doResponse\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">doResponse</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">query</span><span class=\"p\">,</span> <span class=\"n\">UUID</span><span class=\"o\">=</span><span class=\"s1\">&#39;&#39;</span><span class=\"p\">,</span> <span class=\"n\">onSay</span><span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">):</span>\n        <span class=\"n\">statistic</span><span class=\"o\">.</span><span class=\"n\">report</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">interrupt</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">appendHistory</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">query</span><span class=\"p\">,</span> <span class=\"n\">UUID</span><span class=\"p\">)</span>\n\n        <span class=\"k\">if</span> <span class=\"n\">onSay</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">onSay</span> <span class=\"o\">=</span> <span class=\"n\">onSay</span>\n\n        <span class=\"k\">if</span> <span class=\"n\">query</span><span class=\"o\">.</span><span class=\"n\">strip</span><span class=\"p\">()</span> <span class=\"o\">==</span> <span class=\"s1\">&#39;&#39;</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">pardon</span><span class=\"p\">()</span>\n            <span class=\"k\">return</span>\n\n        <span class=\"n\">lastImmersiveMode</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">immersiveMode</span>\n\n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">brain</span><span class=\"o\">.</span><span class=\"n\">query</span><span class=\"p\">(</span><span class=\"n\">query</span><span class=\"p\">):</span>\n            <span class=\"c1\"># 没命中技能，使用机器人回复</span>\n            <span class=\"n\">msg</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">ai</span><span class=\"o\">.</span><span class=\"n\">chat</span><span class=\"p\">(</span><span class=\"n\">query</span><span class=\"p\">)</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">say</span><span class=\"p\">(</span><span class=\"n\">msg</span><span class=\"p\">,</span> <span class=\"kc\">True</span><span class=\"p\">,</span> <span class=\"n\">onCompleted</span><span class=\"o\">=</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">checkRestore</span><span class=\"p\">)</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"k\">if</span> <span class=\"n\">lastImmersiveMode</span> <span class=\"ow\">is</span> <span class=\"ow\">not</span> <span class=\"kc\">None</span> <span class=\"ow\">and</span> <span class=\"n\">lastImmersiveMode</span> <span class=\"o\">!=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">matchPlugin</span><span class=\"p\">:</span>\n                <span class=\"n\">time</span><span class=\"o\">.</span><span class=\"n\">sleep</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n                <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">player</span> <span class=\"ow\">is</span> <span class=\"ow\">not</span> <span class=\"kc\">None</span> <span class=\"ow\">and</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">player</span><span class=\"o\">.</span><span class=\"n\">is_playing</span><span class=\"p\">():</span>\n                    <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">debug</span><span class=\"p\">(</span><span class=\"s1\">&#39;等说完再checkRestore&#39;</span><span class=\"p\">)</span>\n                    <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">player</span><span class=\"o\">.</span><span class=\"n\">appendOnCompleted</span><span class=\"p\">(</span><span class=\"k\">lambda</span><span class=\"p\">:</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">checkRestore</span><span class=\"p\">())</span>\n                <span class=\"k\">else</span><span class=\"p\">:</span>\n                    <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">debug</span><span class=\"p\">(</span><span class=\"s1\">&#39;checkRestore&#39;</span><span class=\"p\">)</span>\n                    <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">checkRestore</span><span class=\"p\">()</span></div>\n\n<div class=\"viewcode-block\" id=\"Conversation.doParse\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.Conversation.Conversation.doParse\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">doParse</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">query</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">args</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">nlu</span><span class=\"o\">.</span><span class=\"n\">parse</span><span class=\"p\">(</span><span class=\"n\">query</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">args</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"Conversation.setImmersiveMode\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.Conversation.Conversation.setImmersiveMode\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">setImmersiveMode</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">slug</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">immersiveMode</span> <span class=\"o\">=</span> <span class=\"n\">slug</span></div>\n\n<div class=\"viewcode-block\" id=\"Conversation.getImmersiveMode\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.Conversation.Conversation.getImmersiveMode\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">getImmersiveMode</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">immersiveMode</span></div>\n\n<div class=\"viewcode-block\" id=\"Conversation.converse\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.Conversation.Conversation.converse\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">converse</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">fp</span><span class=\"p\">,</span> <span class=\"n\">callback</span><span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot; 核心对话逻辑 &quot;&quot;&quot;</span>\n        <span class=\"n\">Player</span><span class=\"o\">.</span><span class=\"n\">play</span><span class=\"p\">(</span><span class=\"n\">constants</span><span class=\"o\">.</span><span class=\"n\">getData</span><span class=\"p\">(</span><span class=\"s1\">&#39;beep_lo.wav&#39;</span><span class=\"p\">))</span>\n        <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s1\">&#39;结束录音&#39;</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">isRecording</span> <span class=\"o\">=</span> <span class=\"kc\">False</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">profiling</span><span class=\"p\">:</span>\n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s1\">&#39;性能调试已打开&#39;</span><span class=\"p\">)</span>\n            <span class=\"n\">pr</span> <span class=\"o\">=</span> <span class=\"n\">cProfile</span><span class=\"o\">.</span><span class=\"n\">Profile</span><span class=\"p\">()</span>\n            <span class=\"n\">pr</span><span class=\"o\">.</span><span class=\"n\">enable</span><span class=\"p\">()</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">doConverse</span><span class=\"p\">(</span><span class=\"n\">fp</span><span class=\"p\">,</span> <span class=\"n\">callback</span><span class=\"p\">)</span>\n            <span class=\"n\">pr</span><span class=\"o\">.</span><span class=\"n\">disable</span><span class=\"p\">()</span>\n            <span class=\"n\">s</span> <span class=\"o\">=</span> <span class=\"n\">io</span><span class=\"o\">.</span><span class=\"n\">StringIO</span><span class=\"p\">()</span>\n            <span class=\"n\">sortby</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;cumulative&#39;</span>\n            <span class=\"n\">ps</span> <span class=\"o\">=</span> <span class=\"n\">pstats</span><span class=\"o\">.</span><span class=\"n\">Stats</span><span class=\"p\">(</span><span class=\"n\">pr</span><span class=\"p\">,</span> <span class=\"n\">stream</span><span class=\"o\">=</span><span class=\"n\">s</span><span class=\"p\">)</span><span class=\"o\">.</span><span class=\"n\">sort_stats</span><span class=\"p\">(</span><span class=\"n\">sortby</span><span class=\"p\">)</span>\n            <span class=\"n\">ps</span><span class=\"o\">.</span><span class=\"n\">print_stats</span><span class=\"p\">()</span>\n            <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"n\">s</span><span class=\"o\">.</span><span class=\"n\">getvalue</span><span class=\"p\">())</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">doConverse</span><span class=\"p\">(</span><span class=\"n\">fp</span><span class=\"p\">,</span> <span class=\"n\">callback</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"Conversation.doConverse\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.Conversation.Conversation.doConverse\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">doConverse</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">fp</span><span class=\"p\">,</span> <span class=\"n\">callback</span><span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">,</span> <span class=\"n\">onSay</span><span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">):</span>\n        <span class=\"k\">try</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">interrupt</span><span class=\"p\">()</span>\n            <span class=\"n\">query</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">asr</span><span class=\"o\">.</span><span class=\"n\">transcribe</span><span class=\"p\">(</span><span class=\"n\">fp</span><span class=\"p\">)</span>\n            <span class=\"n\">utils</span><span class=\"o\">.</span><span class=\"n\">check_and_delete</span><span class=\"p\">(</span><span class=\"n\">fp</span><span class=\"p\">)</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">doResponse</span><span class=\"p\">(</span><span class=\"n\">query</span><span class=\"p\">,</span> <span class=\"n\">callback</span><span class=\"p\">,</span> <span class=\"n\">onSay</span><span class=\"p\">)</span>\n        <span class=\"k\">except</span> <span class=\"ne\">Exception</span> <span class=\"k\">as</span> <span class=\"n\">e</span><span class=\"p\">:</span>\n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">critical</span><span class=\"p\">(</span><span class=\"n\">e</span><span class=\"p\">)</span>\n            <span class=\"n\">utils</span><span class=\"o\">.</span><span class=\"n\">clean</span><span class=\"p\">()</span></div>\n\n<div class=\"viewcode-block\" id=\"Conversation.appendHistory\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.Conversation.Conversation.appendHistory\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">appendHistory</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">t</span><span class=\"p\">,</span> <span class=\"n\">text</span><span class=\"p\">,</span> <span class=\"n\">UUID</span><span class=\"o\">=</span><span class=\"s1\">&#39;&#39;</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot; 将会话历史加进历史记录 &quot;&quot;&quot;</span>\n        <span class=\"k\">if</span> <span class=\"n\">t</span> <span class=\"ow\">in</span> <span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">)</span> <span class=\"ow\">and</span> <span class=\"n\">text</span> <span class=\"ow\">is</span> <span class=\"ow\">not</span> <span class=\"kc\">None</span> <span class=\"ow\">and</span> <span class=\"n\">text</span> <span class=\"o\">!=</span> <span class=\"s1\">&#39;&#39;</span><span class=\"p\">:</span>\n            <span class=\"k\">if</span> <span class=\"n\">text</span><span class=\"o\">.</span><span class=\"n\">endswith</span><span class=\"p\">(</span><span class=\"s1\">&#39;,&#39;</span><span class=\"p\">)</span> <span class=\"ow\">or</span> <span class=\"n\">text</span><span class=\"o\">.</span><span class=\"n\">endswith</span><span class=\"p\">(</span><span class=\"s1\">&#39;，&#39;</span><span class=\"p\">):</span>\n                <span class=\"n\">text</span> <span class=\"o\">=</span> <span class=\"n\">text</span><span class=\"p\">[:</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n            <span class=\"k\">if</span> <span class=\"n\">UUID</span> <span class=\"o\">==</span> <span class=\"s1\">&#39;&#39;</span> <span class=\"ow\">or</span> <span class=\"n\">UUID</span> <span class=\"o\">==</span> <span class=\"kc\">None</span> <span class=\"ow\">or</span> <span class=\"n\">UUID</span> <span class=\"o\">==</span> <span class=\"s1\">&#39;null&#39;</span><span class=\"p\">:</span>\n                <span class=\"n\">UUID</span> <span class=\"o\">=</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">uuid</span><span class=\"o\">.</span><span class=\"n\">uuid1</span><span class=\"p\">())</span>\n            <span class=\"c1\"># 将图片处理成HTML</span>\n            <span class=\"n\">pattern</span> <span class=\"o\">=</span> <span class=\"sa\">r</span><span class=\"s1\">&#39;https?://.+\\.(?:png|jpg|jpeg|bmp|gif|JPG|PNG|JPEG|BMP|GIF)&#39;</span>\n            <span class=\"n\">url_pattern</span> <span class=\"o\">=</span> <span class=\"sa\">r</span><span class=\"s1\">&#39;^https?://.+&#39;</span>\n            <span class=\"n\">imgs</span> <span class=\"o\">=</span> <span class=\"n\">re</span><span class=\"o\">.</span><span class=\"n\">findall</span><span class=\"p\">(</span><span class=\"n\">pattern</span><span class=\"p\">,</span> <span class=\"n\">text</span><span class=\"p\">)</span>\n            <span class=\"k\">for</span> <span class=\"n\">img</span> <span class=\"ow\">in</span> <span class=\"n\">imgs</span><span class=\"p\">:</span>\n                <span class=\"n\">text</span> <span class=\"o\">=</span> <span class=\"n\">text</span><span class=\"o\">.</span><span class=\"n\">replace</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">,</span> <span class=\"s1\">&#39;&lt;img src=</span><span class=\"si\">{}</span><span class=\"s1\"> class=&quot;img&quot;/&gt;&#39;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">img</span><span class=\"p\">))</span>\n            <span class=\"n\">urls</span> <span class=\"o\">=</span> <span class=\"n\">re</span><span class=\"o\">.</span><span class=\"n\">findall</span><span class=\"p\">(</span><span class=\"n\">url_pattern</span><span class=\"p\">,</span> <span class=\"n\">text</span><span class=\"p\">)</span>\n            <span class=\"k\">for</span> <span class=\"n\">url</span> <span class=\"ow\">in</span> <span class=\"n\">urls</span><span class=\"p\">:</span>\n                <span class=\"n\">text</span> <span class=\"o\">=</span> <span class=\"n\">text</span><span class=\"o\">.</span><span class=\"n\">replace</span><span class=\"p\">(</span><span class=\"n\">url</span><span class=\"p\">,</span> <span class=\"s1\">&#39;&lt;a href=</span><span class=\"si\">{}</span><span class=\"s1\"> target=&quot;_blank&quot;&gt;</span><span class=\"si\">{}</span><span class=\"s1\">&lt;/a&gt;&#39;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">url</span><span class=\"p\">,</span> <span class=\"n\">url</span><span class=\"p\">))</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">history</span><span class=\"o\">.</span><span class=\"n\">append</span><span class=\"p\">({</span><span class=\"s1\">&#39;type&#39;</span><span class=\"p\">:</span> <span class=\"n\">t</span><span class=\"p\">,</span> <span class=\"s1\">&#39;text&#39;</span><span class=\"p\">:</span> <span class=\"n\">text</span><span class=\"p\">,</span> <span class=\"s1\">&#39;time&#39;</span><span class=\"p\">:</span> <span class=\"n\">time</span><span class=\"o\">.</span><span class=\"n\">strftime</span><span class=\"p\">(</span><span class=\"s1\">&#39;%Y-%m-</span><span class=\"si\">%d</span><span class=\"s1\"> %H:%M:%S&#39;</span><span class=\"p\">,</span> <span class=\"n\">time</span><span class=\"o\">.</span><span class=\"n\">localtime</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"o\">.</span><span class=\"n\">time</span><span class=\"p\">())),</span> <span class=\"s1\">&#39;uuid&#39;</span><span class=\"p\">:</span> <span class=\"n\">UUID</span><span class=\"p\">})</span></div>\n\n    <span class=\"k\">def</span> <span class=\"nf\">_onCompleted</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">msg</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;active_mode&#39;</span><span class=\"p\">,</span> <span class=\"kc\">False</span><span class=\"p\">)</span> <span class=\"ow\">and</span> \\\n           <span class=\"p\">(</span>\n               <span class=\"n\">msg</span><span class=\"o\">.</span><span class=\"n\">endswith</span><span class=\"p\">(</span><span class=\"s1\">&#39;?&#39;</span><span class=\"p\">)</span> <span class=\"ow\">or</span> \n               <span class=\"n\">msg</span><span class=\"o\">.</span><span class=\"n\">endswith</span><span class=\"p\">(</span><span class=\"sa\">u</span><span class=\"s1\">&#39;？&#39;</span><span class=\"p\">)</span> <span class=\"ow\">or</span> \n               <span class=\"sa\">u</span><span class=\"s1\">&#39;告诉我&#39;</span> <span class=\"ow\">in</span> <span class=\"n\">msg</span> <span class=\"ow\">or</span> <span class=\"sa\">u</span><span class=\"s1\">&#39;请回答&#39;</span> <span class=\"ow\">in</span> <span class=\"n\">msg</span>\n           <span class=\"p\">):</span>\n            <span class=\"n\">query</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">activeListen</span><span class=\"p\">()</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">doResponse</span><span class=\"p\">(</span><span class=\"n\">query</span><span class=\"p\">)</span>\n\n<div class=\"viewcode-block\" id=\"Conversation.pardon\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.Conversation.Conversation.pardon\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">pardon</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">hasPardon</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">say</span><span class=\"p\">(</span><span class=\"s2\">&quot;抱歉，刚刚没听清，能再说一遍吗？&quot;</span><span class=\"p\">,</span> <span class=\"n\">onCompleted</span><span class=\"o\">=</span><span class=\"k\">lambda</span><span class=\"p\">:</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">doResponse</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">activeListen</span><span class=\"p\">()))</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">hasPardon</span> <span class=\"o\">=</span> <span class=\"kc\">True</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">say</span><span class=\"p\">(</span><span class=\"s2\">&quot;没听清呢&quot;</span><span class=\"p\">)</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">hasPardon</span> <span class=\"o\">=</span> <span class=\"kc\">False</span></div>\n\n<div class=\"viewcode-block\" id=\"Conversation.say\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.Conversation.Conversation.say\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">say</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">msg</span><span class=\"p\">,</span> <span class=\"n\">cache</span><span class=\"o\">=</span><span class=\"kc\">False</span><span class=\"p\">,</span> <span class=\"n\">plugin</span><span class=\"o\">=</span><span class=\"s1\">&#39;&#39;</span><span class=\"p\">,</span> <span class=\"n\">onCompleted</span><span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">,</span> <span class=\"n\">wait</span><span class=\"o\">=</span><span class=\"kc\">False</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot; </span>\n<span class=\"sd\">        说一句话</span>\n<span class=\"sd\">        :param msg: 内容</span>\n<span class=\"sd\">        :param cache: 是否缓存这句话的音频</span>\n<span class=\"sd\">        :param plugin: 来自哪个插件的消息（将带上插件的说明）</span>\n<span class=\"sd\">        :param onCompleted: 完成的回调</span>\n<span class=\"sd\">        :param wait: 是否要等待说完（为True将阻塞主线程直至说完这句话）</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"k\">if</span> <span class=\"n\">plugin</span> <span class=\"o\">!=</span> <span class=\"s1\">&#39;&#39;</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">appendHistory</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"s2\">&quot;[</span><span class=\"si\">{}</span><span class=\"s2\">] </span><span class=\"si\">{}</span><span class=\"s2\">&quot;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">plugin</span><span class=\"p\">,</span> <span class=\"n\">msg</span><span class=\"p\">))</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">appendHistory</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"n\">msg</span><span class=\"p\">)</span>\n        <span class=\"n\">pattern</span> <span class=\"o\">=</span> <span class=\"sa\">r</span><span class=\"s1\">&#39;^https?://.+&#39;</span>\n        <span class=\"k\">if</span> <span class=\"n\">re</span><span class=\"o\">.</span><span class=\"n\">match</span><span class=\"p\">(</span><span class=\"n\">pattern</span><span class=\"p\">,</span> <span class=\"n\">msg</span><span class=\"p\">):</span>\n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s2\">&quot;内容包含URL，所以不读出来&quot;</span><span class=\"p\">)</span>\n            <span class=\"k\">return</span>\n        <span class=\"n\">voice</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;&#39;</span>\n        <span class=\"n\">cache_path</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;&#39;</span>\n        <span class=\"k\">if</span> <span class=\"n\">utils</span><span class=\"o\">.</span><span class=\"n\">getCache</span><span class=\"p\">(</span><span class=\"n\">msg</span><span class=\"p\">):</span>\n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s2\">&quot;命中缓存，播放缓存语音&quot;</span><span class=\"p\">)</span>\n            <span class=\"n\">voice</span> <span class=\"o\">=</span> <span class=\"n\">utils</span><span class=\"o\">.</span><span class=\"n\">getCache</span><span class=\"p\">(</span><span class=\"n\">msg</span><span class=\"p\">)</span>\n            <span class=\"n\">cache_path</span> <span class=\"o\">=</span> <span class=\"n\">utils</span><span class=\"o\">.</span><span class=\"n\">getCache</span><span class=\"p\">(</span><span class=\"n\">msg</span><span class=\"p\">)</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"k\">try</span><span class=\"p\">:</span>\n                <span class=\"n\">voice</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">tts</span><span class=\"o\">.</span><span class=\"n\">get_speech</span><span class=\"p\">(</span><span class=\"n\">msg</span><span class=\"p\">)</span>\n                <span class=\"n\">cache_path</span> <span class=\"o\">=</span> <span class=\"n\">utils</span><span class=\"o\">.</span><span class=\"n\">saveCache</span><span class=\"p\">(</span><span class=\"n\">voice</span><span class=\"p\">,</span> <span class=\"n\">msg</span><span class=\"p\">)</span>\n            <span class=\"k\">except</span> <span class=\"ne\">Exception</span> <span class=\"k\">as</span> <span class=\"n\">e</span><span class=\"p\">:</span>\n                <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">error</span><span class=\"p\">(</span><span class=\"s1\">&#39;保存缓存失败：</span><span class=\"si\">{}</span><span class=\"s1\">&#39;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">e</span><span class=\"p\">))</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">onSay</span><span class=\"p\">:</span>\n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"n\">cache</span><span class=\"p\">)</span>\n            <span class=\"n\">audio</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;http://</span><span class=\"si\">{}</span><span class=\"s1\">:</span><span class=\"si\">{}</span><span class=\"s1\">/audio/</span><span class=\"si\">{}</span><span class=\"s1\">&#39;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;/server/host&#39;</span><span class=\"p\">),</span> <span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;/server/port&#39;</span><span class=\"p\">),</span> <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">basename</span><span class=\"p\">(</span><span class=\"n\">cache_path</span><span class=\"p\">))</span>\n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s1\">&#39;onSay: </span><span class=\"si\">{}</span><span class=\"s1\">, </span><span class=\"si\">{}</span><span class=\"s1\">&#39;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">msg</span><span class=\"p\">,</span> <span class=\"n\">audio</span><span class=\"p\">))</span>\n            <span class=\"k\">if</span> <span class=\"n\">plugin</span> <span class=\"o\">!=</span> <span class=\"s1\">&#39;&#39;</span><span class=\"p\">:</span>\n                <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">onSay</span><span class=\"p\">(</span><span class=\"s2\">&quot;[</span><span class=\"si\">{}</span><span class=\"s2\">] </span><span class=\"si\">{}</span><span class=\"s2\">&quot;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">plugin</span><span class=\"p\">,</span> <span class=\"n\">msg</span><span class=\"p\">),</span> <span class=\"n\">audio</span><span class=\"p\">)</span>\n            <span class=\"k\">else</span><span class=\"p\">:</span>\n                <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">onSay</span><span class=\"p\">(</span><span class=\"n\">msg</span><span class=\"p\">,</span> <span class=\"n\">audio</span><span class=\"p\">)</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">onSay</span> <span class=\"o\">=</span> <span class=\"kc\">None</span>\n        <span class=\"k\">if</span> <span class=\"n\">onCompleted</span> <span class=\"ow\">is</span> <span class=\"kc\">None</span><span class=\"p\">:</span>\n            <span class=\"n\">onCompleted</span> <span class=\"o\">=</span> <span class=\"k\">lambda</span><span class=\"p\">:</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_onCompleted</span><span class=\"p\">(</span><span class=\"n\">msg</span><span class=\"p\">)</span>        \n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">player</span> <span class=\"o\">=</span> <span class=\"n\">Player</span><span class=\"o\">.</span><span class=\"n\">SoxPlayer</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">player</span><span class=\"o\">.</span><span class=\"n\">play</span><span class=\"p\">(</span><span class=\"n\">voice</span><span class=\"p\">,</span> <span class=\"ow\">not</span> <span class=\"n\">cache</span><span class=\"p\">,</span> <span class=\"n\">onCompleted</span><span class=\"p\">,</span> <span class=\"n\">wait</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">cache</span><span class=\"p\">:</span>\n            <span class=\"n\">utils</span><span class=\"o\">.</span><span class=\"n\">check_and_delete</span><span class=\"p\">(</span><span class=\"n\">cache_path</span><span class=\"p\">,</span> <span class=\"mi\">60</span><span class=\"p\">)</span> <span class=\"c1\"># 60秒后将自动清理不缓存的音频</span>\n        <span class=\"n\">utils</span><span class=\"o\">.</span><span class=\"n\">lruCache</span><span class=\"p\">()</span>  <span class=\"c1\"># 清理缓存</span></div>\n\n<div class=\"viewcode-block\" id=\"Conversation.activeListen\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.Conversation.Conversation.activeListen\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">activeListen</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">silent</span><span class=\"o\">=</span><span class=\"kc\">False</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot; 主动问一个问题(适用于多轮对话) &quot;&quot;&quot;</span>\n        <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">debug</span><span class=\"p\">(</span><span class=\"s1\">&#39;activeListen&#39;</span><span class=\"p\">)</span>\n        <span class=\"k\">try</span><span class=\"p\">:</span>\n            <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">silent</span><span class=\"p\">:</span>\n                <span class=\"n\">time</span><span class=\"o\">.</span><span class=\"n\">sleep</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n                <span class=\"n\">Player</span><span class=\"o\">.</span><span class=\"n\">play</span><span class=\"p\">(</span><span class=\"n\">constants</span><span class=\"o\">.</span><span class=\"n\">getData</span><span class=\"p\">(</span><span class=\"s1\">&#39;beep_hi.wav&#39;</span><span class=\"p\">))</span>\n            <span class=\"n\">listener</span> <span class=\"o\">=</span> <span class=\"n\">snowboydecoder</span><span class=\"o\">.</span><span class=\"n\">ActiveListener</span><span class=\"p\">([</span><span class=\"n\">constants</span><span class=\"o\">.</span><span class=\"n\">getHotwordModel</span><span class=\"p\">(</span><span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;hotword&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;wukong.pmdl&#39;</span><span class=\"p\">))])</span>\n            <span class=\"n\">voice</span> <span class=\"o\">=</span> <span class=\"n\">listener</span><span class=\"o\">.</span><span class=\"n\">listen</span><span class=\"p\">(</span>\n                <span class=\"n\">silent_count_threshold</span><span class=\"o\">=</span><span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;silent_threshold&#39;</span><span class=\"p\">,</span> <span class=\"mi\">15</span><span class=\"p\">),</span>\n                <span class=\"n\">recording_timeout</span><span class=\"o\">=</span><span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;recording_timeout&#39;</span><span class=\"p\">,</span> <span class=\"mi\">5</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"mi\">4</span>\n            <span class=\"p\">)</span>\n            <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">silent</span><span class=\"p\">:</span>\n                <span class=\"n\">Player</span><span class=\"o\">.</span><span class=\"n\">play</span><span class=\"p\">(</span><span class=\"n\">constants</span><span class=\"o\">.</span><span class=\"n\">getData</span><span class=\"p\">(</span><span class=\"s1\">&#39;beep_lo.wav&#39;</span><span class=\"p\">))</span>\n            <span class=\"k\">if</span> <span class=\"n\">voice</span><span class=\"p\">:</span>\n                <span class=\"n\">query</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">asr</span><span class=\"o\">.</span><span class=\"n\">transcribe</span><span class=\"p\">(</span><span class=\"n\">voice</span><span class=\"p\">)</span>\n                <span class=\"n\">utils</span><span class=\"o\">.</span><span class=\"n\">check_and_delete</span><span class=\"p\">(</span><span class=\"n\">voice</span><span class=\"p\">)</span>\n                <span class=\"k\">return</span> <span class=\"n\">query</span>\n            <span class=\"k\">return</span> <span class=\"s1\">&#39;&#39;</span>\n        <span class=\"k\">except</span> <span class=\"ne\">Exception</span> <span class=\"k\">as</span> <span class=\"n\">e</span><span class=\"p\">:</span>            \n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">error</span><span class=\"p\">(</span><span class=\"n\">e</span><span class=\"p\">)</span>\n            <span class=\"k\">return</span> <span class=\"s1\">&#39;&#39;</span>        </div>\n\n<div class=\"viewcode-block\" id=\"Conversation.play\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.Conversation.Conversation.play\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">play</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">src</span><span class=\"p\">,</span> <span class=\"n\">delete</span><span class=\"o\">=</span><span class=\"kc\">False</span><span class=\"p\">,</span> <span class=\"n\">onCompleted</span><span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">,</span> <span class=\"n\">volume</span><span class=\"o\">=</span><span class=\"mi\">1</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot; 播放一个音频 &quot;&quot;&quot;</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">player</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">interrupt</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">player</span> <span class=\"o\">=</span> <span class=\"n\">Player</span><span class=\"o\">.</span><span class=\"n\">SoxPlayer</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">player</span><span class=\"o\">.</span><span class=\"n\">play</span><span class=\"p\">(</span><span class=\"n\">src</span><span class=\"p\">,</span> <span class=\"n\">delete</span><span class=\"p\">,</span> <span class=\"n\">onCompleted</span><span class=\"o\">=</span><span class=\"n\">onCompleted</span><span class=\"p\">,</span> <span class=\"n\">volume</span><span class=\"o\">=</span><span class=\"n\">volume</span><span class=\"p\">)</span></div></div>\n    \n</pre></div>\n\n           </div>\n           \n          </div>\n          <footer>\n  \n\n  <hr/>\n\n  <div role=\"contentinfo\">\n    <p>\n        &copy; Copyright 2019, wzpan\n\n    </p>\n  </div>\n  Built with <a href=\"http://sphinx-doc.org/\">Sphinx</a> using a <a href=\"https://github.com/rtfd/sphinx_rtd_theme\">theme</a> provided by <a href=\"https://readthedocs.org\">Read the Docs</a>. \n\n</footer>\n\n        </div>\n      </div>\n\n    </section>\n\n  </div>\n  \n\n\n  <script type=\"text/javascript\">\n      jQuery(function () {\n          SphinxRtdTheme.Navigation.enable(true);\n      });\n  </script>\n\n  \n  \n    \n   \n\n</body>\n</html>"
  },
  {
    "path": "docs/_modules/robot/NLU.html",
    "content": "\n\n<!DOCTYPE html>\n<!--[if IE 8]><html class=\"no-js lt-ie9\" lang=\"zh-CN\" > <![endif]-->\n<!--[if gt IE 8]><!--> <html class=\"no-js\" lang=\"zh-CN\" > <!--<![endif]-->\n<head>\n  <meta charset=\"utf-8\">\n  \n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  \n  <title>robot.NLU &mdash; wukong-robot 1.2.0 文档</title>\n  \n\n  \n  \n  \n  \n\n  \n  <script type=\"text/javascript\" src=\"../../_static/js/modernizr.min.js\"></script>\n  \n    \n      <script type=\"text/javascript\" id=\"documentation_options\" data-url_root=\"../../\" src=\"../../_static/documentation_options.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/jquery.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/underscore.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/doctools.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/language_data.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/translations.js\"></script>\n    \n    <script type=\"text/javascript\" src=\"../../_static/js/theme.js\"></script>\n\n    \n\n  \n  <link rel=\"stylesheet\" href=\"../../_static/css/theme.css\" type=\"text/css\" />\n  <link rel=\"stylesheet\" href=\"../../_static/pygments.css\" type=\"text/css\" />\n    <link rel=\"index\" title=\"索引\" href=\"../../genindex.html\" />\n    <link rel=\"search\" title=\"搜索\" href=\"../../search.html\" /> \n</head>\n\n<body class=\"wy-body-for-nav\">\n\n   \n  <div class=\"wy-grid-for-nav\">\n    \n    <nav data-toggle=\"wy-nav-shift\" class=\"wy-nav-side\">\n      <div class=\"wy-side-scroll\">\n        <div class=\"wy-side-nav-search\" >\n          \n\n          \n            <a href=\"../../index.html\" class=\"icon icon-home\"> wukong-robot\n          \n\n          \n          </a>\n\n          \n            \n            \n          \n\n          \n<div role=\"search\">\n  <form id=\"rtd-search-form\" class=\"wy-form\" action=\"../../search.html\" method=\"get\">\n    <input type=\"text\" name=\"q\" placeholder=\"Search docs\" />\n    <input type=\"hidden\" name=\"check_keywords\" value=\"yes\" />\n    <input type=\"hidden\" name=\"area\" value=\"default\" />\n  </form>\n</div>\n\n          \n        </div>\n\n        <div class=\"wy-menu wy-menu-vertical\" data-spy=\"affix\" role=\"navigation\" aria-label=\"main navigation\">\n          \n            \n            \n              \n            \n            \n              <!-- Local TOC -->\n              <div class=\"local-toc\"></div>\n            \n          \n        </div>\n      </div>\n    </nav>\n\n    <section data-toggle=\"wy-nav-shift\" class=\"wy-nav-content-wrap\">\n\n      \n      <nav class=\"wy-nav-top\" aria-label=\"top navigation\">\n        \n          <i data-toggle=\"wy-nav-top\" class=\"fa fa-bars\"></i>\n          <a href=\"../../index.html\">wukong-robot</a>\n        \n      </nav>\n\n\n      <div class=\"wy-nav-content\">\n        \n        <div class=\"rst-content\">\n        \n          \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<div role=\"navigation\" aria-label=\"breadcrumbs navigation\">\n\n  <ul class=\"wy-breadcrumbs\">\n    \n      <li><a href=\"../../index.html\">Docs</a> &raquo;</li>\n        \n          <li><a href=\"../index.html\">模块代码</a> &raquo;</li>\n        \n      <li>robot.NLU</li>\n    \n    \n      <li class=\"wy-breadcrumbs-aside\">\n        \n      </li>\n    \n  </ul>\n\n  \n  <hr/>\n</div>\n          <div role=\"main\" class=\"document\" itemscope=\"itemscope\" itemtype=\"http://schema.org/Article\">\n           <div itemprop=\"articleBody\">\n            \n  <h1>robot.NLU 源代码</h1><div class=\"highlight\"><pre>\n<span></span><span class=\"c1\"># -*- coding: utf-8-*-</span>\n<span class=\"kn\">from</span> <span class=\"nn\">.sdk</span> <span class=\"k\">import</span> <span class=\"n\">unit</span>\n<span class=\"kn\">from</span> <span class=\"nn\">robot</span> <span class=\"k\">import</span> <span class=\"n\">logging</span>\n<span class=\"kn\">from</span> <span class=\"nn\">abc</span> <span class=\"k\">import</span> <span class=\"n\">ABCMeta</span><span class=\"p\">,</span> <span class=\"n\">abstractmethod</span>\n\n<span class=\"n\">logger</span> <span class=\"o\">=</span> <span class=\"n\">logging</span><span class=\"o\">.</span><span class=\"n\">getLogger</span><span class=\"p\">(</span><span class=\"vm\">__name__</span><span class=\"p\">)</span>\n\n<div class=\"viewcode-block\" id=\"AbstractNLU\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.NLU.AbstractNLU\">[文档]</a><span class=\"k\">class</span> <span class=\"nc\">AbstractNLU</span><span class=\"p\">(</span><span class=\"nb\">object</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    Generic parent class for all NLU engines</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n\n    <span class=\"n\">__metaclass__</span> <span class=\"o\">=</span> <span class=\"n\">ABCMeta</span>\n\n<div class=\"viewcode-block\" id=\"AbstractNLU.get_config\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.NLU.AbstractNLU.get_config\">[文档]</a>    <span class=\"nd\">@classmethod</span>\n    <span class=\"k\">def</span> <span class=\"nf\">get_config</span><span class=\"p\">(</span><span class=\"bp\">cls</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"p\">{}</span></div>\n\n<div class=\"viewcode-block\" id=\"AbstractNLU.get_instance\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.NLU.AbstractNLU.get_instance\">[文档]</a>    <span class=\"nd\">@classmethod</span>\n    <span class=\"k\">def</span> <span class=\"nf\">get_instance</span><span class=\"p\">(</span><span class=\"bp\">cls</span><span class=\"p\">):</span>\n        <span class=\"n\">profile</span> <span class=\"o\">=</span> <span class=\"bp\">cls</span><span class=\"o\">.</span><span class=\"n\">get_config</span><span class=\"p\">()</span>\n        <span class=\"n\">instance</span> <span class=\"o\">=</span> <span class=\"bp\">cls</span><span class=\"p\">(</span><span class=\"o\">**</span><span class=\"n\">profile</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span> <span class=\"n\">instance</span></div>\n\n<div class=\"viewcode-block\" id=\"AbstractNLU.parse\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.NLU.AbstractNLU.parse\">[文档]</a>    <span class=\"nd\">@abstractmethod</span>\n    <span class=\"k\">def</span> <span class=\"nf\">parse</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">query</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">args</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        进行 NLU 解析</span>\n\n<span class=\"sd\">        :param query: 用户的指令字符串</span>\n<span class=\"sd\">        :param **args: 可选的参数</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"k\">return</span> <span class=\"kc\">None</span></div>\n\n<div class=\"viewcode-block\" id=\"AbstractNLU.getIntent\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.NLU.AbstractNLU.getIntent\">[文档]</a>    <span class=\"nd\">@abstractmethod</span>\n    <span class=\"k\">def</span> <span class=\"nf\">getIntent</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">parsed</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot; </span>\n<span class=\"sd\">        提取意图</span>\n\n<span class=\"sd\">        :param parsed: 解析结果</span>\n<span class=\"sd\">        :returns: 意图数组</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"k\">return</span> <span class=\"kc\">None</span></div>\n\n<div class=\"viewcode-block\" id=\"AbstractNLU.hasIntent\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.NLU.AbstractNLU.hasIntent\">[文档]</a>    <span class=\"nd\">@abstractmethod</span>\n    <span class=\"k\">def</span> <span class=\"nf\">hasIntent</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">parsed</span><span class=\"p\">,</span> <span class=\"n\">intent</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot; </span>\n<span class=\"sd\">        判断是否包含某个意图</span>\n\n<span class=\"sd\">        :param parsed: 解析结果</span>\n<span class=\"sd\">        :param intent: 意图的名称</span>\n<span class=\"sd\">        :returns: True: 包含; False: 不包含</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"k\">return</span> <span class=\"kc\">False</span></div>\n\n<div class=\"viewcode-block\" id=\"AbstractNLU.getSlots\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.NLU.AbstractNLU.getSlots\">[文档]</a>    <span class=\"nd\">@abstractmethod</span>\n    <span class=\"k\">def</span> <span class=\"nf\">getSlots</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">parsed</span><span class=\"p\">,</span> <span class=\"n\">intent</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot; </span>\n<span class=\"sd\">        提取某个意图的所有词槽</span>\n<span class=\"sd\">    </span>\n<span class=\"sd\">        :param parsed: 解析结果</span>\n<span class=\"sd\">        :param intent: 意图的名称</span>\n<span class=\"sd\">        :returns: 词槽列表。你可以通过 name 属性筛选词槽，</span>\n<span class=\"sd\">        再通过 normalized_word 属性取出相应的值</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"k\">return</span> <span class=\"kc\">None</span></div>\n\n<div class=\"viewcode-block\" id=\"AbstractNLU.getSlotWords\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.NLU.AbstractNLU.getSlotWords\">[文档]</a>    <span class=\"nd\">@abstractmethod</span>\n    <span class=\"k\">def</span> <span class=\"nf\">getSlotWords</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">parsed</span><span class=\"p\">,</span> <span class=\"n\">intent</span><span class=\"p\">,</span> <span class=\"n\">name</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot; </span>\n<span class=\"sd\">        找出命中某个词槽的内容</span>\n<span class=\"sd\">    </span>\n<span class=\"sd\">        :param parsed: 解析结果</span>\n<span class=\"sd\">        :param intent: 意图的名称</span>\n<span class=\"sd\">        :param name: 词槽名</span>\n<span class=\"sd\">        :returns: 命中该词槽的值的列表。</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"k\">return</span> <span class=\"kc\">None</span></div>\n\n<div class=\"viewcode-block\" id=\"AbstractNLU.getSay\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.NLU.AbstractNLU.getSay\">[文档]</a>    <span class=\"nd\">@abstractmethod</span>\n    <span class=\"k\">def</span> <span class=\"nf\">getSay</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">parsed</span><span class=\"p\">,</span> <span class=\"n\">intent</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        提取回复文本</span>\n\n<span class=\"sd\">        :param parsed: 解析结果</span>\n<span class=\"sd\">        :param intent: 意图的名称</span>\n<span class=\"sd\">        :returns: 回复文本</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"k\">return</span> <span class=\"s2\">&quot;&quot;</span></div></div>\n\n\n<div class=\"viewcode-block\" id=\"UnitNLU\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.NLU.UnitNLU\">[文档]</a><span class=\"k\">class</span> <span class=\"nc\">UnitNLU</span><span class=\"p\">(</span><span class=\"n\">AbstractNLU</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    百度UNIT的NLU API.</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n\n    <span class=\"n\">SLUG</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;unit&quot;</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"nb\">super</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"vm\">__class__</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">)</span><span class=\"o\">.</span><span class=\"fm\">__init__</span><span class=\"p\">()</span>\n\n<div class=\"viewcode-block\" id=\"UnitNLU.get_config\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.NLU.UnitNLU.get_config\">[文档]</a>    <span class=\"nd\">@classmethod</span>\n    <span class=\"k\">def</span> <span class=\"nf\">get_config</span><span class=\"p\">(</span><span class=\"bp\">cls</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        百度UNIT的配置</span>\n\n<span class=\"sd\">        无需配置，所以返回 {}</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"k\">return</span> <span class=\"p\">{}</span></div>\n\n<div class=\"viewcode-block\" id=\"UnitNLU.parse\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.NLU.UnitNLU.parse\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">parse</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">query</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">args</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        使用百度 UNIT 进行 NLU 解析</span>\n\n<span class=\"sd\">        :param query: 用户的指令字符串</span>\n<span class=\"sd\">        :param **args: UNIT 的相关参数</span>\n<span class=\"sd\">            - service_id: UNIT 的 service_id</span>\n<span class=\"sd\">            - api_key: UNIT apk_key</span>\n<span class=\"sd\">            - secret_key: UNIT secret_key</span>\n<span class=\"sd\">        :returns: UNIT 解析结果。如果解析失败，返回 None</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"k\">if</span> <span class=\"s1\">&#39;service_id&#39;</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"n\">args</span> <span class=\"ow\">or</span> \\\n           <span class=\"s1\">&#39;api_key&#39;</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"n\">args</span> <span class=\"ow\">or</span> \\\n           <span class=\"s1\">&#39;secret_key&#39;</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"n\">args</span><span class=\"p\">:</span>\n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">critical</span><span class=\"p\">(</span><span class=\"s1\">&#39;</span><span class=\"si\">{}</span><span class=\"s1\"> NLU 失败：参数错误！&#39;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">SLUG</span><span class=\"p\">))</span>\n            <span class=\"k\">return</span> <span class=\"kc\">None</span>\n        <span class=\"k\">return</span> <span class=\"n\">unit</span><span class=\"o\">.</span><span class=\"n\">getUnit</span><span class=\"p\">(</span><span class=\"n\">query</span><span class=\"p\">,</span>\n                            <span class=\"n\">args</span><span class=\"p\">[</span><span class=\"s1\">&#39;service_id&#39;</span><span class=\"p\">],</span>\n                            <span class=\"n\">args</span><span class=\"p\">[</span><span class=\"s1\">&#39;api_key&#39;</span><span class=\"p\">],</span>\n                            <span class=\"n\">args</span><span class=\"p\">[</span><span class=\"s1\">&#39;secret_key&#39;</span><span class=\"p\">])</span></div>\n\n<div class=\"viewcode-block\" id=\"UnitNLU.getIntent\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.NLU.UnitNLU.getIntent\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">getIntent</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">parsed</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot; </span>\n<span class=\"sd\">        提取意图</span>\n\n<span class=\"sd\">        :param parsed: 解析结果</span>\n<span class=\"sd\">        :returns: 意图数组</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"k\">return</span> <span class=\"n\">unit</span><span class=\"o\">.</span><span class=\"n\">getIntent</span><span class=\"p\">(</span><span class=\"n\">parsed</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"UnitNLU.hasIntent\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.NLU.UnitNLU.hasIntent\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">hasIntent</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">parsed</span><span class=\"p\">,</span> <span class=\"n\">intent</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot; </span>\n<span class=\"sd\">        判断是否包含某个意图</span>\n\n<span class=\"sd\">        :param parsed: UNIT 解析结果</span>\n<span class=\"sd\">        :param intent: 意图的名称</span>\n<span class=\"sd\">        :returns: True: 包含; False: 不包含</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"k\">return</span> <span class=\"n\">unit</span><span class=\"o\">.</span><span class=\"n\">hasIntent</span><span class=\"p\">(</span><span class=\"n\">parsed</span><span class=\"p\">,</span> <span class=\"n\">intent</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"UnitNLU.getSlots\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.NLU.UnitNLU.getSlots\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">getSlots</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">parsed</span><span class=\"p\">,</span> <span class=\"n\">intent</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot; </span>\n<span class=\"sd\">        提取某个意图的所有词槽</span>\n<span class=\"sd\">    </span>\n<span class=\"sd\">        :param parsed: UNIT 解析结果</span>\n<span class=\"sd\">        :param intent: 意图的名称</span>\n<span class=\"sd\">        :returns: 词槽列表。你可以通过 name 属性筛选词槽，</span>\n<span class=\"sd\">        再通过 normalized_word 属性取出相应的值</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"k\">return</span> <span class=\"n\">unit</span><span class=\"o\">.</span><span class=\"n\">getSlots</span><span class=\"p\">(</span><span class=\"n\">parsed</span><span class=\"p\">,</span> <span class=\"n\">intent</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"UnitNLU.getSlotWords\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.NLU.UnitNLU.getSlotWords\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">getSlotWords</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">parsed</span><span class=\"p\">,</span> <span class=\"n\">intent</span><span class=\"p\">,</span> <span class=\"n\">name</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot; </span>\n<span class=\"sd\">        找出命中某个词槽的内容</span>\n<span class=\"sd\">    </span>\n<span class=\"sd\">        :param parsed: UNIT 解析结果</span>\n<span class=\"sd\">        :param intent: 意图的名称</span>\n<span class=\"sd\">        :param name: 词槽名</span>\n<span class=\"sd\">        :returns: 命中该词槽的值的列表。</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"k\">return</span> <span class=\"n\">unit</span><span class=\"o\">.</span><span class=\"n\">getSlotWords</span><span class=\"p\">(</span><span class=\"n\">parsed</span><span class=\"p\">,</span> <span class=\"n\">intent</span><span class=\"p\">,</span> <span class=\"n\">name</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"UnitNLU.getSay\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.NLU.UnitNLU.getSay\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">getSay</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">parsed</span><span class=\"p\">,</span> <span class=\"n\">intent</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        提取 UNIT 的回复文本</span>\n\n<span class=\"sd\">        :param parsed: UNIT 解析结果</span>\n<span class=\"sd\">        :param intent: 意图的名称</span>\n<span class=\"sd\">        :returns: UNIT 的回复文本</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"k\">return</span> <span class=\"n\">unit</span><span class=\"o\">.</span><span class=\"n\">getSay</span><span class=\"p\">(</span><span class=\"n\">parsed</span><span class=\"p\">,</span> <span class=\"n\">intent</span><span class=\"p\">)</span></div></div>\n\n\n<div class=\"viewcode-block\" id=\"get_engine_by_slug\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.NLU.get_engine_by_slug\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">get_engine_by_slug</span><span class=\"p\">(</span><span class=\"n\">slug</span><span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    Returns:</span>\n<span class=\"sd\">        An NLU Engine implementation available on the current platform</span>\n\n<span class=\"sd\">    Raises:</span>\n<span class=\"sd\">        ValueError if no speaker implementation is supported on this platform</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n\n    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">slug</span> <span class=\"ow\">or</span> <span class=\"nb\">type</span><span class=\"p\">(</span><span class=\"n\">slug</span><span class=\"p\">)</span> <span class=\"ow\">is</span> <span class=\"ow\">not</span> <span class=\"nb\">str</span><span class=\"p\">:</span>\n        <span class=\"k\">raise</span> <span class=\"ne\">TypeError</span><span class=\"p\">(</span><span class=\"s2\">&quot;无效的 NLU slug &#39;</span><span class=\"si\">%s</span><span class=\"s2\">&#39;&quot;</span><span class=\"p\">,</span> <span class=\"n\">slug</span><span class=\"p\">)</span>\n\n    <span class=\"n\">selected_engines</span> <span class=\"o\">=</span> <span class=\"nb\">list</span><span class=\"p\">(</span><span class=\"nb\">filter</span><span class=\"p\">(</span><span class=\"k\">lambda</span> <span class=\"n\">engine</span><span class=\"p\">:</span> <span class=\"nb\">hasattr</span><span class=\"p\">(</span><span class=\"n\">engine</span><span class=\"p\">,</span> <span class=\"s2\">&quot;SLUG&quot;</span><span class=\"p\">)</span> <span class=\"ow\">and</span>\n                              <span class=\"n\">engine</span><span class=\"o\">.</span><span class=\"n\">SLUG</span> <span class=\"o\">==</span> <span class=\"n\">slug</span><span class=\"p\">,</span> <span class=\"n\">get_engines</span><span class=\"p\">()))</span>\n\n    <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">selected_engines</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"k\">raise</span> <span class=\"ne\">ValueError</span><span class=\"p\">(</span><span class=\"s2\">&quot;错误：找不到名为 </span><span class=\"si\">{}</span><span class=\"s2\"> 的 NLU 引擎&quot;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">slug</span><span class=\"p\">))</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">selected_engines</span><span class=\"p\">)</span> <span class=\"o\">&gt;</span> <span class=\"mi\">1</span><span class=\"p\">:</span>\n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">warning</span><span class=\"p\">(</span><span class=\"s2\">&quot;注意: 有多个 NLU 名称与指定的引擎名 </span><span class=\"si\">{}</span><span class=\"s2\"> 匹配&quot;</span><span class=\"p\">)</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">slug</span><span class=\"p\">)</span>        \n        <span class=\"n\">engine</span> <span class=\"o\">=</span> <span class=\"n\">selected_engines</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n        <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s2\">&quot;使用 </span><span class=\"si\">{}</span><span class=\"s2\"> NLU 引擎&quot;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">engine</span><span class=\"o\">.</span><span class=\"n\">SLUG</span><span class=\"p\">))</span>\n        <span class=\"k\">return</span> <span class=\"n\">engine</span><span class=\"o\">.</span><span class=\"n\">get_instance</span><span class=\"p\">()</span></div>\n\n\n<div class=\"viewcode-block\" id=\"get_engines\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.NLU.get_engines\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">get_engines</span><span class=\"p\">():</span>\n    <span class=\"k\">def</span> <span class=\"nf\">get_subclasses</span><span class=\"p\">(</span><span class=\"bp\">cls</span><span class=\"p\">):</span>\n        <span class=\"n\">subclasses</span> <span class=\"o\">=</span> <span class=\"nb\">set</span><span class=\"p\">()</span>\n        <span class=\"k\">for</span> <span class=\"n\">subclass</span> <span class=\"ow\">in</span> <span class=\"bp\">cls</span><span class=\"o\">.</span><span class=\"n\">__subclasses__</span><span class=\"p\">():</span>\n            <span class=\"n\">subclasses</span><span class=\"o\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">subclass</span><span class=\"p\">)</span>\n            <span class=\"n\">subclasses</span><span class=\"o\">.</span><span class=\"n\">update</span><span class=\"p\">(</span><span class=\"n\">get_subclasses</span><span class=\"p\">(</span><span class=\"n\">subclass</span><span class=\"p\">))</span>\n        <span class=\"k\">return</span> <span class=\"n\">subclasses</span>\n    <span class=\"k\">return</span> <span class=\"p\">[</span><span class=\"n\">engine</span> <span class=\"k\">for</span> <span class=\"n\">engine</span> <span class=\"ow\">in</span>\n            <span class=\"nb\">list</span><span class=\"p\">(</span><span class=\"n\">get_subclasses</span><span class=\"p\">(</span><span class=\"n\">AbstractNLU</span><span class=\"p\">))</span>\n            <span class=\"k\">if</span> <span class=\"nb\">hasattr</span><span class=\"p\">(</span><span class=\"n\">engine</span><span class=\"p\">,</span> <span class=\"s1\">&#39;SLUG&#39;</span><span class=\"p\">)</span> <span class=\"ow\">and</span> <span class=\"n\">engine</span><span class=\"o\">.</span><span class=\"n\">SLUG</span><span class=\"p\">]</span></div>\n</pre></div>\n\n           </div>\n           \n          </div>\n          <footer>\n  \n\n  <hr/>\n\n  <div role=\"contentinfo\">\n    <p>\n        &copy; Copyright 2019, wzpan\n\n    </p>\n  </div>\n  Built with <a href=\"http://sphinx-doc.org/\">Sphinx</a> using a <a href=\"https://github.com/rtfd/sphinx_rtd_theme\">theme</a> provided by <a href=\"https://readthedocs.org\">Read the Docs</a>. \n\n</footer>\n\n        </div>\n      </div>\n\n    </section>\n\n  </div>\n  \n\n\n  <script type=\"text/javascript\">\n      jQuery(function () {\n          SphinxRtdTheme.Navigation.enable(true);\n      });\n  </script>\n\n  \n  \n    \n   \n\n</body>\n</html>"
  },
  {
    "path": "docs/_modules/robot/Player.html",
    "content": "\n\n<!DOCTYPE html>\n<!--[if IE 8]><html class=\"no-js lt-ie9\" lang=\"zh-CN\" > <![endif]-->\n<!--[if gt IE 8]><!--> <html class=\"no-js\" lang=\"zh-CN\" > <!--<![endif]-->\n<head>\n  <meta charset=\"utf-8\">\n  \n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  \n  <title>robot.Player &mdash; wukong-robot 1.2.0 文档</title>\n  \n\n  \n  \n  \n  \n\n  \n  <script type=\"text/javascript\" src=\"../../_static/js/modernizr.min.js\"></script>\n  \n    \n      <script type=\"text/javascript\" id=\"documentation_options\" data-url_root=\"../../\" src=\"../../_static/documentation_options.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/jquery.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/underscore.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/doctools.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/language_data.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/translations.js\"></script>\n    \n    <script type=\"text/javascript\" src=\"../../_static/js/theme.js\"></script>\n\n    \n\n  \n  <link rel=\"stylesheet\" href=\"../../_static/css/theme.css\" type=\"text/css\" />\n  <link rel=\"stylesheet\" href=\"../../_static/pygments.css\" type=\"text/css\" />\n    <link rel=\"index\" title=\"索引\" href=\"../../genindex.html\" />\n    <link rel=\"search\" title=\"搜索\" href=\"../../search.html\" /> \n</head>\n\n<body class=\"wy-body-for-nav\">\n\n   \n  <div class=\"wy-grid-for-nav\">\n    \n    <nav data-toggle=\"wy-nav-shift\" class=\"wy-nav-side\">\n      <div class=\"wy-side-scroll\">\n        <div class=\"wy-side-nav-search\" >\n          \n\n          \n            <a href=\"../../index.html\" class=\"icon icon-home\"> wukong-robot\n          \n\n          \n          </a>\n\n          \n            \n            \n          \n\n          \n<div role=\"search\">\n  <form id=\"rtd-search-form\" class=\"wy-form\" action=\"../../search.html\" method=\"get\">\n    <input type=\"text\" name=\"q\" placeholder=\"Search docs\" />\n    <input type=\"hidden\" name=\"check_keywords\" value=\"yes\" />\n    <input type=\"hidden\" name=\"area\" value=\"default\" />\n  </form>\n</div>\n\n          \n        </div>\n\n        <div class=\"wy-menu wy-menu-vertical\" data-spy=\"affix\" role=\"navigation\" aria-label=\"main navigation\">\n          \n            \n            \n              \n            \n            \n              <!-- Local TOC -->\n              <div class=\"local-toc\"></div>\n            \n          \n        </div>\n      </div>\n    </nav>\n\n    <section data-toggle=\"wy-nav-shift\" class=\"wy-nav-content-wrap\">\n\n      \n      <nav class=\"wy-nav-top\" aria-label=\"top navigation\">\n        \n          <i data-toggle=\"wy-nav-top\" class=\"fa fa-bars\"></i>\n          <a href=\"../../index.html\">wukong-robot</a>\n        \n      </nav>\n\n\n      <div class=\"wy-nav-content\">\n        \n        <div class=\"rst-content\">\n        \n          \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<div role=\"navigation\" aria-label=\"breadcrumbs navigation\">\n\n  <ul class=\"wy-breadcrumbs\">\n    \n      <li><a href=\"../../index.html\">Docs</a> &raquo;</li>\n        \n          <li><a href=\"../index.html\">模块代码</a> &raquo;</li>\n        \n      <li>robot.Player</li>\n    \n    \n      <li class=\"wy-breadcrumbs-aside\">\n        \n      </li>\n    \n  </ul>\n\n  \n  <hr/>\n</div>\n          <div role=\"main\" class=\"document\" itemscope=\"itemscope\" itemtype=\"http://schema.org/Article\">\n           <div itemprop=\"articleBody\">\n            \n  <h1>robot.Player 源代码</h1><div class=\"highlight\"><pre>\n<span></span><span class=\"c1\"># -*- coding: utf-8-*-</span>\n<span class=\"kn\">import</span> <span class=\"nn\">subprocess</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">import</span> <span class=\"nn\">platform</span>\n<span class=\"kn\">from</span> <span class=\"nn\">.</span> <span class=\"k\">import</span> <span class=\"n\">utils</span>\n<span class=\"kn\">import</span> <span class=\"nn\">_thread</span> <span class=\"k\">as</span> <span class=\"nn\">thread</span>\n<span class=\"kn\">from</span> <span class=\"nn\">robot</span> <span class=\"k\">import</span> <span class=\"n\">logging</span>\n<span class=\"kn\">from</span> <span class=\"nn\">ctypes</span> <span class=\"k\">import</span> <span class=\"n\">CFUNCTYPE</span><span class=\"p\">,</span> <span class=\"n\">c_char_p</span><span class=\"p\">,</span> <span class=\"n\">c_int</span><span class=\"p\">,</span> <span class=\"n\">cdll</span>\n<span class=\"kn\">from</span> <span class=\"nn\">contextlib</span> <span class=\"k\">import</span> <span class=\"n\">contextmanager</span>\n\n<span class=\"n\">logger</span> <span class=\"o\">=</span> <span class=\"n\">logging</span><span class=\"o\">.</span><span class=\"n\">getLogger</span><span class=\"p\">(</span><span class=\"vm\">__name__</span><span class=\"p\">)</span>\n\n<div class=\"viewcode-block\" id=\"py_error_handler\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.Player.py_error_handler\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">py_error_handler</span><span class=\"p\">(</span><span class=\"n\">filename</span><span class=\"p\">,</span> <span class=\"n\">line</span><span class=\"p\">,</span> <span class=\"n\">function</span><span class=\"p\">,</span> <span class=\"n\">err</span><span class=\"p\">,</span> <span class=\"n\">fmt</span><span class=\"p\">):</span>\n    <span class=\"k\">pass</span></div>\n\n<span class=\"n\">ERROR_HANDLER_FUNC</span> <span class=\"o\">=</span> <span class=\"n\">CFUNCTYPE</span><span class=\"p\">(</span><span class=\"kc\">None</span><span class=\"p\">,</span> <span class=\"n\">c_char_p</span><span class=\"p\">,</span> <span class=\"n\">c_int</span><span class=\"p\">,</span> <span class=\"n\">c_char_p</span><span class=\"p\">,</span> <span class=\"n\">c_int</span><span class=\"p\">,</span> <span class=\"n\">c_char_p</span><span class=\"p\">)</span>\n\n<span class=\"n\">c_error_handler</span> <span class=\"o\">=</span> <span class=\"n\">ERROR_HANDLER_FUNC</span><span class=\"p\">(</span><span class=\"n\">py_error_handler</span><span class=\"p\">)</span>\n\n<div class=\"viewcode-block\" id=\"no_alsa_error\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.Player.no_alsa_error\">[文档]</a><span class=\"nd\">@contextmanager</span>\n<span class=\"k\">def</span> <span class=\"nf\">no_alsa_error</span><span class=\"p\">():</span>\n    <span class=\"k\">try</span><span class=\"p\">:</span>\n        <span class=\"n\">asound</span> <span class=\"o\">=</span> <span class=\"n\">cdll</span><span class=\"o\">.</span><span class=\"n\">LoadLibrary</span><span class=\"p\">(</span><span class=\"s1\">&#39;libasound.so&#39;</span><span class=\"p\">)</span>\n        <span class=\"n\">asound</span><span class=\"o\">.</span><span class=\"n\">snd_lib_error_set_handler</span><span class=\"p\">(</span><span class=\"n\">c_error_handler</span><span class=\"p\">)</span>\n        <span class=\"k\">yield</span>\n        <span class=\"n\">asound</span><span class=\"o\">.</span><span class=\"n\">snd_lib_error_set_handler</span><span class=\"p\">(</span><span class=\"kc\">None</span><span class=\"p\">)</span>\n    <span class=\"k\">except</span><span class=\"p\">:</span>\n        <span class=\"k\">yield</span>\n        <span class=\"k\">pass</span></div>\n\n<div class=\"viewcode-block\" id=\"play\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.Player.play\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">play</span><span class=\"p\">(</span><span class=\"n\">fname</span><span class=\"p\">,</span> <span class=\"n\">onCompleted</span><span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">):</span>\n    <span class=\"n\">player</span> <span class=\"o\">=</span> <span class=\"n\">getPlayerByFileName</span><span class=\"p\">(</span><span class=\"n\">fname</span><span class=\"p\">)</span>\n    <span class=\"n\">player</span><span class=\"o\">.</span><span class=\"n\">play</span><span class=\"p\">(</span><span class=\"n\">fname</span><span class=\"p\">,</span> <span class=\"n\">onCompleted</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"getPlayerByFileName\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.Player.getPlayerByFileName\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">getPlayerByFileName</span><span class=\"p\">(</span><span class=\"n\">fname</span><span class=\"p\">):</span>\n    <span class=\"n\">foo</span><span class=\"p\">,</span> <span class=\"n\">ext</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">splitext</span><span class=\"p\">(</span><span class=\"n\">fname</span><span class=\"p\">)</span>\n    <span class=\"k\">if</span> <span class=\"n\">ext</span> <span class=\"ow\">in</span> <span class=\"p\">[</span><span class=\"s1\">&#39;.mp3&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;.wav&#39;</span><span class=\"p\">]:</span>\n        <span class=\"k\">return</span> <span class=\"n\">SoxPlayer</span><span class=\"p\">()</span></div>\n\n<div class=\"viewcode-block\" id=\"AbstractPlayer\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.Player.AbstractPlayer\">[文档]</a><span class=\"k\">class</span> <span class=\"nc\">AbstractPlayer</span><span class=\"p\">(</span><span class=\"nb\">object</span><span class=\"p\">):</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">):</span>\n        <span class=\"nb\">super</span><span class=\"p\">(</span><span class=\"n\">AbstractPlayer</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">)</span><span class=\"o\">.</span><span class=\"fm\">__init__</span><span class=\"p\">()</span>\n\n<div class=\"viewcode-block\" id=\"AbstractPlayer.play\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.Player.AbstractPlayer.play\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">play</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">pass</span></div>\n\n<div class=\"viewcode-block\" id=\"AbstractPlayer.play_block\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.Player.AbstractPlayer.play_block\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">play_block</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">pass</span></div>\n\n<div class=\"viewcode-block\" id=\"AbstractPlayer.stop\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.Player.AbstractPlayer.stop\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">stop</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">pass</span></div>\n\n<div class=\"viewcode-block\" id=\"AbstractPlayer.is_playing\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.Player.AbstractPlayer.is_playing\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">is_playing</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"kc\">False</span></div></div>\n    \n\n<div class=\"viewcode-block\" id=\"SoxPlayer\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.Player.SoxPlayer\">[文档]</a><span class=\"k\">class</span> <span class=\"nc\">SoxPlayer</span><span class=\"p\">(</span><span class=\"n\">AbstractPlayer</span><span class=\"p\">):</span>\n    <span class=\"n\">SLUG</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;SoxPlayer&#39;</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">):</span>\n        <span class=\"nb\">super</span><span class=\"p\">(</span><span class=\"n\">SoxPlayer</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">)</span><span class=\"o\">.</span><span class=\"fm\">__init__</span><span class=\"p\">(</span><span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">playing</span> <span class=\"o\">=</span> <span class=\"kc\">False</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">proc</span> <span class=\"o\">=</span> <span class=\"kc\">None</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">delete</span> <span class=\"o\">=</span> <span class=\"kc\">False</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">onCompleteds</span> <span class=\"o\">=</span> <span class=\"p\">[]</span>\n\n<div class=\"viewcode-block\" id=\"SoxPlayer.doPlay\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.Player.SoxPlayer.doPlay\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">doPlay</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"n\">cmd</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s1\">&#39;play&#39;</span><span class=\"p\">,</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">src</span><span class=\"p\">)]</span>\n        <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">debug</span><span class=\"p\">(</span><span class=\"s1\">&#39;Executing </span><span class=\"si\">%s</span><span class=\"s1\">&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39; &#39;</span><span class=\"o\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">cmd</span><span class=\"p\">))</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">proc</span> <span class=\"o\">=</span> <span class=\"n\">subprocess</span><span class=\"o\">.</span><span class=\"n\">Popen</span><span class=\"p\">(</span><span class=\"n\">cmd</span><span class=\"p\">,</span> <span class=\"n\">stdout</span><span class=\"o\">=</span><span class=\"n\">subprocess</span><span class=\"o\">.</span><span class=\"n\">DEVNULL</span><span class=\"p\">,</span> <span class=\"n\">stderr</span><span class=\"o\">=</span><span class=\"n\">subprocess</span><span class=\"o\">.</span><span class=\"n\">DEVNULL</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">playing</span> <span class=\"o\">=</span> <span class=\"kc\">True</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">proc</span><span class=\"o\">.</span><span class=\"n\">wait</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">playing</span> <span class=\"o\">=</span> <span class=\"kc\">False</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">delete</span><span class=\"p\">:</span>\n            <span class=\"n\">utils</span><span class=\"o\">.</span><span class=\"n\">check_and_delete</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">src</span><span class=\"p\">)</span>\n        <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">debug</span><span class=\"p\">(</span><span class=\"s1\">&#39;play completed&#39;</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">proc</span><span class=\"o\">.</span><span class=\"n\">returncode</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"k\">for</span> <span class=\"n\">onCompleted</span> <span class=\"ow\">in</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">onCompleteds</span><span class=\"p\">:</span>\n                <span class=\"k\">if</span> <span class=\"n\">onCompleted</span><span class=\"p\">:</span>                \n                    <span class=\"n\">onCompleted</span><span class=\"p\">()</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">onCompleteds</span> <span class=\"o\">=</span> <span class=\"p\">[]</span></div>\n    \n<div class=\"viewcode-block\" id=\"SoxPlayer.play\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.Player.SoxPlayer.play\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">play</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">src</span><span class=\"p\">,</span> <span class=\"n\">delete</span><span class=\"o\">=</span><span class=\"kc\">False</span><span class=\"p\">,</span> <span class=\"n\">onCompleted</span><span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">,</span> <span class=\"n\">wait</span><span class=\"o\">=</span><span class=\"kc\">False</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">exists</span><span class=\"p\">(</span><span class=\"n\">src</span><span class=\"p\">)):</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">src</span> <span class=\"o\">=</span> <span class=\"n\">src</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">delete</span> <span class=\"o\">=</span> <span class=\"n\">delete</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">onCompleteds</span><span class=\"o\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">onCompleted</span><span class=\"p\">)</span>\n            <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">wait</span><span class=\"p\">:</span>\n                <span class=\"n\">thread</span><span class=\"o\">.</span><span class=\"n\">start_new_thread</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">doPlay</span><span class=\"p\">,</span> <span class=\"p\">())</span>\n            <span class=\"k\">else</span><span class=\"p\">:</span>\n                <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">doPlay</span><span class=\"p\">()</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">critical</span><span class=\"p\">(</span><span class=\"s1\">&#39;path not exists: </span><span class=\"si\">{}</span><span class=\"s1\">&#39;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">src</span><span class=\"p\">))</span></div>\n\n<div class=\"viewcode-block\" id=\"SoxPlayer.appendOnCompleted\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.Player.SoxPlayer.appendOnCompleted\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">appendOnCompleted</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">onCompleted</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"n\">onCompleted</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">onCompleteds</span><span class=\"o\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">onCompleted</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"SoxPlayer.play_block\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.Player.SoxPlayer.play_block\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">play_block</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">()</span></div>\n\n<div class=\"viewcode-block\" id=\"SoxPlayer.stop\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.Player.SoxPlayer.stop\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">stop</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">proc</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">onCompleteds</span> <span class=\"o\">=</span> <span class=\"p\">[]</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">proc</span><span class=\"o\">.</span><span class=\"n\">terminate</span><span class=\"p\">()</span>\n            <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">delete</span><span class=\"p\">:</span>\n                <span class=\"n\">utils</span><span class=\"o\">.</span><span class=\"n\">check_and_delete</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">src</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"SoxPlayer.is_playing\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.Player.SoxPlayer.is_playing\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">is_playing</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">playing</span></div></div>\n\n\n<div class=\"viewcode-block\" id=\"MusicPlayer\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.Player.MusicPlayer\">[文档]</a><span class=\"k\">class</span> <span class=\"nc\">MusicPlayer</span><span class=\"p\">(</span><span class=\"n\">SoxPlayer</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    给音乐播放器插件使用的，</span>\n<span class=\"sd\">    在 SOXPlayer 的基础上增加了列表的支持，</span>\n<span class=\"sd\">    并支持暂停和恢复播放</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"n\">SLUG</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;MusicPlayer&#39;</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">playlist</span><span class=\"p\">,</span> <span class=\"n\">plugin</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">):</span>\n        <span class=\"nb\">super</span><span class=\"p\">(</span><span class=\"n\">MusicPlayer</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">)</span><span class=\"o\">.</span><span class=\"fm\">__init__</span><span class=\"p\">(</span><span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">playlist</span> <span class=\"o\">=</span> <span class=\"n\">playlist</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">plugin</span> <span class=\"o\">=</span> <span class=\"n\">plugin</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">idx</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">pausing</span> <span class=\"o\">=</span> <span class=\"kc\">False</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">last_paused</span> <span class=\"o\">=</span> <span class=\"kc\">None</span>\n\n<div class=\"viewcode-block\" id=\"MusicPlayer.update_playlist\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.Player.MusicPlayer.update_playlist\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">update_playlist</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">playlist</span><span class=\"p\">):</span>\n        <span class=\"nb\">super</span><span class=\"p\">()</span><span class=\"o\">.</span><span class=\"n\">stop</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">playlist</span> <span class=\"o\">=</span> <span class=\"n\">playlist</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">idx</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">play</span><span class=\"p\">()</span></div>\n\n<div class=\"viewcode-block\" id=\"MusicPlayer.play\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.Player.MusicPlayer.play\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">play</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">debug</span><span class=\"p\">(</span><span class=\"s1\">&#39;MusicPlayer play&#39;</span><span class=\"p\">)</span>\n        <span class=\"n\">path</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">playlist</span><span class=\"p\">[</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">idx</span><span class=\"p\">]</span>\n        <span class=\"nb\">super</span><span class=\"p\">()</span><span class=\"o\">.</span><span class=\"n\">stop</span><span class=\"p\">()</span>\n        <span class=\"nb\">super</span><span class=\"p\">()</span><span class=\"o\">.</span><span class=\"n\">play</span><span class=\"p\">(</span><span class=\"n\">path</span><span class=\"p\">,</span> <span class=\"kc\">False</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">next</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"MusicPlayer.next\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.Player.MusicPlayer.next\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">next</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">debug</span><span class=\"p\">(</span><span class=\"s1\">&#39;MusicPlayer next&#39;</span><span class=\"p\">)</span>\n        <span class=\"nb\">super</span><span class=\"p\">()</span><span class=\"o\">.</span><span class=\"n\">stop</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">idx</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">idx</span><span class=\"o\">+</span><span class=\"mi\">1</span><span class=\"p\">)</span> <span class=\"o\">%</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">playlist</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">play</span><span class=\"p\">()</span></div>\n\n<div class=\"viewcode-block\" id=\"MusicPlayer.prev\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.Player.MusicPlayer.prev\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">prev</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">debug</span><span class=\"p\">(</span><span class=\"s1\">&#39;MusicPlayer prev&#39;</span><span class=\"p\">)</span>\n        <span class=\"nb\">super</span><span class=\"p\">()</span><span class=\"o\">.</span><span class=\"n\">stop</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">idx</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">idx</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">)</span> <span class=\"o\">%</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">playlist</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">play</span><span class=\"p\">()</span></div>\n\n<div class=\"viewcode-block\" id=\"MusicPlayer.pause\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.Player.MusicPlayer.pause\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">pause</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">debug</span><span class=\"p\">(</span><span class=\"s1\">&#39;MusicPlayer pause&#39;</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">pausing</span> <span class=\"o\">=</span> <span class=\"kc\">True</span></div>\n\n<div class=\"viewcode-block\" id=\"MusicPlayer.stop\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.Player.MusicPlayer.stop\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">stop</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">proc</span><span class=\"p\">:</span>\n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">debug</span><span class=\"p\">(</span><span class=\"s1\">&#39;MusicPlayer stop&#39;</span><span class=\"p\">)</span>\n            <span class=\"c1\"># STOP current play process</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">last_paused</span> <span class=\"o\">=</span> <span class=\"n\">utils</span><span class=\"o\">.</span><span class=\"n\">write_temp_file</span><span class=\"p\">(</span><span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">proc</span><span class=\"o\">.</span><span class=\"n\">pid</span><span class=\"p\">),</span> <span class=\"s1\">&#39;pid&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;w&#39;</span><span class=\"p\">)</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">onCompleteds</span> <span class=\"o\">=</span> <span class=\"p\">[]</span>\n            <span class=\"n\">subprocess</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">([</span><span class=\"s1\">&#39;pkill&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;-STOP&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;-F&#39;</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">last_paused</span><span class=\"p\">])</span></div>\n\n<div class=\"viewcode-block\" id=\"MusicPlayer.resume\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.Player.MusicPlayer.resume\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">resume</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">debug</span><span class=\"p\">(</span><span class=\"s1\">&#39;MusicPlayer resume&#39;</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">pausing</span> <span class=\"o\">=</span> <span class=\"kc\">False</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">onCompleteds</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">next</span><span class=\"p\">]</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">last_paused</span> <span class=\"ow\">is</span> <span class=\"ow\">not</span> <span class=\"kc\">None</span><span class=\"p\">:</span>\n            <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">last_paused</span><span class=\"p\">)</span>\n            <span class=\"n\">subprocess</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">([</span><span class=\"s1\">&#39;pkill&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;-CONT&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;-F&#39;</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">last_paused</span><span class=\"p\">])</span></div>\n\n<div class=\"viewcode-block\" id=\"MusicPlayer.is_playing\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.Player.MusicPlayer.is_playing\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">is_playing</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">playing</span></div>\n\n<div class=\"viewcode-block\" id=\"MusicPlayer.is_pausing\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.Player.MusicPlayer.is_pausing\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">is_pausing</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">pausing</span></div>\n\n<div class=\"viewcode-block\" id=\"MusicPlayer.turnUp\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.Player.MusicPlayer.turnUp\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">turnUp</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"n\">system</span> <span class=\"o\">=</span> <span class=\"n\">platform</span><span class=\"o\">.</span><span class=\"n\">system</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"n\">system</span> <span class=\"o\">==</span> <span class=\"s1\">&#39;Darwin&#39;</span><span class=\"p\">:</span>\n            <span class=\"n\">res</span> <span class=\"o\">=</span> <span class=\"n\">subprocess</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">([</span><span class=\"s1\">&#39;osascript&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;-e&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;output volume of (get volume settings)&#39;</span><span class=\"p\">],</span> <span class=\"n\">shell</span><span class=\"o\">=</span><span class=\"kc\">False</span><span class=\"p\">,</span> <span class=\"n\">capture_output</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">,</span> <span class=\"n\">text</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">)</span>\n            <span class=\"n\">volume</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">res</span><span class=\"o\">.</span><span class=\"n\">stdout</span><span class=\"o\">.</span><span class=\"n\">strip</span><span class=\"p\">())</span>\n            <span class=\"n\">volume</span> <span class=\"o\">+=</span> <span class=\"mi\">20</span>\n            <span class=\"k\">if</span> <span class=\"n\">volume</span> <span class=\"o\">&gt;=</span> <span class=\"mi\">100</span><span class=\"p\">:</span>\n                <span class=\"n\">volume</span> <span class=\"o\">=</span> <span class=\"mi\">100</span>\n                <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">plugin</span><span class=\"o\">.</span><span class=\"n\">say</span><span class=\"p\">(</span><span class=\"s1\">&#39;音量已经最大啦&#39;</span><span class=\"p\">,</span> <span class=\"n\">wait</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">)</span>\n            <span class=\"n\">subprocess</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">([</span><span class=\"s1\">&#39;osascript&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;-e&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;set volume output volume </span><span class=\"si\">{}</span><span class=\"s1\">&#39;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">volume</span><span class=\"p\">)])</span>\n        <span class=\"k\">elif</span> <span class=\"n\">system</span> <span class=\"o\">==</span> <span class=\"s1\">&#39;Linux&#39;</span><span class=\"p\">:</span>\n            <span class=\"n\">res</span> <span class=\"o\">=</span> <span class=\"n\">subprocess</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">([</span><span class=\"s2\">&quot;amixer sget Master | grep &#39;Mono:&#39; | awk -F&#39;[][]&#39; &#39;{ print $2 }&#39;&quot;</span><span class=\"p\">],</span> <span class=\"n\">shell</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">,</span> <span class=\"n\">capture_output</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">,</span> <span class=\"n\">text</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">)</span>\n            <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"n\">res</span><span class=\"o\">.</span><span class=\"n\">stdout</span><span class=\"p\">)</span>\n            <span class=\"k\">if</span> <span class=\"n\">res</span><span class=\"o\">.</span><span class=\"n\">stdout</span> <span class=\"o\">!=</span> <span class=\"s1\">&#39;&#39;</span> <span class=\"ow\">and</span> <span class=\"n\">res</span><span class=\"o\">.</span><span class=\"n\">stdout</span><span class=\"o\">.</span><span class=\"n\">strip</span><span class=\"p\">()</span><span class=\"o\">.</span><span class=\"n\">endswith</span><span class=\"p\">(</span><span class=\"s1\">&#39;%&#39;</span><span class=\"p\">):</span>\n                <span class=\"n\">volume</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">res</span><span class=\"o\">.</span><span class=\"n\">stdout</span><span class=\"o\">.</span><span class=\"n\">strip</span><span class=\"p\">()</span><span class=\"o\">.</span><span class=\"n\">replace</span><span class=\"p\">(</span><span class=\"s1\">&#39;%&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;&#39;</span><span class=\"p\">))</span>\n                <span class=\"n\">volume</span> <span class=\"o\">+=</span> <span class=\"mi\">20</span>\n                <span class=\"k\">if</span> <span class=\"n\">volume</span> <span class=\"o\">&gt;=</span> <span class=\"mi\">100</span><span class=\"p\">:</span>\n                    <span class=\"n\">volume</span> <span class=\"o\">=</span> <span class=\"mi\">100</span>\n                    <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">plugin</span><span class=\"o\">.</span><span class=\"n\">say</span><span class=\"p\">(</span><span class=\"s1\">&#39;音量已经最大啦&#39;</span><span class=\"p\">,</span> <span class=\"n\">wait</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">)</span>\n                <span class=\"n\">subprocess</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">([</span><span class=\"s1\">&#39;amixer&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;set&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;Master&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;</span><span class=\"si\">{}</span><span class=\"s1\">%&#39;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">volume</span><span class=\"p\">)])</span>\n            <span class=\"k\">else</span><span class=\"p\">:</span>\n                <span class=\"n\">subprocess</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">([</span><span class=\"s1\">&#39;amixer&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;set&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;Master&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;20%+&#39;</span><span class=\"p\">])</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">plugin</span><span class=\"o\">.</span><span class=\"n\">say</span><span class=\"p\">(</span><span class=\"s1\">&#39;当前系统不支持调节音量&#39;</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">resume</span><span class=\"p\">()</span></div>\n\n<div class=\"viewcode-block\" id=\"MusicPlayer.turnDown\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.Player.MusicPlayer.turnDown\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">turnDown</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"n\">system</span> <span class=\"o\">=</span> <span class=\"n\">platform</span><span class=\"o\">.</span><span class=\"n\">system</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"n\">system</span> <span class=\"o\">==</span> <span class=\"s1\">&#39;Darwin&#39;</span><span class=\"p\">:</span>\n            <span class=\"n\">res</span> <span class=\"o\">=</span> <span class=\"n\">subprocess</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">([</span><span class=\"s1\">&#39;osascript&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;-e&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;output volume of (get volume settings)&#39;</span><span class=\"p\">],</span> <span class=\"n\">shell</span><span class=\"o\">=</span><span class=\"kc\">False</span><span class=\"p\">,</span> <span class=\"n\">capture_output</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">,</span> <span class=\"n\">text</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">)</span>\n            <span class=\"n\">volume</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">res</span><span class=\"o\">.</span><span class=\"n\">stdout</span><span class=\"o\">.</span><span class=\"n\">strip</span><span class=\"p\">())</span>\n            <span class=\"n\">volume</span> <span class=\"o\">-=</span> <span class=\"mi\">20</span>\n            <span class=\"k\">if</span> <span class=\"n\">volume</span> <span class=\"o\">&lt;=</span> <span class=\"mi\">20</span><span class=\"p\">:</span>\n                <span class=\"n\">volume</span> <span class=\"o\">=</span> <span class=\"mi\">20</span>\n                <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">plugin</span><span class=\"o\">.</span><span class=\"n\">say</span><span class=\"p\">(</span><span class=\"s1\">&#39;音量已经很小啦&#39;</span><span class=\"p\">,</span> <span class=\"n\">wait</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">)</span>\n            <span class=\"n\">subprocess</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">([</span><span class=\"s1\">&#39;osascript&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;-e&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;set volume output volume </span><span class=\"si\">{}</span><span class=\"s1\">&#39;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">volume</span><span class=\"p\">)])</span>\n        <span class=\"k\">elif</span> <span class=\"n\">system</span> <span class=\"o\">==</span> <span class=\"s1\">&#39;Linux&#39;</span><span class=\"p\">:</span>\n            <span class=\"n\">res</span> <span class=\"o\">=</span> <span class=\"n\">subprocess</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">([</span><span class=\"s2\">&quot;amixer sget Master | grep &#39;Mono:&#39; | awk -F&#39;[][]&#39; &#39;{ print $2 }&#39;&quot;</span><span class=\"p\">],</span> <span class=\"n\">shell</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">,</span> <span class=\"n\">capture_output</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">,</span> <span class=\"n\">text</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">)</span>\n            <span class=\"k\">if</span> <span class=\"n\">res</span><span class=\"o\">.</span><span class=\"n\">stdout</span> <span class=\"o\">!=</span> <span class=\"s1\">&#39;&#39;</span> <span class=\"ow\">and</span> <span class=\"n\">res</span><span class=\"o\">.</span><span class=\"n\">stdout</span><span class=\"o\">.</span><span class=\"n\">endswith</span><span class=\"p\">(</span><span class=\"s1\">&#39;%&#39;</span><span class=\"p\">):</span>\n                <span class=\"n\">volume</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">res</span><span class=\"o\">.</span><span class=\"n\">stdout</span><span class=\"o\">.</span><span class=\"n\">replace</span><span class=\"p\">(</span><span class=\"s1\">&#39;%&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;&#39;</span><span class=\"p\">)</span><span class=\"o\">.</span><span class=\"n\">strip</span><span class=\"p\">())</span>\n                <span class=\"n\">volume</span> <span class=\"o\">-=</span> <span class=\"mi\">20</span>\n                <span class=\"k\">if</span> <span class=\"n\">volume</span> <span class=\"o\">&lt;=</span> <span class=\"mi\">20</span><span class=\"p\">:</span>\n                    <span class=\"n\">volume</span> <span class=\"o\">=</span> <span class=\"mi\">20</span>\n                    <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">plugin</span><span class=\"o\">.</span><span class=\"n\">say</span><span class=\"p\">(</span><span class=\"s1\">&#39;音量已经最小啦&#39;</span><span class=\"p\">,</span> <span class=\"n\">wait</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">)</span>\n                <span class=\"n\">subprocess</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">([</span><span class=\"s1\">&#39;amixer&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;set&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;Master&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;</span><span class=\"si\">{}</span><span class=\"s1\">%&#39;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">volume</span><span class=\"p\">)])</span>\n            <span class=\"k\">else</span><span class=\"p\">:</span>\n                <span class=\"n\">subprocess</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">([</span><span class=\"s1\">&#39;amixer&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;set&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;Master&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;20%-&#39;</span><span class=\"p\">])</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">plugin</span><span class=\"o\">.</span><span class=\"n\">say</span><span class=\"p\">(</span><span class=\"s1\">&#39;当前系统不支持调节音量&#39;</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">resume</span><span class=\"p\">()</span></div></div>\n</pre></div>\n\n           </div>\n           \n          </div>\n          <footer>\n  \n\n  <hr/>\n\n  <div role=\"contentinfo\">\n    <p>\n        &copy; Copyright 2019, wzpan\n\n    </p>\n  </div>\n  Built with <a href=\"http://sphinx-doc.org/\">Sphinx</a> using a <a href=\"https://github.com/rtfd/sphinx_rtd_theme\">theme</a> provided by <a href=\"https://readthedocs.org\">Read the Docs</a>. \n\n</footer>\n\n        </div>\n      </div>\n\n    </section>\n\n  </div>\n  \n\n\n  <script type=\"text/javascript\">\n      jQuery(function () {\n          SphinxRtdTheme.Navigation.enable(true);\n      });\n  </script>\n\n  \n  \n    \n   \n\n</body>\n</html>"
  },
  {
    "path": "docs/_modules/robot/TTS.html",
    "content": "\n\n<!DOCTYPE html>\n<!--[if IE 8]><html class=\"no-js lt-ie9\" lang=\"zh-CN\" > <![endif]-->\n<!--[if gt IE 8]><!--> <html class=\"no-js\" lang=\"zh-CN\" > <!--<![endif]-->\n<head>\n  <meta charset=\"utf-8\">\n  \n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  \n  <title>robot.TTS &mdash; wukong-robot 1.2.0 文档</title>\n  \n\n  \n  \n  \n  \n\n  \n  <script type=\"text/javascript\" src=\"../../_static/js/modernizr.min.js\"></script>\n  \n    \n      <script type=\"text/javascript\" id=\"documentation_options\" data-url_root=\"../../\" src=\"../../_static/documentation_options.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/jquery.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/underscore.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/doctools.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/language_data.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/translations.js\"></script>\n    \n    <script type=\"text/javascript\" src=\"../../_static/js/theme.js\"></script>\n\n    \n\n  \n  <link rel=\"stylesheet\" href=\"../../_static/css/theme.css\" type=\"text/css\" />\n  <link rel=\"stylesheet\" href=\"../../_static/pygments.css\" type=\"text/css\" />\n    <link rel=\"index\" title=\"索引\" href=\"../../genindex.html\" />\n    <link rel=\"search\" title=\"搜索\" href=\"../../search.html\" /> \n</head>\n\n<body class=\"wy-body-for-nav\">\n\n   \n  <div class=\"wy-grid-for-nav\">\n    \n    <nav data-toggle=\"wy-nav-shift\" class=\"wy-nav-side\">\n      <div class=\"wy-side-scroll\">\n        <div class=\"wy-side-nav-search\" >\n          \n\n          \n            <a href=\"../../index.html\" class=\"icon icon-home\"> wukong-robot\n          \n\n          \n          </a>\n\n          \n            \n            \n          \n\n          \n<div role=\"search\">\n  <form id=\"rtd-search-form\" class=\"wy-form\" action=\"../../search.html\" method=\"get\">\n    <input type=\"text\" name=\"q\" placeholder=\"Search docs\" />\n    <input type=\"hidden\" name=\"check_keywords\" value=\"yes\" />\n    <input type=\"hidden\" name=\"area\" value=\"default\" />\n  </form>\n</div>\n\n          \n        </div>\n\n        <div class=\"wy-menu wy-menu-vertical\" data-spy=\"affix\" role=\"navigation\" aria-label=\"main navigation\">\n          \n            \n            \n              \n            \n            \n              <!-- Local TOC -->\n              <div class=\"local-toc\"></div>\n            \n          \n        </div>\n      </div>\n    </nav>\n\n    <section data-toggle=\"wy-nav-shift\" class=\"wy-nav-content-wrap\">\n\n      \n      <nav class=\"wy-nav-top\" aria-label=\"top navigation\">\n        \n          <i data-toggle=\"wy-nav-top\" class=\"fa fa-bars\"></i>\n          <a href=\"../../index.html\">wukong-robot</a>\n        \n      </nav>\n\n\n      <div class=\"wy-nav-content\">\n        \n        <div class=\"rst-content\">\n        \n          \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<div role=\"navigation\" aria-label=\"breadcrumbs navigation\">\n\n  <ul class=\"wy-breadcrumbs\">\n    \n      <li><a href=\"../../index.html\">Docs</a> &raquo;</li>\n        \n          <li><a href=\"../index.html\">模块代码</a> &raquo;</li>\n        \n      <li>robot.TTS</li>\n    \n    \n      <li class=\"wy-breadcrumbs-aside\">\n        \n      </li>\n    \n  </ul>\n\n  \n  <hr/>\n</div>\n          <div role=\"main\" class=\"document\" itemscope=\"itemscope\" itemtype=\"http://schema.org/Article\">\n           <div itemprop=\"articleBody\">\n            \n  <h1>robot.TTS 源代码</h1><div class=\"highlight\"><pre>\n<span></span><span class=\"c1\"># -*- coding: utf-8-*-</span>\n<span class=\"kn\">from</span> <span class=\"nn\">aip</span> <span class=\"k\">import</span> <span class=\"n\">AipSpeech</span>\n<span class=\"kn\">from</span> <span class=\"nn\">.sdk</span> <span class=\"k\">import</span> <span class=\"n\">TencentSpeech</span><span class=\"p\">,</span> <span class=\"n\">AliSpeech</span>\n<span class=\"kn\">from</span> <span class=\"nn\">.</span> <span class=\"k\">import</span> <span class=\"n\">utils</span><span class=\"p\">,</span> <span class=\"n\">config</span>\n<span class=\"kn\">from</span> <span class=\"nn\">robot</span> <span class=\"k\">import</span> <span class=\"n\">logging</span>\n<span class=\"kn\">import</span> <span class=\"nn\">base64</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">requests</span>\n<span class=\"kn\">import</span> <span class=\"nn\">hashlib</span>\n<span class=\"kn\">from</span> <span class=\"nn\">abc</span> <span class=\"k\">import</span> <span class=\"n\">ABCMeta</span><span class=\"p\">,</span> <span class=\"n\">abstractmethod</span>\n\n<span class=\"n\">logger</span> <span class=\"o\">=</span> <span class=\"n\">logging</span><span class=\"o\">.</span><span class=\"n\">getLogger</span><span class=\"p\">(</span><span class=\"vm\">__name__</span><span class=\"p\">)</span>\n\n<div class=\"viewcode-block\" id=\"AbstractTTS\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.TTS.AbstractTTS\">[文档]</a><span class=\"k\">class</span> <span class=\"nc\">AbstractTTS</span><span class=\"p\">(</span><span class=\"nb\">object</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    Generic parent class for all TTS engines</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n\n    <span class=\"n\">__metaclass__</span> <span class=\"o\">=</span> <span class=\"n\">ABCMeta</span>\n\n<div class=\"viewcode-block\" id=\"AbstractTTS.get_config\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.TTS.AbstractTTS.get_config\">[文档]</a>    <span class=\"nd\">@classmethod</span>\n    <span class=\"k\">def</span> <span class=\"nf\">get_config</span><span class=\"p\">(</span><span class=\"bp\">cls</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"p\">{}</span></div>\n\n<div class=\"viewcode-block\" id=\"AbstractTTS.get_instance\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.TTS.AbstractTTS.get_instance\">[文档]</a>    <span class=\"nd\">@classmethod</span>\n    <span class=\"k\">def</span> <span class=\"nf\">get_instance</span><span class=\"p\">(</span><span class=\"bp\">cls</span><span class=\"p\">):</span>\n        <span class=\"n\">profile</span> <span class=\"o\">=</span> <span class=\"bp\">cls</span><span class=\"o\">.</span><span class=\"n\">get_config</span><span class=\"p\">()</span>\n        <span class=\"n\">instance</span> <span class=\"o\">=</span> <span class=\"bp\">cls</span><span class=\"p\">(</span><span class=\"o\">**</span><span class=\"n\">profile</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span> <span class=\"n\">instance</span></div>\n\n<div class=\"viewcode-block\" id=\"AbstractTTS.get_speech\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.TTS.AbstractTTS.get_speech\">[文档]</a>    <span class=\"nd\">@abstractmethod</span>\n    <span class=\"k\">def</span> <span class=\"nf\">get_speech</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">phrase</span><span class=\"p\">):</span>\n        <span class=\"k\">pass</span></div></div>\n\n<div class=\"viewcode-block\" id=\"BaiduTTS\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.TTS.BaiduTTS\">[文档]</a><span class=\"k\">class</span> <span class=\"nc\">BaiduTTS</span><span class=\"p\">(</span><span class=\"n\">AbstractTTS</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    使用百度语音合成技术</span>\n<span class=\"sd\">    要使用本模块, 首先到 yuyin.baidu.com 注册一个开发者账号,</span>\n<span class=\"sd\">    之后创建一个新应用, 然后在应用管理的&quot;查看key&quot;中获得 API Key 和 Secret Key</span>\n<span class=\"sd\">    填入 config.yml 中.</span>\n<span class=\"sd\">    ...</span>\n<span class=\"sd\">        baidu_yuyin: </span>\n<span class=\"sd\">            appid: &#39;9670645&#39;</span>\n<span class=\"sd\">            api_key: &#39;qg4haN8b2bGvFtCbBGqhrmZy&#39;</span>\n<span class=\"sd\">            secret_key: &#39;585d4eccb50d306c401d7df138bb02e7&#39;</span>\n<span class=\"sd\">            dev_pid: 1936</span>\n<span class=\"sd\">            per: 1</span>\n<span class=\"sd\">            lan: &#39;zh&#39;</span>\n<span class=\"sd\">        ...</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n\n    <span class=\"n\">SLUG</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;baidu-tts&quot;</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">appid</span><span class=\"p\">,</span> <span class=\"n\">api_key</span><span class=\"p\">,</span> <span class=\"n\">secret_key</span><span class=\"p\">,</span> <span class=\"n\">per</span><span class=\"o\">=</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"n\">lan</span><span class=\"o\">=</span><span class=\"s1\">&#39;zh&#39;</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">args</span><span class=\"p\">):</span>\n        <span class=\"nb\">super</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"vm\">__class__</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">)</span><span class=\"o\">.</span><span class=\"fm\">__init__</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">client</span> <span class=\"o\">=</span> <span class=\"n\">AipSpeech</span><span class=\"p\">(</span><span class=\"n\">appid</span><span class=\"p\">,</span> <span class=\"n\">api_key</span><span class=\"p\">,</span> <span class=\"n\">secret_key</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">per</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">lan</span> <span class=\"o\">=</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">per</span><span class=\"p\">),</span> <span class=\"n\">lan</span>\n\n<div class=\"viewcode-block\" id=\"BaiduTTS.get_config\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.TTS.BaiduTTS.get_config\">[文档]</a>    <span class=\"nd\">@classmethod</span>\n    <span class=\"k\">def</span> <span class=\"nf\">get_config</span><span class=\"p\">(</span><span class=\"bp\">cls</span><span class=\"p\">):</span>\n        <span class=\"c1\"># Try to get baidu_yuyin config from config</span>\n        <span class=\"k\">return</span> <span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;baidu_yuyin&#39;</span><span class=\"p\">,</span> <span class=\"p\">{})</span></div>\n\n<div class=\"viewcode-block\" id=\"BaiduTTS.get_speech\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.TTS.BaiduTTS.get_speech\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">get_speech</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">phrase</span><span class=\"p\">):</span>\n        <span class=\"n\">result</span>  <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">client</span><span class=\"o\">.</span><span class=\"n\">synthesis</span><span class=\"p\">(</span><span class=\"n\">phrase</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">lan</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"p\">{</span><span class=\"s1\">&#39;per&#39;</span><span class=\"p\">:</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">per</span><span class=\"p\">});</span>\n        <span class=\"c1\"># 识别正确返回语音二进制 错误则返回dict 参照下面错误码</span>\n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"nb\">isinstance</span><span class=\"p\">(</span><span class=\"n\">result</span><span class=\"p\">,</span> <span class=\"nb\">dict</span><span class=\"p\">):</span>\n            <span class=\"n\">tmpfile</span> <span class=\"o\">=</span> <span class=\"n\">utils</span><span class=\"o\">.</span><span class=\"n\">write_temp_file</span><span class=\"p\">(</span><span class=\"n\">result</span><span class=\"p\">,</span> <span class=\"s1\">&#39;.mp3&#39;</span><span class=\"p\">)</span>\n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s1\">&#39;</span><span class=\"si\">{}</span><span class=\"s1\"> 语音合成成功，合成路径：</span><span class=\"si\">{}</span><span class=\"s1\">&#39;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">SLUG</span><span class=\"p\">,</span> <span class=\"n\">tmpfile</span><span class=\"p\">))</span>\n            <span class=\"k\">return</span> <span class=\"n\">tmpfile</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">critical</span><span class=\"p\">(</span><span class=\"s1\">&#39;</span><span class=\"si\">{}</span><span class=\"s1\"> 合成失败！&#39;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">SLUG</span><span class=\"p\">),</span> <span class=\"n\">exc_info</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">)</span></div></div>\n\n\n<div class=\"viewcode-block\" id=\"TencentTTS\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.TTS.TencentTTS\">[文档]</a><span class=\"k\">class</span> <span class=\"nc\">TencentTTS</span><span class=\"p\">(</span><span class=\"n\">AbstractTTS</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    腾讯的语音合成</span>\n<span class=\"sd\">    region: 服务地域，挑个离自己最近的区域有助于提升速度。</span>\n<span class=\"sd\">        有效值：https://cloud.tencent.com/document/api/441/17365#.E5.9C.B0.E5.9F.9F.E5.88.97.E8.A1.A8</span>\n<span class=\"sd\">    voiceType:</span>\n<span class=\"sd\">        - 0：女声1，亲和风格(默认)</span>\n<span class=\"sd\">        - 1：男声1，成熟风格</span>\n<span class=\"sd\">        - 2：男声2，成熟风格</span>\n<span class=\"sd\">    language:</span>\n<span class=\"sd\">        - 1: 中文，最大100个汉字（标点符号算一个汉子）</span>\n<span class=\"sd\">        - 2: 英文，最大支持400个字母（标点符号算一个字母）</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n\n    <span class=\"n\">SLUG</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;tencent-tts&quot;</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">appid</span><span class=\"p\">,</span> <span class=\"n\">secretid</span><span class=\"p\">,</span> <span class=\"n\">secret_key</span><span class=\"p\">,</span> <span class=\"n\">region</span><span class=\"o\">=</span><span class=\"s1\">&#39;ap-guangzhou&#39;</span><span class=\"p\">,</span> <span class=\"n\">voiceType</span><span class=\"o\">=</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">language</span><span class=\"o\">=</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">args</span><span class=\"p\">):</span>\n        <span class=\"nb\">super</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"vm\">__class__</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">)</span><span class=\"o\">.</span><span class=\"fm\">__init__</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">engine</span> <span class=\"o\">=</span> <span class=\"n\">TencentSpeech</span><span class=\"o\">.</span><span class=\"n\">tencentSpeech</span><span class=\"p\">(</span><span class=\"n\">secret_key</span><span class=\"p\">,</span> <span class=\"n\">secretid</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">region</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">voiceType</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">language</span> <span class=\"o\">=</span> <span class=\"n\">region</span><span class=\"p\">,</span> <span class=\"n\">voiceType</span><span class=\"p\">,</span> <span class=\"n\">language</span>\n\n<div class=\"viewcode-block\" id=\"TencentTTS.get_config\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.TTS.TencentTTS.get_config\">[文档]</a>    <span class=\"nd\">@classmethod</span>\n    <span class=\"k\">def</span> <span class=\"nf\">get_config</span><span class=\"p\">(</span><span class=\"bp\">cls</span><span class=\"p\">):</span>\n        <span class=\"c1\"># Try to get tencent_yuyin config from config</span>\n        <span class=\"k\">return</span> <span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;tencent_yuyin&#39;</span><span class=\"p\">,</span> <span class=\"p\">{})</span></div>\n                \n<div class=\"viewcode-block\" id=\"TencentTTS.get_speech\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.TTS.TencentTTS.get_speech\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">get_speech</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">phrase</span><span class=\"p\">):</span>\n        <span class=\"n\">result</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">engine</span><span class=\"o\">.</span><span class=\"n\">TTS</span><span class=\"p\">(</span><span class=\"n\">phrase</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">voiceType</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">language</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">region</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"s1\">&#39;Response&#39;</span> <span class=\"ow\">in</span> <span class=\"n\">result</span> <span class=\"ow\">and</span> <span class=\"s1\">&#39;Audio&#39;</span> <span class=\"ow\">in</span> <span class=\"n\">result</span><span class=\"p\">[</span><span class=\"s1\">&#39;Response&#39;</span><span class=\"p\">]:</span>\n            <span class=\"n\">audio</span> <span class=\"o\">=</span> <span class=\"n\">result</span><span class=\"p\">[</span><span class=\"s1\">&#39;Response&#39;</span><span class=\"p\">][</span><span class=\"s1\">&#39;Audio&#39;</span><span class=\"p\">]</span>\n            <span class=\"n\">data</span> <span class=\"o\">=</span> <span class=\"n\">base64</span><span class=\"o\">.</span><span class=\"n\">b64decode</span><span class=\"p\">(</span><span class=\"n\">audio</span><span class=\"p\">)</span>\n            <span class=\"n\">tmpfile</span> <span class=\"o\">=</span> <span class=\"n\">utils</span><span class=\"o\">.</span><span class=\"n\">write_temp_file</span><span class=\"p\">(</span><span class=\"n\">data</span><span class=\"p\">,</span> <span class=\"s1\">&#39;.wav&#39;</span><span class=\"p\">)</span>\n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s1\">&#39;</span><span class=\"si\">{}</span><span class=\"s1\"> 语音合成成功，合成路径：</span><span class=\"si\">{}</span><span class=\"s1\">&#39;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">SLUG</span><span class=\"p\">,</span> <span class=\"n\">tmpfile</span><span class=\"p\">))</span>\n            <span class=\"k\">return</span> <span class=\"n\">tmpfile</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">critical</span><span class=\"p\">(</span><span class=\"s1\">&#39;</span><span class=\"si\">{}</span><span class=\"s1\"> 合成失败！&#39;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">SLUG</span><span class=\"p\">),</span> <span class=\"n\">exc_info</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">)</span></div></div>\n\n\n<div class=\"viewcode-block\" id=\"XunfeiTTS\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.TTS.XunfeiTTS\">[文档]</a><span class=\"k\">class</span> <span class=\"nc\">XunfeiTTS</span><span class=\"p\">(</span><span class=\"n\">AbstractTTS</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    科大讯飞的语音识别API.</span>\n<span class=\"sd\">    外网ip查询：https://ip.51240.com/</span>\n<span class=\"sd\">    voice_name: https://www.xfyun.cn/services/online_tts</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n\n    <span class=\"n\">SLUG</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;xunfei-tts&quot;</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">appid</span><span class=\"p\">,</span> <span class=\"n\">asr_api_key</span><span class=\"p\">,</span> <span class=\"n\">asr_api_secret</span><span class=\"p\">,</span> <span class=\"n\">tts_api_key</span><span class=\"p\">,</span> <span class=\"n\">voice</span><span class=\"o\">=</span><span class=\"s1\">&#39;xiaoyan&#39;</span><span class=\"p\">):</span>\n        <span class=\"nb\">super</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"vm\">__class__</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">)</span><span class=\"o\">.</span><span class=\"fm\">__init__</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">appid</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">api_key</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">voice_name</span> <span class=\"o\">=</span> <span class=\"n\">appid</span><span class=\"p\">,</span> <span class=\"n\">tts_api_key</span><span class=\"p\">,</span> <span class=\"n\">voice</span>\n\n<div class=\"viewcode-block\" id=\"XunfeiTTS.get_config\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.TTS.XunfeiTTS.get_config\">[文档]</a>    <span class=\"nd\">@classmethod</span>\n    <span class=\"k\">def</span> <span class=\"nf\">get_config</span><span class=\"p\">(</span><span class=\"bp\">cls</span><span class=\"p\">):</span>\n        <span class=\"c1\"># Try to get xunfei_yuyin config from config</span>\n        <span class=\"k\">return</span> <span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;xunfei_yuyin&#39;</span><span class=\"p\">,</span> <span class=\"p\">{})</span>     </div>\n\n<div class=\"viewcode-block\" id=\"XunfeiTTS.getHeader\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.TTS.XunfeiTTS.getHeader\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">getHeader</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">aue</span><span class=\"p\">):</span>\n        <span class=\"n\">curTime</span> <span class=\"o\">=</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"o\">.</span><span class=\"n\">time</span><span class=\"p\">()))</span>\n        <span class=\"c1\"># curTime = &#39;1526542623&#39;</span>\n        <span class=\"n\">param</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;{</span><span class=\"se\">\\&quot;</span><span class=\"s2\">aue</span><span class=\"se\">\\&quot;</span><span class=\"s2\">:</span><span class=\"se\">\\&quot;</span><span class=\"s2\">&quot;</span><span class=\"o\">+</span><span class=\"n\">aue</span><span class=\"o\">+</span><span class=\"s2\">&quot;</span><span class=\"se\">\\&quot;</span><span class=\"s2\">,</span><span class=\"se\">\\&quot;</span><span class=\"s2\">auf</span><span class=\"se\">\\&quot;</span><span class=\"s2\">:</span><span class=\"se\">\\&quot;</span><span class=\"s2\">audio/L16;rate=16000</span><span class=\"se\">\\&quot;</span><span class=\"s2\">,</span><span class=\"se\">\\&quot;</span><span class=\"s2\">voice_name</span><span class=\"se\">\\&quot;</span><span class=\"s2\">:</span><span class=\"se\">\\&quot;</span><span class=\"s2\">&quot;</span> <span class=\"o\">+</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">voice_name</span> <span class=\"o\">+</span> <span class=\"s2\">&quot;</span><span class=\"se\">\\&quot;</span><span class=\"s2\">,</span><span class=\"se\">\\&quot;</span><span class=\"s2\">engine_type</span><span class=\"se\">\\&quot;</span><span class=\"s2\">:</span><span class=\"se\">\\&quot;</span><span class=\"s2\">intp65</span><span class=\"se\">\\&quot;</span><span class=\"s2\">}&quot;</span>\n        <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">debug</span><span class=\"p\">(</span><span class=\"s2\">&quot;param:</span><span class=\"si\">{}</span><span class=\"s2\">&quot;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">param</span><span class=\"p\">))</span>\n        <span class=\"n\">paramBase64</span> <span class=\"o\">=</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">base64</span><span class=\"o\">.</span><span class=\"n\">b64encode</span><span class=\"p\">(</span><span class=\"n\">param</span><span class=\"o\">.</span><span class=\"n\">encode</span><span class=\"p\">(</span><span class=\"s1\">&#39;utf-8&#39;</span><span class=\"p\">)),</span> <span class=\"s1\">&#39;utf-8&#39;</span><span class=\"p\">)</span>\n        <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">debug</span><span class=\"p\">(</span><span class=\"s2\">&quot;x_param:</span><span class=\"si\">{}</span><span class=\"s2\">&quot;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">paramBase64</span><span class=\"p\">))</span>\n\n        <span class=\"n\">m2</span> <span class=\"o\">=</span> <span class=\"n\">hashlib</span><span class=\"o\">.</span><span class=\"n\">md5</span><span class=\"p\">()</span>\n        <span class=\"n\">m2</span><span class=\"o\">.</span><span class=\"n\">update</span><span class=\"p\">((</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">api_key</span> <span class=\"o\">+</span> <span class=\"n\">curTime</span> <span class=\"o\">+</span> <span class=\"n\">paramBase64</span><span class=\"p\">)</span><span class=\"o\">.</span><span class=\"n\">encode</span><span class=\"p\">(</span><span class=\"s1\">&#39;utf-8&#39;</span><span class=\"p\">))</span>\n        <span class=\"n\">checkSum</span> <span class=\"o\">=</span> <span class=\"n\">m2</span><span class=\"o\">.</span><span class=\"n\">hexdigest</span><span class=\"p\">()</span>\n        <span class=\"n\">header</span> <span class=\"o\">=</span> <span class=\"p\">{</span>\n            <span class=\"s1\">&#39;X-CurTime&#39;</span><span class=\"p\">:</span> <span class=\"n\">curTime</span><span class=\"p\">,</span>\n            <span class=\"s1\">&#39;X-Param&#39;</span><span class=\"p\">:</span> <span class=\"n\">paramBase64</span><span class=\"p\">,</span>\n            <span class=\"s1\">&#39;X-Appid&#39;</span><span class=\"p\">:</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">appid</span><span class=\"p\">,</span>\n            <span class=\"s1\">&#39;X-CheckSum&#39;</span><span class=\"p\">:</span> <span class=\"n\">checkSum</span><span class=\"p\">,</span>\n            <span class=\"s1\">&#39;X-Real-Ip&#39;</span><span class=\"p\">:</span><span class=\"s1\">&#39;127.0.0.1&#39;</span><span class=\"p\">,</span>\n            <span class=\"s1\">&#39;Content-Type&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;application/x-www-form-urlencoded; charset=utf-8&#39;</span><span class=\"p\">,</span>\n        <span class=\"p\">}</span>\n        <span class=\"k\">return</span> <span class=\"n\">header</span></div>\n\n<div class=\"viewcode-block\" id=\"XunfeiTTS.getBody\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.TTS.XunfeiTTS.getBody\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">getBody</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">text</span><span class=\"p\">):</span>\n        <span class=\"n\">data</span> <span class=\"o\">=</span> <span class=\"p\">{</span><span class=\"s1\">&#39;text&#39;</span><span class=\"p\">:</span><span class=\"n\">text</span><span class=\"p\">}</span>\n        <span class=\"k\">return</span> <span class=\"n\">data</span></div>\n\n<div class=\"viewcode-block\" id=\"XunfeiTTS.get_speech\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.TTS.XunfeiTTS.get_speech\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">get_speech</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">phrase</span><span class=\"p\">):</span>\n        <span class=\"n\">URL</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;http://api.xfyun.cn/v1/service/v1/tts&quot;</span>\n        <span class=\"n\">r</span> <span class=\"o\">=</span> <span class=\"n\">requests</span><span class=\"o\">.</span><span class=\"n\">post</span><span class=\"p\">(</span><span class=\"n\">URL</span><span class=\"p\">,</span> <span class=\"n\">headers</span><span class=\"o\">=</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">getHeader</span><span class=\"p\">(</span><span class=\"s1\">&#39;lame&#39;</span><span class=\"p\">),</span> <span class=\"n\">data</span><span class=\"o\">=</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">getBody</span><span class=\"p\">(</span><span class=\"n\">phrase</span><span class=\"p\">))</span>\n        <span class=\"n\">contentType</span> <span class=\"o\">=</span> <span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">headers</span><span class=\"p\">[</span><span class=\"s1\">&#39;Content-Type&#39;</span><span class=\"p\">]</span>\n        <span class=\"k\">if</span> <span class=\"n\">contentType</span> <span class=\"o\">==</span> <span class=\"s2\">&quot;audio/mpeg&quot;</span><span class=\"p\">:</span>\n            <span class=\"n\">tmpfile</span> <span class=\"o\">=</span> <span class=\"n\">utils</span><span class=\"o\">.</span><span class=\"n\">write_temp_file</span><span class=\"p\">(</span><span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">content</span><span class=\"p\">,</span> <span class=\"s1\">&#39;.mp3&#39;</span><span class=\"p\">)</span>\n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s1\">&#39;</span><span class=\"si\">{}</span><span class=\"s1\"> 语音合成成功，合成路径：</span><span class=\"si\">{}</span><span class=\"s1\">&#39;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">SLUG</span><span class=\"p\">,</span> <span class=\"n\">tmpfile</span><span class=\"p\">))</span>\n            <span class=\"k\">return</span> <span class=\"n\">tmpfile</span>\n        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">critical</span><span class=\"p\">(</span><span class=\"s1\">&#39;</span><span class=\"si\">{}</span><span class=\"s1\"> 合成失败！</span><span class=\"si\">{}</span><span class=\"s1\">&#39;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">SLUG</span><span class=\"p\">,</span> <span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">text</span><span class=\"p\">),</span> <span class=\"n\">exc_info</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">)</span></div></div>\n\n\n<div class=\"viewcode-block\" id=\"AliTTS\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.TTS.AliTTS\">[文档]</a><span class=\"k\">class</span> <span class=\"nc\">AliTTS</span><span class=\"p\">(</span><span class=\"n\">AbstractTTS</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    阿里的TTS</span>\n<span class=\"sd\">    voice: 发音人，默认是 xiaoyun</span>\n<span class=\"sd\">        全部发音人列表：https://help.aliyun.com/document_detail/84435.html?spm=a2c4g.11186623.2.24.67ce5275q2RGsT</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"n\">SLUG</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;ali-tts&quot;</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">appKey</span><span class=\"p\">,</span> <span class=\"n\">token</span><span class=\"p\">,</span> <span class=\"n\">voice</span><span class=\"o\">=</span><span class=\"s1\">&#39;xiaoyun&#39;</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">args</span><span class=\"p\">):</span>\n        <span class=\"nb\">super</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"vm\">__class__</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">)</span><span class=\"o\">.</span><span class=\"fm\">__init__</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">appKey</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">token</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">voice</span> <span class=\"o\">=</span> <span class=\"n\">appKey</span><span class=\"p\">,</span> <span class=\"n\">token</span><span class=\"p\">,</span> <span class=\"n\">voice</span>\n\n<div class=\"viewcode-block\" id=\"AliTTS.get_config\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.TTS.AliTTS.get_config\">[文档]</a>    <span class=\"nd\">@classmethod</span>\n    <span class=\"k\">def</span> <span class=\"nf\">get_config</span><span class=\"p\">(</span><span class=\"bp\">cls</span><span class=\"p\">):</span>\n        <span class=\"c1\"># Try to get ali_yuyin config from config</span>\n        <span class=\"k\">return</span> <span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;ali_yuyin&#39;</span><span class=\"p\">,</span> <span class=\"p\">{})</span></div>\n                \n<div class=\"viewcode-block\" id=\"AliTTS.get_speech\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.TTS.AliTTS.get_speech\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">get_speech</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">phrase</span><span class=\"p\">):</span>\n        <span class=\"n\">tmpfile</span> <span class=\"o\">=</span> <span class=\"n\">AliSpeech</span><span class=\"o\">.</span><span class=\"n\">tts</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">appKey</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">token</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">voice</span><span class=\"p\">,</span> <span class=\"n\">phrase</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">tmpfile</span> <span class=\"ow\">is</span> <span class=\"ow\">not</span> <span class=\"kc\">None</span><span class=\"p\">:</span>\n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s1\">&#39;</span><span class=\"si\">{}</span><span class=\"s1\"> 语音合成成功，合成路径：</span><span class=\"si\">{}</span><span class=\"s1\">&#39;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">SLUG</span><span class=\"p\">,</span> <span class=\"n\">tmpfile</span><span class=\"p\">))</span>\n            <span class=\"k\">return</span> <span class=\"n\">tmpfile</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">critical</span><span class=\"p\">(</span><span class=\"s1\">&#39;</span><span class=\"si\">{}</span><span class=\"s1\"> 合成失败！&#39;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">SLUG</span><span class=\"p\">),</span> <span class=\"n\">exc_info</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">)</span></div></div>\n\n<div class=\"viewcode-block\" id=\"get_engine_by_slug\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.TTS.get_engine_by_slug\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">get_engine_by_slug</span><span class=\"p\">(</span><span class=\"n\">slug</span><span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    Returns:</span>\n<span class=\"sd\">        A TTS Engine implementation available on the current platform</span>\n\n<span class=\"sd\">    Raises:</span>\n<span class=\"sd\">        ValueError if no speaker implementation is supported on this platform</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n\n    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">slug</span> <span class=\"ow\">or</span> <span class=\"nb\">type</span><span class=\"p\">(</span><span class=\"n\">slug</span><span class=\"p\">)</span> <span class=\"ow\">is</span> <span class=\"ow\">not</span> <span class=\"nb\">str</span><span class=\"p\">:</span>\n        <span class=\"k\">raise</span> <span class=\"ne\">TypeError</span><span class=\"p\">(</span><span class=\"s2\">&quot;无效的 TTS slug &#39;</span><span class=\"si\">%s</span><span class=\"s2\">&#39;&quot;</span><span class=\"p\">,</span> <span class=\"n\">slug</span><span class=\"p\">)</span>\n\n    <span class=\"n\">selected_engines</span> <span class=\"o\">=</span> <span class=\"nb\">list</span><span class=\"p\">(</span><span class=\"nb\">filter</span><span class=\"p\">(</span><span class=\"k\">lambda</span> <span class=\"n\">engine</span><span class=\"p\">:</span> <span class=\"nb\">hasattr</span><span class=\"p\">(</span><span class=\"n\">engine</span><span class=\"p\">,</span> <span class=\"s2\">&quot;SLUG&quot;</span><span class=\"p\">)</span> <span class=\"ow\">and</span>\n                              <span class=\"n\">engine</span><span class=\"o\">.</span><span class=\"n\">SLUG</span> <span class=\"o\">==</span> <span class=\"n\">slug</span><span class=\"p\">,</span> <span class=\"n\">get_engines</span><span class=\"p\">()))</span>\n\n    <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">selected_engines</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"k\">raise</span> <span class=\"ne\">ValueError</span><span class=\"p\">(</span><span class=\"s2\">&quot;错误：找不到名为 </span><span class=\"si\">{}</span><span class=\"s2\"> 的 TTS 引擎&quot;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">slug</span><span class=\"p\">))</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">selected_engines</span><span class=\"p\">)</span> <span class=\"o\">&gt;</span> <span class=\"mi\">1</span><span class=\"p\">:</span>\n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">warning</span><span class=\"p\">(</span><span class=\"s2\">&quot;注意: 有多个 TTS 名称与指定的引擎名 </span><span class=\"si\">{}</span><span class=\"s2\"> 匹配&quot;</span><span class=\"p\">)</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">slug</span><span class=\"p\">)</span>        \n        <span class=\"n\">engine</span> <span class=\"o\">=</span> <span class=\"n\">selected_engines</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n        <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s2\">&quot;使用 </span><span class=\"si\">{}</span><span class=\"s2\"> TTS 引擎&quot;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">engine</span><span class=\"o\">.</span><span class=\"n\">SLUG</span><span class=\"p\">))</span>\n        <span class=\"k\">return</span> <span class=\"n\">engine</span><span class=\"o\">.</span><span class=\"n\">get_instance</span><span class=\"p\">()</span></div>\n\n\n<div class=\"viewcode-block\" id=\"get_engines\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.TTS.get_engines\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">get_engines</span><span class=\"p\">():</span>\n    <span class=\"k\">def</span> <span class=\"nf\">get_subclasses</span><span class=\"p\">(</span><span class=\"bp\">cls</span><span class=\"p\">):</span>\n        <span class=\"n\">subclasses</span> <span class=\"o\">=</span> <span class=\"nb\">set</span><span class=\"p\">()</span>\n        <span class=\"k\">for</span> <span class=\"n\">subclass</span> <span class=\"ow\">in</span> <span class=\"bp\">cls</span><span class=\"o\">.</span><span class=\"n\">__subclasses__</span><span class=\"p\">():</span>\n            <span class=\"n\">subclasses</span><span class=\"o\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">subclass</span><span class=\"p\">)</span>\n            <span class=\"n\">subclasses</span><span class=\"o\">.</span><span class=\"n\">update</span><span class=\"p\">(</span><span class=\"n\">get_subclasses</span><span class=\"p\">(</span><span class=\"n\">subclass</span><span class=\"p\">))</span>\n        <span class=\"k\">return</span> <span class=\"n\">subclasses</span>\n    <span class=\"k\">return</span> <span class=\"p\">[</span><span class=\"n\">engine</span> <span class=\"k\">for</span> <span class=\"n\">engine</span> <span class=\"ow\">in</span>\n            <span class=\"nb\">list</span><span class=\"p\">(</span><span class=\"n\">get_subclasses</span><span class=\"p\">(</span><span class=\"n\">AbstractTTS</span><span class=\"p\">))</span>\n            <span class=\"k\">if</span> <span class=\"nb\">hasattr</span><span class=\"p\">(</span><span class=\"n\">engine</span><span class=\"p\">,</span> <span class=\"s1\">&#39;SLUG&#39;</span><span class=\"p\">)</span> <span class=\"ow\">and</span> <span class=\"n\">engine</span><span class=\"o\">.</span><span class=\"n\">SLUG</span><span class=\"p\">]</span></div>\n</pre></div>\n\n           </div>\n           \n          </div>\n          <footer>\n  \n\n  <hr/>\n\n  <div role=\"contentinfo\">\n    <p>\n        &copy; Copyright 2019, wzpan\n\n    </p>\n  </div>\n  Built with <a href=\"http://sphinx-doc.org/\">Sphinx</a> using a <a href=\"https://github.com/rtfd/sphinx_rtd_theme\">theme</a> provided by <a href=\"https://readthedocs.org\">Read the Docs</a>. \n\n</footer>\n\n        </div>\n      </div>\n\n    </section>\n\n  </div>\n  \n\n\n  <script type=\"text/javascript\">\n      jQuery(function () {\n          SphinxRtdTheme.Navigation.enable(true);\n      });\n  </script>\n\n  \n  \n    \n   \n\n</body>\n</html>"
  },
  {
    "path": "docs/_modules/robot/Updater.html",
    "content": "\n\n<!DOCTYPE html>\n<!--[if IE 8]><html class=\"no-js lt-ie9\" lang=\"zh-CN\" > <![endif]-->\n<!--[if gt IE 8]><!--> <html class=\"no-js\" lang=\"zh-CN\" > <!--<![endif]-->\n<head>\n  <meta charset=\"utf-8\">\n  \n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  \n  <title>robot.Updater &mdash; wukong-robot 1.2.0 文档</title>\n  \n\n  \n  \n  \n  \n\n  \n  <script type=\"text/javascript\" src=\"../../_static/js/modernizr.min.js\"></script>\n  \n    \n      <script type=\"text/javascript\" id=\"documentation_options\" data-url_root=\"../../\" src=\"../../_static/documentation_options.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/jquery.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/underscore.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/doctools.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/language_data.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/translations.js\"></script>\n    \n    <script type=\"text/javascript\" src=\"../../_static/js/theme.js\"></script>\n\n    \n\n  \n  <link rel=\"stylesheet\" href=\"../../_static/css/theme.css\" type=\"text/css\" />\n  <link rel=\"stylesheet\" href=\"../../_static/pygments.css\" type=\"text/css\" />\n    <link rel=\"index\" title=\"索引\" href=\"../../genindex.html\" />\n    <link rel=\"search\" title=\"搜索\" href=\"../../search.html\" /> \n</head>\n\n<body class=\"wy-body-for-nav\">\n\n   \n  <div class=\"wy-grid-for-nav\">\n    \n    <nav data-toggle=\"wy-nav-shift\" class=\"wy-nav-side\">\n      <div class=\"wy-side-scroll\">\n        <div class=\"wy-side-nav-search\" >\n          \n\n          \n            <a href=\"../../index.html\" class=\"icon icon-home\"> wukong-robot\n          \n\n          \n          </a>\n\n          \n            \n            \n          \n\n          \n<div role=\"search\">\n  <form id=\"rtd-search-form\" class=\"wy-form\" action=\"../../search.html\" method=\"get\">\n    <input type=\"text\" name=\"q\" placeholder=\"Search docs\" />\n    <input type=\"hidden\" name=\"check_keywords\" value=\"yes\" />\n    <input type=\"hidden\" name=\"area\" value=\"default\" />\n  </form>\n</div>\n\n          \n        </div>\n\n        <div class=\"wy-menu wy-menu-vertical\" data-spy=\"affix\" role=\"navigation\" aria-label=\"main navigation\">\n          \n            \n            \n              \n            \n            \n              <!-- Local TOC -->\n              <div class=\"local-toc\"></div>\n            \n          \n        </div>\n      </div>\n    </nav>\n\n    <section data-toggle=\"wy-nav-shift\" class=\"wy-nav-content-wrap\">\n\n      \n      <nav class=\"wy-nav-top\" aria-label=\"top navigation\">\n        \n          <i data-toggle=\"wy-nav-top\" class=\"fa fa-bars\"></i>\n          <a href=\"../../index.html\">wukong-robot</a>\n        \n      </nav>\n\n\n      <div class=\"wy-nav-content\">\n        \n        <div class=\"rst-content\">\n        \n          \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<div role=\"navigation\" aria-label=\"breadcrumbs navigation\">\n\n  <ul class=\"wy-breadcrumbs\">\n    \n      <li><a href=\"../../index.html\">Docs</a> &raquo;</li>\n        \n          <li><a href=\"../index.html\">模块代码</a> &raquo;</li>\n        \n      <li>robot.Updater</li>\n    \n    \n      <li class=\"wy-breadcrumbs-aside\">\n        \n      </li>\n    \n  </ul>\n\n  \n  <hr/>\n</div>\n          <div role=\"main\" class=\"document\" itemscope=\"itemscope\" itemtype=\"http://schema.org/Article\">\n           <div itemprop=\"articleBody\">\n            \n  <h1>robot.Updater 源代码</h1><div class=\"highlight\"><pre>\n<span></span><span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">import</span> <span class=\"nn\">requests</span>\n<span class=\"kn\">import</span> <span class=\"nn\">json</span>\n<span class=\"kn\">import</span> <span class=\"nn\">semver</span>\n<span class=\"kn\">from</span> <span class=\"nn\">subprocess</span> <span class=\"k\">import</span> <span class=\"n\">call</span>\n<span class=\"kn\">from</span> <span class=\"nn\">robot</span> <span class=\"k\">import</span> <span class=\"n\">constants</span><span class=\"p\">,</span> <span class=\"n\">logging</span>\n<span class=\"kn\">from</span> <span class=\"nn\">datetime</span> <span class=\"k\">import</span> <span class=\"n\">datetime</span><span class=\"p\">,</span> <span class=\"n\">timedelta</span>\n\n<span class=\"n\">logger</span> <span class=\"o\">=</span> <span class=\"n\">logging</span><span class=\"o\">.</span><span class=\"n\">getLogger</span><span class=\"p\">(</span><span class=\"vm\">__name__</span><span class=\"p\">)</span>\n<span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">setLevel</span><span class=\"p\">(</span><span class=\"n\">level</span><span class=\"o\">=</span><span class=\"n\">logging</span><span class=\"o\">.</span><span class=\"n\">INFO</span><span class=\"p\">)</span>\n\n<span class=\"n\">_updater</span> <span class=\"o\">=</span> <span class=\"kc\">None</span>\n<span class=\"n\">URL</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;https://service-e32kknxi-1253537070.ap-hongkong.apigateway.myqcloud.com/release/wukong&#39;</span>\n<span class=\"n\">DEV_URL</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;https://service-e32kknxi-1253537070.ap-hongkong.apigateway.myqcloud.com/release/wukong-dev&#39;</span>\n\n<div class=\"viewcode-block\" id=\"Updater\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.Updater.Updater\">[文档]</a><span class=\"k\">class</span> <span class=\"nc\">Updater</span><span class=\"p\">(</span><span class=\"nb\">object</span><span class=\"p\">):</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">last_check</span> <span class=\"o\">=</span> <span class=\"n\">datetime</span><span class=\"o\">.</span><span class=\"n\">now</span><span class=\"p\">()</span> <span class=\"o\">-</span> <span class=\"n\">timedelta</span><span class=\"p\">(</span><span class=\"n\">days</span><span class=\"o\">=</span><span class=\"mf\">1.5</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">update_info</span> <span class=\"o\">=</span> <span class=\"p\">{}</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">_pull</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">cwd</span><span class=\"p\">,</span> <span class=\"n\">tag</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">exists</span><span class=\"p\">(</span><span class=\"n\">cwd</span><span class=\"p\">):</span>\n            <span class=\"k\">return</span> <span class=\"n\">call</span><span class=\"p\">([</span><span class=\"s1\">&#39;git checkout master &amp;&amp; git pull &amp;&amp; git checkout </span><span class=\"si\">{}</span><span class=\"s1\">&#39;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">tag</span><span class=\"p\">,</span> <span class=\"n\">tag</span><span class=\"p\">,</span> <span class=\"n\">tag</span><span class=\"p\">)],</span> <span class=\"n\">cwd</span><span class=\"o\">=</span><span class=\"n\">cwd</span><span class=\"p\">,</span> <span class=\"n\">shell</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">0</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">error</span><span class=\"p\">(</span><span class=\"s2\">&quot;目录 </span><span class=\"si\">{}</span><span class=\"s2\"> 不存在&quot;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">cwd</span><span class=\"p\">))</span>\n            <span class=\"k\">return</span> <span class=\"kc\">False</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">_pip</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">cwd</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">exists</span><span class=\"p\">(</span><span class=\"n\">cwd</span><span class=\"p\">):</span>\n            <span class=\"k\">return</span> <span class=\"n\">call</span><span class=\"p\">([</span><span class=\"s1\">&#39;pip3&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;install&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;-r&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;requirements.txt&#39;</span><span class=\"p\">],</span> <span class=\"n\">cwd</span><span class=\"o\">=</span><span class=\"n\">cwd</span><span class=\"p\">,</span> <span class=\"n\">shell</span><span class=\"o\">=</span><span class=\"kc\">False</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">0</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">error</span><span class=\"p\">(</span><span class=\"s2\">&quot;目录 </span><span class=\"si\">{}</span><span class=\"s2\"> 不存在&quot;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">cwd</span><span class=\"p\">))</span>\n            <span class=\"k\">return</span> <span class=\"kc\">False</span>\n\n<div class=\"viewcode-block\" id=\"Updater.update\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.Updater.Updater.update\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">update</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"n\">update_info</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">fetch</span><span class=\"p\">()</span>\n        <span class=\"n\">success</span> <span class=\"o\">=</span> <span class=\"kc\">True</span>\n        <span class=\"k\">if</span> <span class=\"n\">update_info</span> <span class=\"o\">==</span> <span class=\"p\">{}:</span>\n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s1\">&#39;恭喜你，wukong-robot 已经是最新！&#39;</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"s1\">&#39;main&#39;</span> <span class=\"ow\">in</span> <span class=\"n\">update_info</span><span class=\"p\">:</span>\n            <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_pull</span><span class=\"p\">(</span><span class=\"n\">constants</span><span class=\"o\">.</span><span class=\"n\">APP_PATH</span><span class=\"p\">,</span> <span class=\"n\">update_info</span><span class=\"p\">[</span><span class=\"s1\">&#39;main&#39;</span><span class=\"p\">][</span><span class=\"s1\">&#39;version&#39;</span><span class=\"p\">])</span> <span class=\"ow\">and</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_pip</span><span class=\"p\">(</span><span class=\"n\">constants</span><span class=\"o\">.</span><span class=\"n\">APP_PATH</span><span class=\"p\">):</span>\n                <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s1\">&#39;wukong-robot 更新成功！&#39;</span><span class=\"p\">)</span>\n                <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">update_info</span><span class=\"o\">.</span><span class=\"n\">pop</span><span class=\"p\">(</span><span class=\"s1\">&#39;main&#39;</span><span class=\"p\">)</span>\n            <span class=\"k\">else</span><span class=\"p\">:</span>\n                <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s1\">&#39;wukong-robot 更新失败！&#39;</span><span class=\"p\">)</span>\n                <span class=\"n\">success</span> <span class=\"o\">=</span> <span class=\"kc\">False</span>\n        <span class=\"k\">if</span> <span class=\"s1\">&#39;contrib&#39;</span> <span class=\"ow\">in</span> <span class=\"n\">update_info</span><span class=\"p\">:</span>\n            <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_pull</span><span class=\"p\">(</span><span class=\"n\">constants</span><span class=\"o\">.</span><span class=\"n\">CONTRIB_PATH</span><span class=\"p\">,</span> <span class=\"n\">update_info</span><span class=\"p\">[</span><span class=\"s1\">&#39;contrib&#39;</span><span class=\"p\">][</span><span class=\"s1\">&#39;version&#39;</span><span class=\"p\">])</span> <span class=\"ow\">and</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_pip</span><span class=\"p\">(</span><span class=\"n\">constants</span><span class=\"o\">.</span><span class=\"n\">CONTRIB_PATH</span><span class=\"p\">):</span>\n                <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s1\">&#39;wukong-contrib 更新成功！&#39;</span><span class=\"p\">)</span>\n                <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">update_info</span><span class=\"o\">.</span><span class=\"n\">pop</span><span class=\"p\">(</span><span class=\"s1\">&#39;contrib&#39;</span><span class=\"p\">)</span>\n            <span class=\"k\">else</span><span class=\"p\">:</span>\n                <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s1\">&#39;wukong-contrib 更新失败！&#39;</span><span class=\"p\">)</span>\n                <span class=\"n\">success</span> <span class=\"o\">=</span> <span class=\"kc\">False</span>\n        <span class=\"k\">return</span> <span class=\"n\">success</span></div>\n\n    <span class=\"k\">def</span> <span class=\"nf\">_get_version</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">path</span><span class=\"p\">,</span> <span class=\"n\">current</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">exists</span><span class=\"p\">(</span><span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">path</span><span class=\"p\">,</span> <span class=\"s1\">&#39;VERSION&#39;</span><span class=\"p\">)):</span>\n            <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">path</span><span class=\"p\">,</span> <span class=\"s1\">&#39;VERSION&#39;</span><span class=\"p\">),</span> <span class=\"s1\">&#39;r&#39;</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n                <span class=\"k\">return</span> <span class=\"n\">f</span><span class=\"o\">.</span><span class=\"n\">read</span><span class=\"p\">()</span><span class=\"o\">.</span><span class=\"n\">strip</span><span class=\"p\">()</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"k\">return</span> <span class=\"n\">current</span>\n\n<div class=\"viewcode-block\" id=\"Updater.fetch\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.Updater.Updater.fetch\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">fetch</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">dev</span><span class=\"o\">=</span><span class=\"kc\">False</span><span class=\"p\">):</span>\n        <span class=\"k\">global</span> <span class=\"n\">URL</span><span class=\"p\">,</span> <span class=\"n\">DEV_URL</span>\n        <span class=\"n\">url</span> <span class=\"o\">=</span> <span class=\"n\">URL</span>\n        <span class=\"k\">if</span> <span class=\"n\">dev</span><span class=\"p\">:</span>\n            <span class=\"n\">url</span> <span class=\"o\">=</span> <span class=\"n\">DEV_URL</span>\n        <span class=\"n\">now</span> <span class=\"o\">=</span> <span class=\"n\">datetime</span><span class=\"o\">.</span><span class=\"n\">now</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">now</span> <span class=\"o\">-</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">last_check</span><span class=\"p\">)</span><span class=\"o\">.</span><span class=\"n\">seconds</span> <span class=\"o\">&lt;=</span> <span class=\"mi\">1800</span><span class=\"p\">:</span>\n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">debug</span><span class=\"p\">(</span><span class=\"s1\">&#39;30 分钟内已检查过更新，使用上次的检查结果：</span><span class=\"si\">{}</span><span class=\"s1\">&#39;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">update_info</span><span class=\"p\">))</span>            \n            <span class=\"k\">return</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">update_info</span>\n        <span class=\"k\">try</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">last_check</span> <span class=\"o\">=</span> <span class=\"n\">now</span>\n            <span class=\"n\">r</span> <span class=\"o\">=</span> <span class=\"n\">requests</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">url</span><span class=\"p\">,</span> <span class=\"n\">timeout</span><span class=\"o\">=</span><span class=\"mi\">3</span><span class=\"p\">)</span>\n            <span class=\"n\">info</span> <span class=\"o\">=</span> <span class=\"n\">json</span><span class=\"o\">.</span><span class=\"n\">loads</span><span class=\"p\">(</span><span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">text</span><span class=\"p\">)</span>\n            <span class=\"n\">main_version</span> <span class=\"o\">=</span> <span class=\"n\">info</span><span class=\"p\">[</span><span class=\"s1\">&#39;main&#39;</span><span class=\"p\">][</span><span class=\"s1\">&#39;version&#39;</span><span class=\"p\">]</span>\n            <span class=\"n\">contrib_version</span> <span class=\"o\">=</span> <span class=\"n\">info</span><span class=\"p\">[</span><span class=\"s1\">&#39;contrib&#39;</span><span class=\"p\">][</span><span class=\"s1\">&#39;version&#39;</span><span class=\"p\">]</span>\n            <span class=\"c1\"># 检查主仓库</span>\n            <span class=\"n\">current_main_version</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_get_version</span><span class=\"p\">(</span><span class=\"n\">constants</span><span class=\"o\">.</span><span class=\"n\">APP_PATH</span><span class=\"p\">,</span> <span class=\"n\">main_version</span><span class=\"p\">)</span>\n            <span class=\"n\">current_contrib_version</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_get_version</span><span class=\"p\">(</span><span class=\"n\">constants</span><span class=\"o\">.</span><span class=\"n\">CONTRIB_PATH</span><span class=\"p\">,</span> <span class=\"n\">contrib_version</span><span class=\"p\">)</span>\n            <span class=\"k\">if</span> <span class=\"n\">semver</span><span class=\"o\">.</span><span class=\"n\">compare</span><span class=\"p\">(</span><span class=\"n\">main_version</span><span class=\"p\">,</span> <span class=\"n\">current_main_version</span><span class=\"p\">)</span> <span class=\"o\">&gt;</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n                <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s1\">&#39;主仓库检查到更新：</span><span class=\"si\">{}</span><span class=\"s1\">&#39;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">info</span><span class=\"p\">[</span><span class=\"s1\">&#39;main&#39;</span><span class=\"p\">]))</span>\n                <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">update_info</span><span class=\"p\">[</span><span class=\"s1\">&#39;main&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">info</span><span class=\"p\">[</span><span class=\"s1\">&#39;main&#39;</span><span class=\"p\">]</span>\n            <span class=\"k\">if</span> <span class=\"n\">semver</span><span class=\"o\">.</span><span class=\"n\">compare</span><span class=\"p\">(</span><span class=\"n\">contrib_version</span><span class=\"p\">,</span> <span class=\"n\">current_contrib_version</span><span class=\"p\">)</span> <span class=\"o\">&gt;</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n                <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s1\">&#39;插件库检查到更新：</span><span class=\"si\">{}</span><span class=\"s1\">&#39;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">info</span><span class=\"p\">[</span><span class=\"s1\">&#39;contrib&#39;</span><span class=\"p\">]))</span>\n                <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">update_info</span><span class=\"p\">[</span><span class=\"s1\">&#39;contrib&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">info</span><span class=\"p\">[</span><span class=\"s1\">&#39;contrib&#39;</span><span class=\"p\">]</span>\n            <span class=\"k\">if</span> <span class=\"s1\">&#39;notices&#39;</span> <span class=\"ow\">in</span> <span class=\"n\">info</span><span class=\"p\">:</span>\n                <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">update_info</span><span class=\"p\">[</span><span class=\"s1\">&#39;notices&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">info</span><span class=\"p\">[</span><span class=\"s1\">&#39;notices&#39;</span><span class=\"p\">]</span>\n            <span class=\"k\">return</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">update_info</span>\n        <span class=\"k\">except</span> <span class=\"ne\">Exception</span> <span class=\"k\">as</span> <span class=\"n\">e</span><span class=\"p\">:</span>\n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">error</span><span class=\"p\">(</span><span class=\"s2\">&quot;检查更新失败：&quot;</span><span class=\"p\">,</span> <span class=\"n\">e</span><span class=\"p\">)</span>\n            <span class=\"k\">return</span> <span class=\"p\">{}</span></div></div>\n\n<div class=\"viewcode-block\" id=\"fetch\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.Updater.fetch\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">fetch</span><span class=\"p\">(</span><span class=\"n\">dev</span><span class=\"p\">):</span>\n    <span class=\"k\">global</span> <span class=\"n\">_updater</span>\n    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">_updater</span><span class=\"p\">:</span>\n        <span class=\"n\">_updater</span> <span class=\"o\">=</span> <span class=\"n\">Updater</span><span class=\"p\">()</span>\n    <span class=\"k\">return</span> <span class=\"n\">_updater</span><span class=\"o\">.</span><span class=\"n\">fetch</span><span class=\"p\">(</span><span class=\"n\">dev</span><span class=\"p\">)</span></div>\n    \n    \n<span class=\"k\">if</span> <span class=\"vm\">__name__</span> <span class=\"o\">==</span> <span class=\"s1\">&#39;__main__&#39;</span><span class=\"p\">:</span>\n    <span class=\"n\">fetch</span><span class=\"p\">()</span>\n</pre></div>\n\n           </div>\n           \n          </div>\n          <footer>\n  \n\n  <hr/>\n\n  <div role=\"contentinfo\">\n    <p>\n        &copy; Copyright 2019, wzpan\n\n    </p>\n  </div>\n  Built with <a href=\"http://sphinx-doc.org/\">Sphinx</a> using a <a href=\"https://github.com/rtfd/sphinx_rtd_theme\">theme</a> provided by <a href=\"https://readthedocs.org\">Read the Docs</a>. \n\n</footer>\n\n        </div>\n      </div>\n\n    </section>\n\n  </div>\n  \n\n\n  <script type=\"text/javascript\">\n      jQuery(function () {\n          SphinxRtdTheme.Navigation.enable(true);\n      });\n  </script>\n\n  \n  \n    \n   \n\n</body>\n</html>"
  },
  {
    "path": "docs/_modules/robot/config.html",
    "content": "\n\n<!DOCTYPE html>\n<!--[if IE 8]><html class=\"no-js lt-ie9\" lang=\"zh-CN\" > <![endif]-->\n<!--[if gt IE 8]><!--> <html class=\"no-js\" lang=\"zh-CN\" > <!--<![endif]-->\n<head>\n  <meta charset=\"utf-8\">\n  \n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  \n  <title>robot.config &mdash; wukong-robot 1.2.0 文档</title>\n  \n\n  \n  \n  \n  \n\n  \n  <script type=\"text/javascript\" src=\"../../_static/js/modernizr.min.js\"></script>\n  \n    \n      <script type=\"text/javascript\" id=\"documentation_options\" data-url_root=\"../../\" src=\"../../_static/documentation_options.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/jquery.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/underscore.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/doctools.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/language_data.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/translations.js\"></script>\n    \n    <script type=\"text/javascript\" src=\"../../_static/js/theme.js\"></script>\n\n    \n\n  \n  <link rel=\"stylesheet\" href=\"../../_static/css/theme.css\" type=\"text/css\" />\n  <link rel=\"stylesheet\" href=\"../../_static/pygments.css\" type=\"text/css\" />\n    <link rel=\"index\" title=\"索引\" href=\"../../genindex.html\" />\n    <link rel=\"search\" title=\"搜索\" href=\"../../search.html\" /> \n</head>\n\n<body class=\"wy-body-for-nav\">\n\n   \n  <div class=\"wy-grid-for-nav\">\n    \n    <nav data-toggle=\"wy-nav-shift\" class=\"wy-nav-side\">\n      <div class=\"wy-side-scroll\">\n        <div class=\"wy-side-nav-search\" >\n          \n\n          \n            <a href=\"../../index.html\" class=\"icon icon-home\"> wukong-robot\n          \n\n          \n          </a>\n\n          \n            \n            \n          \n\n          \n<div role=\"search\">\n  <form id=\"rtd-search-form\" class=\"wy-form\" action=\"../../search.html\" method=\"get\">\n    <input type=\"text\" name=\"q\" placeholder=\"Search docs\" />\n    <input type=\"hidden\" name=\"check_keywords\" value=\"yes\" />\n    <input type=\"hidden\" name=\"area\" value=\"default\" />\n  </form>\n</div>\n\n          \n        </div>\n\n        <div class=\"wy-menu wy-menu-vertical\" data-spy=\"affix\" role=\"navigation\" aria-label=\"main navigation\">\n          \n            \n            \n              \n            \n            \n              <!-- Local TOC -->\n              <div class=\"local-toc\"></div>\n            \n          \n        </div>\n      </div>\n    </nav>\n\n    <section data-toggle=\"wy-nav-shift\" class=\"wy-nav-content-wrap\">\n\n      \n      <nav class=\"wy-nav-top\" aria-label=\"top navigation\">\n        \n          <i data-toggle=\"wy-nav-top\" class=\"fa fa-bars\"></i>\n          <a href=\"../../index.html\">wukong-robot</a>\n        \n      </nav>\n\n\n      <div class=\"wy-nav-content\">\n        \n        <div class=\"rst-content\">\n        \n          \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<div role=\"navigation\" aria-label=\"breadcrumbs navigation\">\n\n  <ul class=\"wy-breadcrumbs\">\n    \n      <li><a href=\"../../index.html\">Docs</a> &raquo;</li>\n        \n          <li><a href=\"../index.html\">模块代码</a> &raquo;</li>\n        \n      <li>robot.config</li>\n    \n    \n      <li class=\"wy-breadcrumbs-aside\">\n        \n      </li>\n    \n  </ul>\n\n  \n  <hr/>\n</div>\n          <div role=\"main\" class=\"document\" itemscope=\"itemscope\" itemtype=\"http://schema.org/Article\">\n           <div itemprop=\"articleBody\">\n            \n  <h1>robot.config 源代码</h1><div class=\"highlight\"><pre>\n<span></span><span class=\"c1\"># -*- coding: utf-8-*-</span>\n<span class=\"kn\">import</span> <span class=\"nn\">yaml</span>\n<span class=\"kn\">import</span> <span class=\"nn\">logging</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">from</span> <span class=\"nn\">.</span> <span class=\"k\">import</span> <span class=\"n\">constants</span>\n\n<span class=\"n\">logger</span> <span class=\"o\">=</span> <span class=\"n\">logging</span><span class=\"o\">.</span><span class=\"n\">getLogger</span><span class=\"p\">(</span><span class=\"vm\">__name__</span><span class=\"p\">)</span>\n\n<span class=\"n\">_config</span> <span class=\"o\">=</span> <span class=\"p\">{}</span>\n<span class=\"n\">has_init</span> <span class=\"o\">=</span> <span class=\"kc\">False</span>\n\n<div class=\"viewcode-block\" id=\"reload\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.config.reload\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">reload</span><span class=\"p\">():</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    重新加载配置</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s1\">&#39;配置文件发生变更，重新加载配置文件&#39;</span><span class=\"p\">)</span>\n    <span class=\"n\">init</span><span class=\"p\">()</span></div>\n\n<div class=\"viewcode-block\" id=\"init\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.config.init\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">init</span><span class=\"p\">():</span>\n    <span class=\"k\">global</span> <span class=\"n\">has_init</span>\n    <span class=\"k\">if</span> <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">constants</span><span class=\"o\">.</span><span class=\"n\">CONFIG_PATH</span><span class=\"p\">):</span>\n        <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">critical</span><span class=\"p\">(</span><span class=\"s2\">&quot;错误：</span><span class=\"si\">{}</span><span class=\"s2\"> 应该是个目录，而不应该是个文件&quot;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">constants</span><span class=\"o\">.</span><span class=\"n\">CONFIG_PATH</span><span class=\"p\">))</span>\n    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">exists</span><span class=\"p\">(</span><span class=\"n\">constants</span><span class=\"o\">.</span><span class=\"n\">CONFIG_PATH</span><span class=\"p\">):</span>\n        <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">makedirs</span><span class=\"p\">(</span><span class=\"n\">constants</span><span class=\"o\">.</span><span class=\"n\">CONFIG_PATH</span><span class=\"p\">)</span>\n    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">exists</span><span class=\"p\">(</span><span class=\"n\">constants</span><span class=\"o\">.</span><span class=\"n\">getConfigPath</span><span class=\"p\">()):</span>\n        <span class=\"n\">yes_no</span> <span class=\"o\">=</span> <span class=\"nb\">input</span><span class=\"p\">(</span><span class=\"s2\">&quot;配置文件</span><span class=\"si\">{}</span><span class=\"s2\">不存在，要创建吗？(y/n)&quot;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">constants</span><span class=\"o\">.</span><span class=\"n\">getConfigPath</span><span class=\"p\">()))</span>\n        <span class=\"k\">if</span> <span class=\"n\">yes_no</span><span class=\"o\">.</span><span class=\"n\">lower</span><span class=\"p\">()</span> <span class=\"o\">==</span> <span class=\"s1\">&#39;y&#39;</span><span class=\"p\">:</span>\n            <span class=\"n\">constants</span><span class=\"o\">.</span><span class=\"n\">newConfig</span><span class=\"p\">()</span>\n            <span class=\"n\">doInit</span><span class=\"p\">(</span><span class=\"n\">constants</span><span class=\"o\">.</span><span class=\"n\">getConfigPath</span><span class=\"p\">())</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"n\">doInit</span><span class=\"p\">(</span><span class=\"n\">constants</span><span class=\"o\">.</span><span class=\"n\">getDefaultConfigPath</span><span class=\"p\">())</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">doInit</span><span class=\"p\">(</span><span class=\"n\">constants</span><span class=\"o\">.</span><span class=\"n\">getConfigPath</span><span class=\"p\">())</span>\n    <span class=\"n\">has_init</span> <span class=\"o\">=</span> <span class=\"kc\">True</span></div>\n\n<div class=\"viewcode-block\" id=\"doInit\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.config.doInit\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">doInit</span><span class=\"p\">(</span><span class=\"n\">config_file</span><span class=\"o\">=</span><span class=\"n\">constants</span><span class=\"o\">.</span><span class=\"n\">getDefaultConfigPath</span><span class=\"p\">()):</span>\n    <span class=\"c1\"># Create config dir if it does not exist yet</span>\n    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">exists</span><span class=\"p\">(</span><span class=\"n\">constants</span><span class=\"o\">.</span><span class=\"n\">CONFIG_PATH</span><span class=\"p\">):</span>\n        <span class=\"k\">try</span><span class=\"p\">:</span>\n            <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">makedirs</span><span class=\"p\">(</span><span class=\"n\">constants</span><span class=\"o\">.</span><span class=\"n\">CONFIG_PATH</span><span class=\"p\">)</span>\n        <span class=\"k\">except</span> <span class=\"ne\">OSError</span><span class=\"p\">:</span>\n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">error</span><span class=\"p\">(</span><span class=\"s2\">&quot;Could not create config dir: &#39;</span><span class=\"si\">%s</span><span class=\"s2\">&#39;&quot;</span><span class=\"p\">,</span>\n                          <span class=\"n\">constants</span><span class=\"o\">.</span><span class=\"n\">CONFIG_PATH</span><span class=\"p\">,</span> <span class=\"n\">exc_info</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">)</span>\n            <span class=\"k\">raise</span>\n\n    <span class=\"c1\"># Check if config dir is writable</span>\n    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">access</span><span class=\"p\">(</span><span class=\"n\">constants</span><span class=\"o\">.</span><span class=\"n\">CONFIG_PATH</span><span class=\"p\">,</span> <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">W_OK</span><span class=\"p\">):</span>\n        <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">critical</span><span class=\"p\">(</span><span class=\"s2\">&quot;Config dir </span><span class=\"si\">%s</span><span class=\"s2\"> is not writable. Dingdang &quot;</span> <span class=\"o\">+</span>\n                         <span class=\"s2\">&quot;won&#39;t work correctly.&quot;</span><span class=\"p\">,</span>\n                         <span class=\"n\">constants</span><span class=\"o\">.</span><span class=\"n\">CONFIG_PATH</span><span class=\"p\">)</span>\n\n    <span class=\"k\">global</span> <span class=\"n\">_config</span>\n\n    <span class=\"c1\"># Read config</span>\n    <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">debug</span><span class=\"p\">(</span><span class=\"s2\">&quot;Trying to read config file: &#39;</span><span class=\"si\">%s</span><span class=\"s2\">&#39;&quot;</span><span class=\"p\">,</span> <span class=\"n\">config_file</span><span class=\"p\">)</span>\n    <span class=\"k\">try</span><span class=\"p\">:</span>\n        <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">config_file</span><span class=\"p\">,</span> <span class=\"s2\">&quot;r&quot;</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n            <span class=\"n\">_config</span> <span class=\"o\">=</span> <span class=\"n\">yaml</span><span class=\"o\">.</span><span class=\"n\">safe_load</span><span class=\"p\">(</span><span class=\"n\">f</span><span class=\"p\">)</span>\n    <span class=\"k\">except</span> <span class=\"ne\">Exception</span> <span class=\"k\">as</span> <span class=\"n\">e</span><span class=\"p\">:</span>\n        <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">error</span><span class=\"p\">(</span><span class=\"s2\">&quot;配置文件 </span><span class=\"si\">{}</span><span class=\"s2\"> 读取失败: </span><span class=\"si\">{}</span><span class=\"s2\">&quot;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">config_file</span><span class=\"p\">,</span> <span class=\"n\">e</span><span class=\"p\">))</span>\n        <span class=\"k\">raise</span></div>\n\n\n<div class=\"viewcode-block\" id=\"get_path\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.config.get_path\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">get_path</span><span class=\"p\">(</span><span class=\"n\">items</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">):</span>\n    <span class=\"k\">global</span> <span class=\"n\">_config</span>\n    <span class=\"n\">curConfig</span> <span class=\"o\">=</span> <span class=\"n\">_config</span>\n    <span class=\"k\">if</span> <span class=\"nb\">isinstance</span><span class=\"p\">(</span><span class=\"n\">items</span><span class=\"p\">,</span> <span class=\"nb\">str</span><span class=\"p\">)</span> <span class=\"ow\">and</span> <span class=\"n\">items</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">==</span> <span class=\"s1\">&#39;/&#39;</span><span class=\"p\">:</span>\n        <span class=\"n\">items</span> <span class=\"o\">=</span> <span class=\"n\">items</span><span class=\"o\">.</span><span class=\"n\">split</span><span class=\"p\">(</span><span class=\"s1\">&#39;/&#39;</span><span class=\"p\">)[</span><span class=\"mi\">1</span><span class=\"p\">:]</span>\n    <span class=\"k\">for</span> <span class=\"n\">key</span> <span class=\"ow\">in</span> <span class=\"n\">items</span><span class=\"p\">:</span>\n        <span class=\"k\">if</span> <span class=\"n\">key</span> <span class=\"ow\">in</span> <span class=\"n\">curConfig</span><span class=\"p\">:</span>\n            <span class=\"n\">curConfig</span> <span class=\"o\">=</span> <span class=\"n\">curConfig</span><span class=\"p\">[</span><span class=\"n\">key</span><span class=\"p\">]</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">warning</span><span class=\"p\">(</span><span class=\"s2\">&quot;/</span><span class=\"si\">%s</span><span class=\"s2\"> not specified in profile, defaulting to &quot;</span>\n                            <span class=\"s2\">&quot;&#39;</span><span class=\"si\">%s</span><span class=\"s2\">&#39;&quot;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;/&#39;</span><span class=\"o\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">items</span><span class=\"p\">),</span> <span class=\"n\">default</span><span class=\"p\">)</span>\n            <span class=\"k\">return</span> <span class=\"n\">default</span>\n    <span class=\"k\">return</span> <span class=\"n\">curConfig</span></div>\n\n\n<div class=\"viewcode-block\" id=\"has_path\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.config.has_path\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">has_path</span><span class=\"p\">(</span><span class=\"n\">items</span><span class=\"p\">):</span>\n    <span class=\"k\">global</span> <span class=\"n\">_config</span>\n    <span class=\"n\">curConfig</span> <span class=\"o\">=</span> <span class=\"n\">_config</span>\n    <span class=\"k\">if</span> <span class=\"nb\">isinstance</span><span class=\"p\">(</span><span class=\"n\">items</span><span class=\"p\">,</span> <span class=\"nb\">str</span><span class=\"p\">)</span> <span class=\"ow\">and</span> <span class=\"n\">items</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">==</span> <span class=\"s1\">&#39;/&#39;</span><span class=\"p\">:</span>\n        <span class=\"n\">items</span> <span class=\"o\">=</span> <span class=\"n\">items</span><span class=\"o\">.</span><span class=\"n\">split</span><span class=\"p\">(</span><span class=\"s1\">&#39;/&#39;</span><span class=\"p\">)[</span><span class=\"mi\">1</span><span class=\"p\">:]</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">items</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">items</span><span class=\"p\">]</span>\n    <span class=\"k\">for</span> <span class=\"n\">key</span> <span class=\"ow\">in</span> <span class=\"n\">items</span><span class=\"p\">:</span>\n        <span class=\"k\">if</span> <span class=\"n\">key</span> <span class=\"ow\">in</span> <span class=\"n\">curConfig</span><span class=\"p\">:</span>\n            <span class=\"n\">curConfig</span> <span class=\"o\">=</span> <span class=\"n\">curConfig</span><span class=\"p\">[</span><span class=\"n\">key</span><span class=\"p\">]</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"k\">return</span> <span class=\"kc\">False</span>\n    <span class=\"k\">return</span> <span class=\"kc\">True</span></div>\n\n\n<div class=\"viewcode-block\" id=\"has\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.config.has\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">has</span><span class=\"p\">(</span><span class=\"n\">item</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    判断配置里是否包含某个配置项</span>\n\n<span class=\"sd\">    :param item: 配置项名</span>\n<span class=\"sd\">    :returns: True: 包含; False: 不包含</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"k\">return</span> <span class=\"n\">has_path</span><span class=\"p\">(</span><span class=\"n\">item</span><span class=\"p\">)</span></div>\n\n\n<div class=\"viewcode-block\" id=\"get\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.config.get\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">get</span><span class=\"p\">(</span><span class=\"n\">item</span><span class=\"o\">=</span><span class=\"s1\">&#39;&#39;</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    获取某个配置的值</span>\n\n<span class=\"sd\">    :param item: 配置项名。如果是多级配置，则以 &quot;/a/b&quot; 的形式提供</span>\n<span class=\"sd\">    :param default: 默认值（可选）</span>\n<span class=\"sd\">    :returns: 这个配置的值。如果没有该配置，则提供一个默认值</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"k\">global</span> <span class=\"n\">has_init</span>\n    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">has_init</span><span class=\"p\">:</span>\n        <span class=\"n\">init</span><span class=\"p\">()</span>\n    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">item</span><span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"n\">_config</span>\n    <span class=\"k\">if</span> <span class=\"n\">item</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">==</span> <span class=\"s1\">&#39;/&#39;</span><span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"n\">get_path</span><span class=\"p\">(</span><span class=\"n\">item</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"p\">)</span>\n    <span class=\"k\">try</span><span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"n\">_config</span><span class=\"p\">[</span><span class=\"n\">item</span><span class=\"p\">]</span>\n    <span class=\"k\">except</span> <span class=\"ne\">KeyError</span><span class=\"p\">:</span>\n        <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">warning</span><span class=\"p\">(</span><span class=\"s2\">&quot;</span><span class=\"si\">%s</span><span class=\"s2\"> not specified in profile, defaulting to &#39;</span><span class=\"si\">%s</span><span class=\"s2\">&#39;&quot;</span><span class=\"p\">,</span>\n                        <span class=\"n\">item</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span> <span class=\"n\">default</span></div>\n    \n<div class=\"viewcode-block\" id=\"getConfig\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.config.getConfig\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">getConfig</span><span class=\"p\">():</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    返回全部配置数据</span>\n\n<span class=\"sd\">    :returns: 全部配置数据（字典类型）</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"k\">return</span> <span class=\"n\">_config</span></div>\n\n<div class=\"viewcode-block\" id=\"getText\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.config.getText\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">getText</span><span class=\"p\">():</span>\n    <span class=\"k\">if</span> <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">exists</span><span class=\"p\">(</span><span class=\"n\">constants</span><span class=\"o\">.</span><span class=\"n\">getConfigPath</span><span class=\"p\">()):</span>\n        <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">constants</span><span class=\"o\">.</span><span class=\"n\">getConfigPath</span><span class=\"p\">(),</span> <span class=\"s1\">&#39;r&#39;</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n            <span class=\"k\">return</span> <span class=\"n\">f</span><span class=\"o\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n    <span class=\"k\">return</span> <span class=\"s1\">&#39;&#39;</span></div>\n\n<div class=\"viewcode-block\" id=\"dump\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.config.dump\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">dump</span><span class=\"p\">(</span><span class=\"n\">configStr</span><span class=\"p\">):</span>\n    <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">constants</span><span class=\"o\">.</span><span class=\"n\">getConfigPath</span><span class=\"p\">(),</span> <span class=\"s1\">&#39;w&#39;</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n        <span class=\"n\">f</span><span class=\"o\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"n\">configStr</span><span class=\"p\">)</span></div>\n\n</pre></div>\n\n           </div>\n           \n          </div>\n          <footer>\n  \n\n  <hr/>\n\n  <div role=\"contentinfo\">\n    <p>\n        &copy; Copyright 2019, wzpan\n\n    </p>\n  </div>\n  Built with <a href=\"http://sphinx-doc.org/\">Sphinx</a> using a <a href=\"https://github.com/rtfd/sphinx_rtd_theme\">theme</a> provided by <a href=\"https://readthedocs.org\">Read the Docs</a>. \n\n</footer>\n\n        </div>\n      </div>\n\n    </section>\n\n  </div>\n  \n\n\n  <script type=\"text/javascript\">\n      jQuery(function () {\n          SphinxRtdTheme.Navigation.enable(true);\n      });\n  </script>\n\n  \n  \n    \n   \n\n</body>\n</html>"
  },
  {
    "path": "docs/_modules/robot/constants.html",
    "content": "\n\n<!DOCTYPE html>\n<!--[if IE 8]><html class=\"no-js lt-ie9\" lang=\"zh-CN\" > <![endif]-->\n<!--[if gt IE 8]><!--> <html class=\"no-js\" lang=\"zh-CN\" > <!--<![endif]-->\n<head>\n  <meta charset=\"utf-8\">\n  \n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  \n  <title>robot.constants &mdash; wukong-robot 1.2.0 文档</title>\n  \n\n  \n  \n  \n  \n\n  \n  <script type=\"text/javascript\" src=\"../../_static/js/modernizr.min.js\"></script>\n  \n    \n      <script type=\"text/javascript\" id=\"documentation_options\" data-url_root=\"../../\" src=\"../../_static/documentation_options.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/jquery.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/underscore.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/doctools.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/language_data.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/translations.js\"></script>\n    \n    <script type=\"text/javascript\" src=\"../../_static/js/theme.js\"></script>\n\n    \n\n  \n  <link rel=\"stylesheet\" href=\"../../_static/css/theme.css\" type=\"text/css\" />\n  <link rel=\"stylesheet\" href=\"../../_static/pygments.css\" type=\"text/css\" />\n    <link rel=\"index\" title=\"索引\" href=\"../../genindex.html\" />\n    <link rel=\"search\" title=\"搜索\" href=\"../../search.html\" /> \n</head>\n\n<body class=\"wy-body-for-nav\">\n\n   \n  <div class=\"wy-grid-for-nav\">\n    \n    <nav data-toggle=\"wy-nav-shift\" class=\"wy-nav-side\">\n      <div class=\"wy-side-scroll\">\n        <div class=\"wy-side-nav-search\" >\n          \n\n          \n            <a href=\"../../index.html\" class=\"icon icon-home\"> wukong-robot\n          \n\n          \n          </a>\n\n          \n            \n            \n          \n\n          \n<div role=\"search\">\n  <form id=\"rtd-search-form\" class=\"wy-form\" action=\"../../search.html\" method=\"get\">\n    <input type=\"text\" name=\"q\" placeholder=\"Search docs\" />\n    <input type=\"hidden\" name=\"check_keywords\" value=\"yes\" />\n    <input type=\"hidden\" name=\"area\" value=\"default\" />\n  </form>\n</div>\n\n          \n        </div>\n\n        <div class=\"wy-menu wy-menu-vertical\" data-spy=\"affix\" role=\"navigation\" aria-label=\"main navigation\">\n          \n            \n            \n              \n            \n            \n              <!-- Local TOC -->\n              <div class=\"local-toc\"></div>\n            \n          \n        </div>\n      </div>\n    </nav>\n\n    <section data-toggle=\"wy-nav-shift\" class=\"wy-nav-content-wrap\">\n\n      \n      <nav class=\"wy-nav-top\" aria-label=\"top navigation\">\n        \n          <i data-toggle=\"wy-nav-top\" class=\"fa fa-bars\"></i>\n          <a href=\"../../index.html\">wukong-robot</a>\n        \n      </nav>\n\n\n      <div class=\"wy-nav-content\">\n        \n        <div class=\"rst-content\">\n        \n          \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<div role=\"navigation\" aria-label=\"breadcrumbs navigation\">\n\n  <ul class=\"wy-breadcrumbs\">\n    \n      <li><a href=\"../../index.html\">Docs</a> &raquo;</li>\n        \n          <li><a href=\"../index.html\">模块代码</a> &raquo;</li>\n        \n      <li>robot.constants</li>\n    \n    \n      <li class=\"wy-breadcrumbs-aside\">\n        \n      </li>\n    \n  </ul>\n\n  \n  <hr/>\n</div>\n          <div role=\"main\" class=\"document\" itemscope=\"itemscope\" itemtype=\"http://schema.org/Article\">\n           <div itemprop=\"articleBody\">\n            \n  <h1>robot.constants 源代码</h1><div class=\"highlight\"><pre>\n<span></span><span class=\"c1\"># -*- coding: utf-8-*-</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">import</span> <span class=\"nn\">shutil</span>\n\n<span class=\"c1\"># Wukong main directory</span>\n<span class=\"n\">APP_PATH</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">normpath</span><span class=\"p\">(</span><span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">join</span><span class=\"p\">(</span>\n    <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">dirname</span><span class=\"p\">(</span><span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">abspath</span><span class=\"p\">(</span><span class=\"vm\">__file__</span><span class=\"p\">)),</span> <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">pardir</span><span class=\"p\">))</span>\n \n<span class=\"n\">LIB_PATH</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">APP_PATH</span><span class=\"p\">,</span> <span class=\"s2\">&quot;robot&quot;</span><span class=\"p\">)</span>\n<span class=\"n\">DATA_PATH</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">APP_PATH</span><span class=\"p\">,</span> <span class=\"s2\">&quot;static&quot;</span><span class=\"p\">)</span>\n<span class=\"n\">TEMP_PATH</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">APP_PATH</span><span class=\"p\">,</span> <span class=\"s2\">&quot;temp&quot;</span><span class=\"p\">)</span>\n<span class=\"n\">TEMPLATE_PATH</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">APP_PATH</span><span class=\"p\">,</span> <span class=\"s2\">&quot;server&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;templates&quot;</span><span class=\"p\">)</span>\n<span class=\"n\">PLUGIN_PATH</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">APP_PATH</span><span class=\"p\">,</span> <span class=\"s2\">&quot;plugins&quot;</span><span class=\"p\">)</span>\n<span class=\"n\">DEFAULT_CONFIG_NAME</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;default.yml&#39;</span>\n<span class=\"n\">CUSTOM_CONFIG_NAME</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;config.yml&#39;</span>\n\n<span class=\"n\">CONFIG_PATH</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">expanduser</span><span class=\"p\">(</span>\n    <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">getenv</span><span class=\"p\">(</span><span class=\"s1\">&#39;WUKONG_CONFIG&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;~/.wukong&#39;</span><span class=\"p\">)</span>\n<span class=\"p\">)</span>\n<span class=\"n\">CONTRIB_PATH</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">expanduser</span><span class=\"p\">(</span>\n    <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">getenv</span><span class=\"p\">(</span><span class=\"s1\">&#39;WUKONG_CONFIG&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;~/.wukong/contrib&#39;</span><span class=\"p\">)</span>\n<span class=\"p\">)</span>\n<span class=\"n\">CUSTOM_PATH</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">expanduser</span><span class=\"p\">(</span>\n    <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">getenv</span><span class=\"p\">(</span><span class=\"s1\">&#39;WUKONG_CONFIG&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;~/.wukong/custom&#39;</span><span class=\"p\">)</span>\n<span class=\"p\">)</span>\n\n<div class=\"viewcode-block\" id=\"getConfigPath\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.constants.getConfigPath\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">getConfigPath</span><span class=\"p\">():</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    获取配置文件的路径</span>\n\n<span class=\"sd\">    returns: 配置文件的存储路径</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"k\">return</span> <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">CONFIG_PATH</span><span class=\"p\">,</span> <span class=\"n\">CUSTOM_CONFIG_NAME</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"getConfigData\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.constants.getConfigData\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">getConfigData</span><span class=\"p\">(</span><span class=\"o\">*</span><span class=\"n\">fname</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    获取配置目录下的指定文件的路径</span>\n\n<span class=\"sd\">    :param *fname: 指定文件名。如果传多个，则自动拼接</span>\n<span class=\"sd\">    :returns: 配置目录下的某个文件的存储路径</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"k\">return</span> <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">CONFIG_PATH</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">fname</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"getData\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.constants.getData\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">getData</span><span class=\"p\">(</span><span class=\"o\">*</span><span class=\"n\">fname</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    获取资源目录下指定文件的路径</span>\n\n<span class=\"sd\">    :param *fname: 指定文件名。如果传多个，则自动拼接</span>\n<span class=\"sd\">    :returns: 配置文件的存储路径</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"k\">return</span> <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">DATA_PATH</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">fname</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"getDefaultConfigPath\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.constants.getDefaultConfigPath\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">getDefaultConfigPath</span><span class=\"p\">():</span>    \n    <span class=\"k\">return</span> <span class=\"n\">getData</span><span class=\"p\">(</span><span class=\"n\">DEFAULT_CONFIG_NAME</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"newConfig\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.constants.newConfig\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">newConfig</span><span class=\"p\">():</span>\n    <span class=\"n\">shutil</span><span class=\"o\">.</span><span class=\"n\">copyfile</span><span class=\"p\">(</span><span class=\"n\">getDefaultConfigPath</span><span class=\"p\">(),</span> <span class=\"n\">getConfigPath</span><span class=\"p\">())</span></div>\n\n<div class=\"viewcode-block\" id=\"getHotwordModel\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.constants.getHotwordModel\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">getHotwordModel</span><span class=\"p\">(</span><span class=\"n\">fname</span><span class=\"p\">):</span>\n    <span class=\"k\">if</span> <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">exists</span><span class=\"p\">(</span><span class=\"n\">getData</span><span class=\"p\">(</span><span class=\"n\">fname</span><span class=\"p\">)):</span>\n        <span class=\"k\">return</span> <span class=\"n\">getData</span><span class=\"p\">(</span><span class=\"n\">fname</span><span class=\"p\">)</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"n\">getConfigData</span><span class=\"p\">(</span><span class=\"n\">fname</span><span class=\"p\">)</span></div>\n\n</pre></div>\n\n           </div>\n           \n          </div>\n          <footer>\n  \n\n  <hr/>\n\n  <div role=\"contentinfo\">\n    <p>\n        &copy; Copyright 2019, wzpan\n\n    </p>\n  </div>\n  Built with <a href=\"http://sphinx-doc.org/\">Sphinx</a> using a <a href=\"https://github.com/rtfd/sphinx_rtd_theme\">theme</a> provided by <a href=\"https://readthedocs.org\">Read the Docs</a>. \n\n</footer>\n\n        </div>\n      </div>\n\n    </section>\n\n  </div>\n  \n\n\n  <script type=\"text/javascript\">\n      jQuery(function () {\n          SphinxRtdTheme.Navigation.enable(true);\n      });\n  </script>\n\n  \n  \n    \n   \n\n</body>\n</html>"
  },
  {
    "path": "docs/_modules/robot/drivers/apa102.html",
    "content": "\n\n<!DOCTYPE html>\n<!--[if IE 8]><html class=\"no-js lt-ie9\" lang=\"zh-CN\" > <![endif]-->\n<!--[if gt IE 8]><!--> <html class=\"no-js\" lang=\"zh-CN\" > <!--<![endif]-->\n<head>\n  <meta charset=\"utf-8\">\n  \n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  \n  <title>robot.drivers.apa102 &mdash; wukong-robot 1.2.0 文档</title>\n  \n\n  \n  \n  \n  \n\n  \n  <script type=\"text/javascript\" src=\"../../../_static/js/modernizr.min.js\"></script>\n  \n    \n      <script type=\"text/javascript\" id=\"documentation_options\" data-url_root=\"../../../\" src=\"../../../_static/documentation_options.js\"></script>\n        <script type=\"text/javascript\" src=\"../../../_static/jquery.js\"></script>\n        <script type=\"text/javascript\" src=\"../../../_static/underscore.js\"></script>\n        <script type=\"text/javascript\" src=\"../../../_static/doctools.js\"></script>\n        <script type=\"text/javascript\" src=\"../../../_static/language_data.js\"></script>\n        <script type=\"text/javascript\" src=\"../../../_static/translations.js\"></script>\n    \n    <script type=\"text/javascript\" src=\"../../../_static/js/theme.js\"></script>\n\n    \n\n  \n  <link rel=\"stylesheet\" href=\"../../../_static/css/theme.css\" type=\"text/css\" />\n  <link rel=\"stylesheet\" href=\"../../../_static/pygments.css\" type=\"text/css\" />\n    <link rel=\"index\" title=\"索引\" href=\"../../../genindex.html\" />\n    <link rel=\"search\" title=\"搜索\" href=\"../../../search.html\" /> \n</head>\n\n<body class=\"wy-body-for-nav\">\n\n   \n  <div class=\"wy-grid-for-nav\">\n    \n    <nav data-toggle=\"wy-nav-shift\" class=\"wy-nav-side\">\n      <div class=\"wy-side-scroll\">\n        <div class=\"wy-side-nav-search\" >\n          \n\n          \n            <a href=\"../../../index.html\" class=\"icon icon-home\"> wukong-robot\n          \n\n          \n          </a>\n\n          \n            \n            \n          \n\n          \n<div role=\"search\">\n  <form id=\"rtd-search-form\" class=\"wy-form\" action=\"../../../search.html\" method=\"get\">\n    <input type=\"text\" name=\"q\" placeholder=\"Search docs\" />\n    <input type=\"hidden\" name=\"check_keywords\" value=\"yes\" />\n    <input type=\"hidden\" name=\"area\" value=\"default\" />\n  </form>\n</div>\n\n          \n        </div>\n\n        <div class=\"wy-menu wy-menu-vertical\" data-spy=\"affix\" role=\"navigation\" aria-label=\"main navigation\">\n          \n            \n            \n              \n            \n            \n              <!-- Local TOC -->\n              <div class=\"local-toc\"></div>\n            \n          \n        </div>\n      </div>\n    </nav>\n\n    <section data-toggle=\"wy-nav-shift\" class=\"wy-nav-content-wrap\">\n\n      \n      <nav class=\"wy-nav-top\" aria-label=\"top navigation\">\n        \n          <i data-toggle=\"wy-nav-top\" class=\"fa fa-bars\"></i>\n          <a href=\"../../../index.html\">wukong-robot</a>\n        \n      </nav>\n\n\n      <div class=\"wy-nav-content\">\n        \n        <div class=\"rst-content\">\n        \n          \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<div role=\"navigation\" aria-label=\"breadcrumbs navigation\">\n\n  <ul class=\"wy-breadcrumbs\">\n    \n      <li><a href=\"../../../index.html\">Docs</a> &raquo;</li>\n        \n          <li><a href=\"../../index.html\">模块代码</a> &raquo;</li>\n        \n      <li>robot.drivers.apa102</li>\n    \n    \n      <li class=\"wy-breadcrumbs-aside\">\n        \n      </li>\n    \n  </ul>\n\n  \n  <hr/>\n</div>\n          <div role=\"main\" class=\"document\" itemscope=\"itemscope\" itemtype=\"http://schema.org/Article\">\n           <div itemprop=\"articleBody\">\n            \n  <h1>robot.drivers.apa102 源代码</h1><div class=\"highlight\"><pre>\n<span></span><span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">from https://github.com/tinue/APA102_Pi</span>\n<span class=\"sd\">This is the main driver module for APA102 LEDs</span>\n<span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"kn\">import</span> <span class=\"nn\">spidev</span>\n<span class=\"kn\">from</span> <span class=\"nn\">math</span> <span class=\"k\">import</span> <span class=\"n\">ceil</span>\n\n<span class=\"n\">RGB_MAP</span> <span class=\"o\">=</span> <span class=\"p\">{</span> <span class=\"s1\">&#39;rgb&#39;</span><span class=\"p\">:</span> <span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">],</span> <span class=\"s1\">&#39;rbg&#39;</span><span class=\"p\">:</span> <span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">],</span> <span class=\"s1\">&#39;grb&#39;</span><span class=\"p\">:</span> <span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">3</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">],</span>\n            <span class=\"s1\">&#39;gbr&#39;</span><span class=\"p\">:</span> <span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"mi\">3</span><span class=\"p\">],</span> <span class=\"s1\">&#39;brg&#39;</span><span class=\"p\">:</span> <span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"mi\">3</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">],</span> <span class=\"s1\">&#39;bgr&#39;</span><span class=\"p\">:</span> <span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"p\">}</span>\n\n<div class=\"viewcode-block\" id=\"APA102\"><a class=\"viewcode-back\" href=\"../../../robot.drivers.html#robot.drivers.apa102.APA102\">[文档]</a><span class=\"k\">class</span> <span class=\"nc\">APA102</span><span class=\"p\">:</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    Driver for APA102 LEDS (aka &quot;DotStar&quot;).</span>\n\n<span class=\"sd\">    (c) Martin Erzberger 2016-2017</span>\n\n<span class=\"sd\">    My very first Python code, so I am sure there is a lot to be optimized ;)</span>\n\n<span class=\"sd\">    Public methods are:</span>\n<span class=\"sd\">     - set_pixel</span>\n<span class=\"sd\">     - set_pixel_rgb</span>\n<span class=\"sd\">     - show</span>\n<span class=\"sd\">     - clear_strip</span>\n<span class=\"sd\">     - cleanup</span>\n\n<span class=\"sd\">    Helper methods for color manipulation are:</span>\n<span class=\"sd\">     - combine_color</span>\n<span class=\"sd\">     - wheel</span>\n\n<span class=\"sd\">    The rest of the methods are used internally and should not be used by the</span>\n<span class=\"sd\">    user of the library.</span>\n\n<span class=\"sd\">    Very brief overview of APA102: An APA102 LED is addressed with SPI. The bits</span>\n<span class=\"sd\">    are shifted in one by one, starting with the least significant bit.</span>\n\n<span class=\"sd\">    An LED usually just forwards everything that is sent to its data-in to</span>\n<span class=\"sd\">    data-out. While doing this, it remembers its own color and keeps glowing</span>\n<span class=\"sd\">    with that color as long as there is power.</span>\n\n<span class=\"sd\">    An LED can be switched to not forward the data, but instead use the data</span>\n<span class=\"sd\">    to change it&#39;s own color. This is done by sending (at least) 32 bits of</span>\n<span class=\"sd\">    zeroes to data-in. The LED then accepts the next correct 32 bit LED</span>\n<span class=\"sd\">    frame (with color information) as its new color setting.</span>\n\n<span class=\"sd\">    After having received the 32 bit color frame, the LED changes color,</span>\n<span class=\"sd\">    and then resumes to just copying data-in to data-out.</span>\n\n<span class=\"sd\">    The really clever bit is this: While receiving the 32 bit LED frame,</span>\n<span class=\"sd\">    the LED sends zeroes on its data-out line. Because a color frame is</span>\n<span class=\"sd\">    32 bits, the LED sends 32 bits of zeroes to the next LED.</span>\n<span class=\"sd\">    As we have seen above, this means that the next LED is now ready</span>\n<span class=\"sd\">    to accept a color frame and update its color.</span>\n\n<span class=\"sd\">    So that&#39;s really the entire protocol:</span>\n<span class=\"sd\">    - Start by sending 32 bits of zeroes. This prepares LED 1 to update</span>\n<span class=\"sd\">      its color.</span>\n<span class=\"sd\">    - Send color information one by one, starting with the color for LED 1,</span>\n<span class=\"sd\">      then LED 2 etc.</span>\n<span class=\"sd\">    - Finish off by cycling the clock line a few times to get all data</span>\n<span class=\"sd\">      to the very last LED on the strip</span>\n\n<span class=\"sd\">    The last step is necessary, because each LED delays forwarding the data</span>\n<span class=\"sd\">    a bit. Imagine ten people in a row. When you yell the last color</span>\n<span class=\"sd\">    information, i.e. the one for person ten, to the first person in</span>\n<span class=\"sd\">    the line, then you are not finished yet. Person one has to turn around</span>\n<span class=\"sd\">    and yell it to person 2, and so on. So it takes ten additional &quot;dummy&quot;</span>\n<span class=\"sd\">    cycles until person ten knows the color. When you look closer,</span>\n<span class=\"sd\">    you will see that not even person 9 knows its own color yet. This</span>\n<span class=\"sd\">    information is still with person 2. Essentially the driver sends additional</span>\n<span class=\"sd\">    zeroes to LED 1 as long as it takes for the last color frame to make it</span>\n<span class=\"sd\">    down the line to the last LED.</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"c1\"># Constants</span>\n    <span class=\"n\">MAX_BRIGHTNESS</span> <span class=\"o\">=</span> <span class=\"mi\">31</span> <span class=\"c1\"># Safeguard: Set to a value appropriate for your setup</span>\n    <span class=\"n\">LED_START</span> <span class=\"o\">=</span> <span class=\"mb\">0b11100000</span> <span class=\"c1\"># Three &quot;1&quot; bits, followed by 5 brightness bits</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">num_led</span><span class=\"p\">,</span> <span class=\"n\">global_brightness</span><span class=\"o\">=</span><span class=\"n\">MAX_BRIGHTNESS</span><span class=\"p\">,</span>\n                 <span class=\"n\">order</span><span class=\"o\">=</span><span class=\"s1\">&#39;rgb&#39;</span><span class=\"p\">,</span> <span class=\"n\">bus</span><span class=\"o\">=</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">device</span><span class=\"o\">=</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"n\">max_speed_hz</span><span class=\"o\">=</span><span class=\"mi\">8000000</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">num_led</span> <span class=\"o\">=</span> <span class=\"n\">num_led</span>  <span class=\"c1\"># The number of LEDs in the Strip</span>\n        <span class=\"n\">order</span> <span class=\"o\">=</span> <span class=\"n\">order</span><span class=\"o\">.</span><span class=\"n\">lower</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">rgb</span> <span class=\"o\">=</span> <span class=\"n\">RGB_MAP</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">order</span><span class=\"p\">,</span> <span class=\"n\">RGB_MAP</span><span class=\"p\">[</span><span class=\"s1\">&#39;rgb&#39;</span><span class=\"p\">])</span>\n        <span class=\"c1\"># Limit the brightness to the maximum if it&#39;s set higher</span>\n        <span class=\"k\">if</span> <span class=\"n\">global_brightness</span> <span class=\"o\">&gt;</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">MAX_BRIGHTNESS</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">global_brightness</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">MAX_BRIGHTNESS</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">global_brightness</span> <span class=\"o\">=</span> <span class=\"n\">global_brightness</span>\n\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">leds</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">LED_START</span><span class=\"p\">,</span><span class=\"mi\">0</span><span class=\"p\">,</span><span class=\"mi\">0</span><span class=\"p\">,</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">num_led</span> <span class=\"c1\"># Pixel buffer</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">spi</span> <span class=\"o\">=</span> <span class=\"n\">spidev</span><span class=\"o\">.</span><span class=\"n\">SpiDev</span><span class=\"p\">()</span>  <span class=\"c1\"># Init the SPI device</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">spi</span><span class=\"o\">.</span><span class=\"n\">open</span><span class=\"p\">(</span><span class=\"n\">bus</span><span class=\"p\">,</span> <span class=\"n\">device</span><span class=\"p\">)</span>  <span class=\"c1\"># Open SPI port 0, slave device (CS) 1</span>\n        <span class=\"c1\"># Up the speed a bit, so that the LEDs are painted faster</span>\n        <span class=\"k\">if</span> <span class=\"n\">max_speed_hz</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">spi</span><span class=\"o\">.</span><span class=\"n\">max_speed_hz</span> <span class=\"o\">=</span> <span class=\"n\">max_speed_hz</span>\n\n<div class=\"viewcode-block\" id=\"APA102.clock_start_frame\"><a class=\"viewcode-back\" href=\"../../../robot.drivers.html#robot.drivers.apa102.APA102.clock_start_frame\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">clock_start_frame</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;Sends a start frame to the LED strip.</span>\n\n<span class=\"sd\">        This method clocks out a start frame, telling the receiving LED</span>\n<span class=\"sd\">        that it must update its own color now.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">spi</span><span class=\"o\">.</span><span class=\"n\">xfer2</span><span class=\"p\">([</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"mi\">4</span><span class=\"p\">)</span>  <span class=\"c1\"># Start frame, 32 zero bits</span></div>\n\n\n<div class=\"viewcode-block\" id=\"APA102.clock_end_frame\"><a class=\"viewcode-back\" href=\"../../../robot.drivers.html#robot.drivers.apa102.APA102.clock_end_frame\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">clock_end_frame</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;Sends an end frame to the LED strip.</span>\n\n<span class=\"sd\">        As explained above, dummy data must be sent after the last real colour</span>\n<span class=\"sd\">        information so that all of the data can reach its destination down the line.</span>\n<span class=\"sd\">        The delay is not as bad as with the human example above.</span>\n<span class=\"sd\">        It is only 1/2 bit per LED. This is because the SPI clock line</span>\n<span class=\"sd\">        needs to be inverted.</span>\n\n<span class=\"sd\">        Say a bit is ready on the SPI data line. The sender communicates</span>\n<span class=\"sd\">        this by toggling the clock line. The bit is read by the LED</span>\n<span class=\"sd\">        and immediately forwarded to the output data line. When the clock goes</span>\n<span class=\"sd\">        down again on the input side, the LED will toggle the clock up</span>\n<span class=\"sd\">        on the output to tell the next LED that the bit is ready.</span>\n\n<span class=\"sd\">        After one LED the clock is inverted, and after two LEDs it is in sync</span>\n<span class=\"sd\">        again, but one cycle behind. Therefore, for every two LEDs, one bit</span>\n<span class=\"sd\">        of delay gets accumulated. For 300 LEDs, 150 additional bits must be fed to</span>\n<span class=\"sd\">        the input of LED one so that the data can reach the last LED.</span>\n\n<span class=\"sd\">        Ultimately, we need to send additional numLEDs/2 arbitrary data bits,</span>\n<span class=\"sd\">        in order to trigger numLEDs/2 additional clock changes. This driver</span>\n<span class=\"sd\">        sends zeroes, which has the benefit of getting LED one partially or</span>\n<span class=\"sd\">        fully ready for the next update to the strip. An optimized version</span>\n<span class=\"sd\">        of the driver could omit the &quot;clockStartFrame&quot; method if enough zeroes have</span>\n<span class=\"sd\">        been sent as part of &quot;clockEndFrame&quot;.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"c1\"># Round up num_led/2 bits (or num_led/16 bytes)</span>\n        <span class=\"k\">for</span> <span class=\"n\">_</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">((</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">num_led</span> <span class=\"o\">+</span> <span class=\"mi\">15</span><span class=\"p\">)</span> <span class=\"o\">//</span> <span class=\"mi\">16</span><span class=\"p\">):</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">spi</span><span class=\"o\">.</span><span class=\"n\">xfer2</span><span class=\"p\">([</span><span class=\"mh\">0x00</span><span class=\"p\">])</span></div>\n\n\n<div class=\"viewcode-block\" id=\"APA102.clear_strip\"><a class=\"viewcode-back\" href=\"../../../robot.drivers.html#robot.drivers.apa102.APA102.clear_strip\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">clear_strip</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot; Turns off the strip and shows the result right away.&quot;&quot;&quot;</span>\n\n        <span class=\"k\">for</span> <span class=\"n\">led</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">num_led</span><span class=\"p\">):</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">set_pixel</span><span class=\"p\">(</span><span class=\"n\">led</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">show</span><span class=\"p\">()</span></div>\n\n\n<div class=\"viewcode-block\" id=\"APA102.set_pixel\"><a class=\"viewcode-back\" href=\"../../../robot.drivers.html#robot.drivers.apa102.APA102.set_pixel\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">set_pixel</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">led_num</span><span class=\"p\">,</span> <span class=\"n\">red</span><span class=\"p\">,</span> <span class=\"n\">green</span><span class=\"p\">,</span> <span class=\"n\">blue</span><span class=\"p\">,</span> <span class=\"n\">bright_percent</span><span class=\"o\">=</span><span class=\"mi\">100</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;Sets the color of one pixel in the LED stripe.</span>\n\n<span class=\"sd\">        The changed pixel is not shown yet on the Stripe, it is only</span>\n<span class=\"sd\">        written to the pixel buffer. Colors are passed individually.</span>\n<span class=\"sd\">        If brightness is not set the global brightness setting is used.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"k\">if</span> <span class=\"n\">led_num</span> <span class=\"o\">&lt;</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"k\">return</span>  <span class=\"c1\"># Pixel is invisible, so ignore</span>\n        <span class=\"k\">if</span> <span class=\"n\">led_num</span> <span class=\"o\">&gt;=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">num_led</span><span class=\"p\">:</span>\n            <span class=\"k\">return</span>  <span class=\"c1\"># again, invisible</span>\n\n        <span class=\"c1\"># Calculate pixel brightness as a percentage of the</span>\n        <span class=\"c1\"># defined global_brightness. Round up to nearest integer</span>\n        <span class=\"c1\"># as we expect some brightness unless set to 0</span>\n        <span class=\"n\">brightness</span> <span class=\"o\">=</span> <span class=\"n\">ceil</span><span class=\"p\">(</span><span class=\"n\">bright_percent</span><span class=\"o\">*</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">global_brightness</span><span class=\"o\">/</span><span class=\"mf\">100.0</span><span class=\"p\">)</span>\n        <span class=\"n\">brightness</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">brightness</span><span class=\"p\">)</span>\n\n        <span class=\"c1\"># LED startframe is three &quot;1&quot; bits, followed by 5 brightness bits</span>\n        <span class=\"n\">ledstart</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"n\">brightness</span> <span class=\"o\">&amp;</span> <span class=\"mb\">0b00011111</span><span class=\"p\">)</span> <span class=\"o\">|</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">LED_START</span>\n\n        <span class=\"n\">start_index</span> <span class=\"o\">=</span> <span class=\"mi\">4</span> <span class=\"o\">*</span> <span class=\"n\">led_num</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">leds</span><span class=\"p\">[</span><span class=\"n\">start_index</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">ledstart</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">leds</span><span class=\"p\">[</span><span class=\"n\">start_index</span> <span class=\"o\">+</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">rgb</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]]</span> <span class=\"o\">=</span> <span class=\"n\">red</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">leds</span><span class=\"p\">[</span><span class=\"n\">start_index</span> <span class=\"o\">+</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">rgb</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]]</span> <span class=\"o\">=</span> <span class=\"n\">green</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">leds</span><span class=\"p\">[</span><span class=\"n\">start_index</span> <span class=\"o\">+</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">rgb</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">]]</span> <span class=\"o\">=</span> <span class=\"n\">blue</span></div>\n\n\n<div class=\"viewcode-block\" id=\"APA102.set_pixel_rgb\"><a class=\"viewcode-back\" href=\"../../../robot.drivers.html#robot.drivers.apa102.APA102.set_pixel_rgb\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">set_pixel_rgb</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">led_num</span><span class=\"p\">,</span> <span class=\"n\">rgb_color</span><span class=\"p\">,</span> <span class=\"n\">bright_percent</span><span class=\"o\">=</span><span class=\"mi\">100</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;Sets the color of one pixel in the LED stripe.</span>\n\n<span class=\"sd\">        The changed pixel is not shown yet on the Stripe, it is only</span>\n<span class=\"sd\">        written to the pixel buffer.</span>\n<span class=\"sd\">        Colors are passed combined (3 bytes concatenated)</span>\n<span class=\"sd\">        If brightness is not set the global brightness setting is used.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">set_pixel</span><span class=\"p\">(</span><span class=\"n\">led_num</span><span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"n\">rgb_color</span> <span class=\"o\">&amp;</span> <span class=\"mh\">0xFF0000</span><span class=\"p\">)</span> <span class=\"o\">&gt;&gt;</span> <span class=\"mi\">16</span><span class=\"p\">,</span>\n                       <span class=\"p\">(</span><span class=\"n\">rgb_color</span> <span class=\"o\">&amp;</span> <span class=\"mh\">0x00FF00</span><span class=\"p\">)</span> <span class=\"o\">&gt;&gt;</span> <span class=\"mi\">8</span><span class=\"p\">,</span> <span class=\"n\">rgb_color</span> <span class=\"o\">&amp;</span> <span class=\"mh\">0x0000FF</span><span class=\"p\">,</span>\n                        <span class=\"n\">bright_percent</span><span class=\"p\">)</span></div>\n\n\n<div class=\"viewcode-block\" id=\"APA102.rotate\"><a class=\"viewcode-back\" href=\"../../../robot.drivers.html#robot.drivers.apa102.APA102.rotate\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">rotate</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">positions</span><span class=\"o\">=</span><span class=\"mi\">1</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot; Rotate the LEDs by the specified number of positions.</span>\n\n<span class=\"sd\">        Treating the internal LED array as a circular buffer, rotate it by</span>\n<span class=\"sd\">        the specified number of positions. The number could be negative,</span>\n<span class=\"sd\">        which means rotating in the opposite direction.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"n\">cutoff</span> <span class=\"o\">=</span> <span class=\"mi\">4</span> <span class=\"o\">*</span> <span class=\"p\">(</span><span class=\"n\">positions</span> <span class=\"o\">%</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">num_led</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">leds</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">leds</span><span class=\"p\">[</span><span class=\"n\">cutoff</span><span class=\"p\">:]</span> <span class=\"o\">+</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">leds</span><span class=\"p\">[:</span><span class=\"n\">cutoff</span><span class=\"p\">]</span></div>\n\n\n<div class=\"viewcode-block\" id=\"APA102.show\"><a class=\"viewcode-back\" href=\"../../../robot.drivers.html#robot.drivers.apa102.APA102.show\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">show</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;Sends the content of the pixel buffer to the strip.</span>\n\n<span class=\"sd\">        Todo: More than 1024 LEDs requires more than one xfer operation.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">clock_start_frame</span><span class=\"p\">()</span>\n        <span class=\"c1\"># xfer2 kills the list, unfortunately. So it must be copied first</span>\n        <span class=\"c1\"># SPI takes up to 4096 Integers. So we are fine for up to 1024 LEDs.</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">spi</span><span class=\"o\">.</span><span class=\"n\">xfer2</span><span class=\"p\">(</span><span class=\"nb\">list</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">leds</span><span class=\"p\">))</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">clock_end_frame</span><span class=\"p\">()</span></div>\n\n\n<div class=\"viewcode-block\" id=\"APA102.cleanup\"><a class=\"viewcode-back\" href=\"../../../robot.drivers.html#robot.drivers.apa102.APA102.cleanup\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">cleanup</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;Release the SPI device; Call this method at the end&quot;&quot;&quot;</span>\n\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">spi</span><span class=\"o\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>  <span class=\"c1\"># Close SPI port</span></div>\n\n<div class=\"viewcode-block\" id=\"APA102.combine_color\"><a class=\"viewcode-back\" href=\"../../../robot.drivers.html#robot.drivers.apa102.APA102.combine_color\">[文档]</a>    <span class=\"nd\">@staticmethod</span>\n    <span class=\"k\">def</span> <span class=\"nf\">combine_color</span><span class=\"p\">(</span><span class=\"n\">red</span><span class=\"p\">,</span> <span class=\"n\">green</span><span class=\"p\">,</span> <span class=\"n\">blue</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;Make one 3*8 byte color value.&quot;&quot;&quot;</span>\n\n        <span class=\"k\">return</span> <span class=\"p\">(</span><span class=\"n\">red</span> <span class=\"o\">&lt;&lt;</span> <span class=\"mi\">16</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"p\">(</span><span class=\"n\">green</span> <span class=\"o\">&lt;&lt;</span> <span class=\"mi\">8</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"n\">blue</span></div>\n\n\n<div class=\"viewcode-block\" id=\"APA102.wheel\"><a class=\"viewcode-back\" href=\"../../../robot.drivers.html#robot.drivers.apa102.APA102.wheel\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">wheel</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">wheel_pos</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;Get a color from a color wheel; Green -&gt; Red -&gt; Blue -&gt; Green&quot;&quot;&quot;</span>\n\n        <span class=\"k\">if</span> <span class=\"n\">wheel_pos</span> <span class=\"o\">&gt;</span> <span class=\"mi\">255</span><span class=\"p\">:</span>\n            <span class=\"n\">wheel_pos</span> <span class=\"o\">=</span> <span class=\"mi\">255</span> <span class=\"c1\"># Safeguard</span>\n        <span class=\"k\">if</span> <span class=\"n\">wheel_pos</span> <span class=\"o\">&lt;</span> <span class=\"mi\">85</span><span class=\"p\">:</span>  <span class=\"c1\"># Green -&gt; Red</span>\n            <span class=\"k\">return</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">combine_color</span><span class=\"p\">(</span><span class=\"n\">wheel_pos</span> <span class=\"o\">*</span> <span class=\"mi\">3</span><span class=\"p\">,</span> <span class=\"mi\">255</span> <span class=\"o\">-</span> <span class=\"n\">wheel_pos</span> <span class=\"o\">*</span> <span class=\"mi\">3</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">wheel_pos</span> <span class=\"o\">&lt;</span> <span class=\"mi\">170</span><span class=\"p\">:</span>  <span class=\"c1\"># Red -&gt; Blue</span>\n            <span class=\"n\">wheel_pos</span> <span class=\"o\">-=</span> <span class=\"mi\">85</span>\n            <span class=\"k\">return</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">combine_color</span><span class=\"p\">(</span><span class=\"mi\">255</span> <span class=\"o\">-</span> <span class=\"n\">wheel_pos</span> <span class=\"o\">*</span> <span class=\"mi\">3</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">wheel_pos</span> <span class=\"o\">*</span> <span class=\"mi\">3</span><span class=\"p\">)</span>\n        <span class=\"c1\"># Blue -&gt; Green</span>\n        <span class=\"n\">wheel_pos</span> <span class=\"o\">-=</span> <span class=\"mi\">170</span>\n        <span class=\"k\">return</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">combine_color</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">wheel_pos</span> <span class=\"o\">*</span> <span class=\"mi\">3</span><span class=\"p\">,</span> <span class=\"mi\">255</span> <span class=\"o\">-</span> <span class=\"n\">wheel_pos</span> <span class=\"o\">*</span> <span class=\"mi\">3</span><span class=\"p\">)</span></div>\n\n\n<div class=\"viewcode-block\" id=\"APA102.dump_array\"><a class=\"viewcode-back\" href=\"../../../robot.drivers.html#robot.drivers.apa102.APA102.dump_array\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">dump_array</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;For debug purposes: Dump the LED array onto the console.&quot;&quot;&quot;</span>\n\n        <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">leds</span><span class=\"p\">)</span></div></div>\n</pre></div>\n\n           </div>\n           \n          </div>\n          <footer>\n  \n\n  <hr/>\n\n  <div role=\"contentinfo\">\n    <p>\n        &copy; Copyright 2019, wzpan\n\n    </p>\n  </div>\n  Built with <a href=\"http://sphinx-doc.org/\">Sphinx</a> using a <a href=\"https://github.com/rtfd/sphinx_rtd_theme\">theme</a> provided by <a href=\"https://readthedocs.org\">Read the Docs</a>. \n\n</footer>\n\n        </div>\n      </div>\n\n    </section>\n\n  </div>\n  \n\n\n  <script type=\"text/javascript\">\n      jQuery(function () {\n          SphinxRtdTheme.Navigation.enable(true);\n      });\n  </script>\n\n  \n  \n    \n   \n\n</body>\n</html>"
  },
  {
    "path": "docs/_modules/robot/drivers/pixels.html",
    "content": "\n\n<!DOCTYPE html>\n<!--[if IE 8]><html class=\"no-js lt-ie9\" lang=\"zh-CN\" > <![endif]-->\n<!--[if gt IE 8]><!--> <html class=\"no-js\" lang=\"zh-CN\" > <!--<![endif]-->\n<head>\n  <meta charset=\"utf-8\">\n  \n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  \n  <title>robot.drivers.pixels &mdash; wukong-robot 1.2.0 文档</title>\n  \n\n  \n  \n  \n  \n\n  \n  <script type=\"text/javascript\" src=\"../../../_static/js/modernizr.min.js\"></script>\n  \n    \n      <script type=\"text/javascript\" id=\"documentation_options\" data-url_root=\"../../../\" src=\"../../../_static/documentation_options.js\"></script>\n        <script type=\"text/javascript\" src=\"../../../_static/jquery.js\"></script>\n        <script type=\"text/javascript\" src=\"../../../_static/underscore.js\"></script>\n        <script type=\"text/javascript\" src=\"../../../_static/doctools.js\"></script>\n        <script type=\"text/javascript\" src=\"../../../_static/language_data.js\"></script>\n        <script type=\"text/javascript\" src=\"../../../_static/translations.js\"></script>\n    \n    <script type=\"text/javascript\" src=\"../../../_static/js/theme.js\"></script>\n\n    \n\n  \n  <link rel=\"stylesheet\" href=\"../../../_static/css/theme.css\" type=\"text/css\" />\n  <link rel=\"stylesheet\" href=\"../../../_static/pygments.css\" type=\"text/css\" />\n    <link rel=\"index\" title=\"索引\" href=\"../../../genindex.html\" />\n    <link rel=\"search\" title=\"搜索\" href=\"../../../search.html\" /> \n</head>\n\n<body class=\"wy-body-for-nav\">\n\n   \n  <div class=\"wy-grid-for-nav\">\n    \n    <nav data-toggle=\"wy-nav-shift\" class=\"wy-nav-side\">\n      <div class=\"wy-side-scroll\">\n        <div class=\"wy-side-nav-search\" >\n          \n\n          \n            <a href=\"../../../index.html\" class=\"icon icon-home\"> wukong-robot\n          \n\n          \n          </a>\n\n          \n            \n            \n          \n\n          \n<div role=\"search\">\n  <form id=\"rtd-search-form\" class=\"wy-form\" action=\"../../../search.html\" method=\"get\">\n    <input type=\"text\" name=\"q\" placeholder=\"Search docs\" />\n    <input type=\"hidden\" name=\"check_keywords\" value=\"yes\" />\n    <input type=\"hidden\" name=\"area\" value=\"default\" />\n  </form>\n</div>\n\n          \n        </div>\n\n        <div class=\"wy-menu wy-menu-vertical\" data-spy=\"affix\" role=\"navigation\" aria-label=\"main navigation\">\n          \n            \n            \n              \n            \n            \n              <!-- Local TOC -->\n              <div class=\"local-toc\"></div>\n            \n          \n        </div>\n      </div>\n    </nav>\n\n    <section data-toggle=\"wy-nav-shift\" class=\"wy-nav-content-wrap\">\n\n      \n      <nav class=\"wy-nav-top\" aria-label=\"top navigation\">\n        \n          <i data-toggle=\"wy-nav-top\" class=\"fa fa-bars\"></i>\n          <a href=\"../../../index.html\">wukong-robot</a>\n        \n      </nav>\n\n\n      <div class=\"wy-nav-content\">\n        \n        <div class=\"rst-content\">\n        \n          \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<div role=\"navigation\" aria-label=\"breadcrumbs navigation\">\n\n  <ul class=\"wy-breadcrumbs\">\n    \n      <li><a href=\"../../../index.html\">Docs</a> &raquo;</li>\n        \n          <li><a href=\"../../index.html\">模块代码</a> &raquo;</li>\n        \n      <li>robot.drivers.pixels</li>\n    \n    \n      <li class=\"wy-breadcrumbs-aside\">\n        \n      </li>\n    \n  </ul>\n\n  \n  <hr/>\n</div>\n          <div role=\"main\" class=\"document\" itemscope=\"itemscope\" itemtype=\"http://schema.org/Article\">\n           <div itemprop=\"articleBody\">\n            \n  <h1>robot.drivers.pixels 源代码</h1><div class=\"highlight\"><pre>\n<span></span><span class=\"kn\">from</span> <span class=\"nn\">.</span> <span class=\"k\">import</span> <span class=\"n\">apa102</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">threading</span>\n<span class=\"k\">try</span><span class=\"p\">:</span>\n    <span class=\"kn\">import</span> <span class=\"nn\">queue</span> <span class=\"k\">as</span> <span class=\"nn\">Queue</span>\n<span class=\"k\">except</span> <span class=\"ne\">ImportError</span><span class=\"p\">:</span>\n    <span class=\"kn\">import</span> <span class=\"nn\">Queue</span> <span class=\"k\">as</span> <span class=\"nn\">Queue</span>\n\n\n<div class=\"viewcode-block\" id=\"Pixels\"><a class=\"viewcode-back\" href=\"../../../robot.drivers.html#robot.drivers.pixels.Pixels\">[文档]</a><span class=\"k\">class</span> <span class=\"nc\">Pixels</span><span class=\"p\">:</span>\n    <span class=\"n\">PIXELS_N</span> <span class=\"o\">=</span> <span class=\"mi\">3</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">basis</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"mi\">3</span> <span class=\"o\">*</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">PIXELS_N</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">basis</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">basis</span><span class=\"p\">[</span><span class=\"mi\">4</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">basis</span><span class=\"p\">[</span><span class=\"mi\">8</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"mi\">2</span>\n\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">colors</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"mi\">3</span> <span class=\"o\">*</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">PIXELS_N</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">dev</span> <span class=\"o\">=</span> <span class=\"n\">apa102</span><span class=\"o\">.</span><span class=\"n\">APA102</span><span class=\"p\">(</span><span class=\"n\">num_led</span><span class=\"o\">=</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">PIXELS_N</span><span class=\"p\">)</span>\n\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">next</span> <span class=\"o\">=</span> <span class=\"n\">threading</span><span class=\"o\">.</span><span class=\"n\">Event</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">queue</span> <span class=\"o\">=</span> <span class=\"n\">Queue</span><span class=\"o\">.</span><span class=\"n\">Queue</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">thread</span> <span class=\"o\">=</span> <span class=\"n\">threading</span><span class=\"o\">.</span><span class=\"n\">Thread</span><span class=\"p\">(</span><span class=\"n\">target</span><span class=\"o\">=</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_run</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">thread</span><span class=\"o\">.</span><span class=\"n\">daemon</span> <span class=\"o\">=</span> <span class=\"kc\">True</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">thread</span><span class=\"o\">.</span><span class=\"n\">start</span><span class=\"p\">()</span>\n\n<div class=\"viewcode-block\" id=\"Pixels.wakeup\"><a class=\"viewcode-back\" href=\"../../../robot.drivers.html#robot.drivers.pixels.Pixels.wakeup\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">wakeup</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">direction</span><span class=\"o\">=</span><span class=\"mi\">0</span><span class=\"p\">):</span>\n        <span class=\"k\">def</span> <span class=\"nf\">f</span><span class=\"p\">():</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_wakeup</span><span class=\"p\">(</span><span class=\"n\">direction</span><span class=\"p\">)</span>\n\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">next</span><span class=\"o\">.</span><span class=\"n\">set</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">queue</span><span class=\"o\">.</span><span class=\"n\">put</span><span class=\"p\">(</span><span class=\"n\">f</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"Pixels.listen\"><a class=\"viewcode-back\" href=\"../../../robot.drivers.html#robot.drivers.pixels.Pixels.listen\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">listen</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">next</span><span class=\"o\">.</span><span class=\"n\">set</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">queue</span><span class=\"o\">.</span><span class=\"n\">put</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_listen</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"Pixels.think\"><a class=\"viewcode-back\" href=\"../../../robot.drivers.html#robot.drivers.pixels.Pixels.think\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">think</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">next</span><span class=\"o\">.</span><span class=\"n\">set</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">queue</span><span class=\"o\">.</span><span class=\"n\">put</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_think</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"Pixels.speak\"><a class=\"viewcode-back\" href=\"../../../robot.drivers.html#robot.drivers.pixels.Pixels.speak\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">speak</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">next</span><span class=\"o\">.</span><span class=\"n\">set</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">queue</span><span class=\"o\">.</span><span class=\"n\">put</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_speak</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"Pixels.off\"><a class=\"viewcode-back\" href=\"../../../robot.drivers.html#robot.drivers.pixels.Pixels.off\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">off</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">next</span><span class=\"o\">.</span><span class=\"n\">set</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">queue</span><span class=\"o\">.</span><span class=\"n\">put</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_off</span><span class=\"p\">)</span></div>\n\n    <span class=\"k\">def</span> <span class=\"nf\">_run</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">while</span> <span class=\"kc\">True</span><span class=\"p\">:</span>\n            <span class=\"n\">func</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">queue</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">()</span>\n            <span class=\"n\">func</span><span class=\"p\">()</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">_wakeup</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">direction</span><span class=\"o\">=</span><span class=\"mi\">0</span><span class=\"p\">):</span>\n        <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"mi\">25</span><span class=\"p\">):</span>\n            <span class=\"n\">colors</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">i</span> <span class=\"o\">*</span> <span class=\"n\">v</span> <span class=\"k\">for</span> <span class=\"n\">v</span> <span class=\"ow\">in</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">basis</span><span class=\"p\">]</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"n\">colors</span><span class=\"p\">)</span>\n            <span class=\"n\">time</span><span class=\"o\">.</span><span class=\"n\">sleep</span><span class=\"p\">(</span><span class=\"mf\">0.01</span><span class=\"p\">)</span>\n\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">colors</span> <span class=\"o\">=</span> <span class=\"n\">colors</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">_listen</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"mi\">25</span><span class=\"p\">):</span>\n            <span class=\"n\">colors</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">i</span> <span class=\"o\">*</span> <span class=\"n\">v</span> <span class=\"k\">for</span> <span class=\"n\">v</span> <span class=\"ow\">in</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">basis</span><span class=\"p\">]</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"n\">colors</span><span class=\"p\">)</span>\n            <span class=\"n\">time</span><span class=\"o\">.</span><span class=\"n\">sleep</span><span class=\"p\">(</span><span class=\"mf\">0.01</span><span class=\"p\">)</span>\n\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">colors</span> <span class=\"o\">=</span> <span class=\"n\">colors</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">_think</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"n\">colors</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">colors</span>\n\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">next</span><span class=\"o\">.</span><span class=\"n\">clear</span><span class=\"p\">()</span>\n        <span class=\"k\">while</span> <span class=\"ow\">not</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">next</span><span class=\"o\">.</span><span class=\"n\">is_set</span><span class=\"p\">():</span>\n            <span class=\"n\">colors</span> <span class=\"o\">=</span> <span class=\"n\">colors</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">:]</span> <span class=\"o\">+</span> <span class=\"n\">colors</span><span class=\"p\">[:</span><span class=\"mi\">3</span><span class=\"p\">]</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"n\">colors</span><span class=\"p\">)</span>\n            <span class=\"n\">time</span><span class=\"o\">.</span><span class=\"n\">sleep</span><span class=\"p\">(</span><span class=\"mf\">0.2</span><span class=\"p\">)</span>\n\n        <span class=\"n\">t</span> <span class=\"o\">=</span> <span class=\"mf\">0.1</span>\n        <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">5</span><span class=\"p\">):</span>\n            <span class=\"n\">colors</span> <span class=\"o\">=</span> <span class=\"n\">colors</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"p\">:]</span> <span class=\"o\">+</span> <span class=\"n\">colors</span><span class=\"p\">[:</span><span class=\"mi\">3</span><span class=\"p\">]</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">write</span><span class=\"p\">([(</span><span class=\"n\">v</span> <span class=\"o\">*</span> <span class=\"p\">(</span><span class=\"mi\">4</span> <span class=\"o\">-</span> <span class=\"n\">i</span><span class=\"p\">)</span> <span class=\"o\">/</span> <span class=\"mi\">4</span><span class=\"p\">)</span> <span class=\"k\">for</span> <span class=\"n\">v</span> <span class=\"ow\">in</span> <span class=\"n\">colors</span><span class=\"p\">])</span>\n            <span class=\"n\">time</span><span class=\"o\">.</span><span class=\"n\">sleep</span><span class=\"p\">(</span><span class=\"n\">t</span><span class=\"p\">)</span>\n            <span class=\"n\">t</span> <span class=\"o\">/=</span> <span class=\"mi\">2</span>\n\n        <span class=\"c1\"># time.sleep(0.5)</span>\n\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">colors</span> <span class=\"o\">=</span> <span class=\"n\">colors</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">_speak</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"n\">colors</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">colors</span>\n\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">next</span><span class=\"o\">.</span><span class=\"n\">clear</span><span class=\"p\">()</span>\n        <span class=\"k\">while</span> <span class=\"ow\">not</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">next</span><span class=\"o\">.</span><span class=\"n\">is_set</span><span class=\"p\">():</span>\n            <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"mi\">5</span><span class=\"p\">,</span> <span class=\"mi\">25</span><span class=\"p\">):</span>\n                <span class=\"n\">colors</span> <span class=\"o\">=</span> <span class=\"p\">[(</span><span class=\"n\">v</span> <span class=\"o\">*</span> <span class=\"n\">i</span> <span class=\"o\">/</span> <span class=\"mi\">24</span><span class=\"p\">)</span> <span class=\"k\">for</span> <span class=\"n\">v</span> <span class=\"ow\">in</span> <span class=\"n\">colors</span><span class=\"p\">]</span>\n                <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"n\">colors</span><span class=\"p\">)</span>\n                <span class=\"n\">time</span><span class=\"o\">.</span><span class=\"n\">sleep</span><span class=\"p\">(</span><span class=\"mf\">0.01</span><span class=\"p\">)</span>\n\n            <span class=\"n\">time</span><span class=\"o\">.</span><span class=\"n\">sleep</span><span class=\"p\">(</span><span class=\"mf\">0.3</span><span class=\"p\">)</span>\n\n            <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"mi\">24</span><span class=\"p\">,</span> <span class=\"mi\">4</span><span class=\"p\">,</span> <span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">):</span>\n                <span class=\"n\">colors</span> <span class=\"o\">=</span> <span class=\"p\">[(</span><span class=\"n\">v</span> <span class=\"o\">*</span> <span class=\"n\">i</span> <span class=\"o\">/</span> <span class=\"mi\">24</span><span class=\"p\">)</span> <span class=\"k\">for</span> <span class=\"n\">v</span> <span class=\"ow\">in</span> <span class=\"n\">colors</span><span class=\"p\">]</span>\n                <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"n\">colors</span><span class=\"p\">)</span>\n                <span class=\"n\">time</span><span class=\"o\">.</span><span class=\"n\">sleep</span><span class=\"p\">(</span><span class=\"mf\">0.01</span><span class=\"p\">)</span>\n\n            <span class=\"n\">time</span><span class=\"o\">.</span><span class=\"n\">sleep</span><span class=\"p\">(</span><span class=\"mf\">0.3</span><span class=\"p\">)</span>\n\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_off</span><span class=\"p\">()</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">_off</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">write</span><span class=\"p\">([</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"mi\">3</span> <span class=\"o\">*</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">PIXELS_N</span><span class=\"p\">)</span>\n\n<div class=\"viewcode-block\" id=\"Pixels.write\"><a class=\"viewcode-back\" href=\"../../../robot.drivers.html#robot.drivers.pixels.Pixels.write\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">write</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">colors</span><span class=\"p\">):</span>\n        <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">PIXELS_N</span><span class=\"p\">):</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">dev</span><span class=\"o\">.</span><span class=\"n\">set_pixel</span><span class=\"p\">(</span><span class=\"n\">i</span><span class=\"p\">,</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">colors</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"o\">*</span><span class=\"n\">i</span><span class=\"p\">]),</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">colors</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"o\">*</span><span class=\"n\">i</span> <span class=\"o\">+</span> <span class=\"mi\">1</span><span class=\"p\">]),</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">colors</span><span class=\"p\">[</span><span class=\"mi\">3</span><span class=\"o\">*</span><span class=\"n\">i</span> <span class=\"o\">+</span> <span class=\"mi\">2</span><span class=\"p\">]))</span>\n\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">dev</span><span class=\"o\">.</span><span class=\"n\">show</span><span class=\"p\">()</span></div></div>\n\n\n<span class=\"n\">pixels</span> <span class=\"o\">=</span> <span class=\"n\">Pixels</span><span class=\"p\">()</span>\n\n\n<span class=\"k\">if</span> <span class=\"vm\">__name__</span> <span class=\"o\">==</span> <span class=\"s1\">&#39;__main__&#39;</span><span class=\"p\">:</span>\n    <span class=\"k\">while</span> <span class=\"kc\">True</span><span class=\"p\">:</span>\n\n        <span class=\"k\">try</span><span class=\"p\">:</span>\n            <span class=\"n\">pixels</span><span class=\"o\">.</span><span class=\"n\">wakeup</span><span class=\"p\">()</span>\n            <span class=\"n\">time</span><span class=\"o\">.</span><span class=\"n\">sleep</span><span class=\"p\">(</span><span class=\"mi\">3</span><span class=\"p\">)</span>\n            <span class=\"n\">pixels</span><span class=\"o\">.</span><span class=\"n\">think</span><span class=\"p\">()</span>\n            <span class=\"n\">time</span><span class=\"o\">.</span><span class=\"n\">sleep</span><span class=\"p\">(</span><span class=\"mi\">3</span><span class=\"p\">)</span>\n            <span class=\"n\">pixels</span><span class=\"o\">.</span><span class=\"n\">speak</span><span class=\"p\">()</span>\n            <span class=\"n\">time</span><span class=\"o\">.</span><span class=\"n\">sleep</span><span class=\"p\">(</span><span class=\"mi\">3</span><span class=\"p\">)</span>\n            <span class=\"n\">pixels</span><span class=\"o\">.</span><span class=\"n\">off</span><span class=\"p\">()</span>\n            <span class=\"n\">time</span><span class=\"o\">.</span><span class=\"n\">sleep</span><span class=\"p\">(</span><span class=\"mi\">3</span><span class=\"p\">)</span>\n        <span class=\"k\">except</span> <span class=\"ne\">KeyboardInterrupt</span><span class=\"p\">:</span>\n            <span class=\"k\">break</span>\n\n\n    <span class=\"n\">pixels</span><span class=\"o\">.</span><span class=\"n\">off</span><span class=\"p\">()</span>\n    <span class=\"n\">time</span><span class=\"o\">.</span><span class=\"n\">sleep</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n</pre></div>\n\n           </div>\n           \n          </div>\n          <footer>\n  \n\n  <hr/>\n\n  <div role=\"contentinfo\">\n    <p>\n        &copy; Copyright 2019, wzpan\n\n    </p>\n  </div>\n  Built with <a href=\"http://sphinx-doc.org/\">Sphinx</a> using a <a href=\"https://github.com/rtfd/sphinx_rtd_theme\">theme</a> provided by <a href=\"https://readthedocs.org\">Read the Docs</a>. \n\n</footer>\n\n        </div>\n      </div>\n\n    </section>\n\n  </div>\n  \n\n\n  <script type=\"text/javascript\">\n      jQuery(function () {\n          SphinxRtdTheme.Navigation.enable(true);\n      });\n  </script>\n\n  \n  \n    \n   \n\n</body>\n</html>"
  },
  {
    "path": "docs/_modules/robot/logging.html",
    "content": "\n\n<!DOCTYPE html>\n<!--[if IE 8]><html class=\"no-js lt-ie9\" lang=\"zh-CN\" > <![endif]-->\n<!--[if gt IE 8]><!--> <html class=\"no-js\" lang=\"zh-CN\" > <!--<![endif]-->\n<head>\n  <meta charset=\"utf-8\">\n  \n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  \n  <title>robot.logging &mdash; wukong-robot 1.2.0 文档</title>\n  \n\n  \n  \n  \n  \n\n  \n  <script type=\"text/javascript\" src=\"../../_static/js/modernizr.min.js\"></script>\n  \n    \n      <script type=\"text/javascript\" id=\"documentation_options\" data-url_root=\"../../\" src=\"../../_static/documentation_options.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/jquery.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/underscore.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/doctools.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/language_data.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/translations.js\"></script>\n    \n    <script type=\"text/javascript\" src=\"../../_static/js/theme.js\"></script>\n\n    \n\n  \n  <link rel=\"stylesheet\" href=\"../../_static/css/theme.css\" type=\"text/css\" />\n  <link rel=\"stylesheet\" href=\"../../_static/pygments.css\" type=\"text/css\" />\n    <link rel=\"index\" title=\"索引\" href=\"../../genindex.html\" />\n    <link rel=\"search\" title=\"搜索\" href=\"../../search.html\" /> \n</head>\n\n<body class=\"wy-body-for-nav\">\n\n   \n  <div class=\"wy-grid-for-nav\">\n    \n    <nav data-toggle=\"wy-nav-shift\" class=\"wy-nav-side\">\n      <div class=\"wy-side-scroll\">\n        <div class=\"wy-side-nav-search\" >\n          \n\n          \n            <a href=\"../../index.html\" class=\"icon icon-home\"> wukong-robot\n          \n\n          \n          </a>\n\n          \n            \n            \n          \n\n          \n<div role=\"search\">\n  <form id=\"rtd-search-form\" class=\"wy-form\" action=\"../../search.html\" method=\"get\">\n    <input type=\"text\" name=\"q\" placeholder=\"Search docs\" />\n    <input type=\"hidden\" name=\"check_keywords\" value=\"yes\" />\n    <input type=\"hidden\" name=\"area\" value=\"default\" />\n  </form>\n</div>\n\n          \n        </div>\n\n        <div class=\"wy-menu wy-menu-vertical\" data-spy=\"affix\" role=\"navigation\" aria-label=\"main navigation\">\n          \n            \n            \n              \n            \n            \n              <!-- Local TOC -->\n              <div class=\"local-toc\"></div>\n            \n          \n        </div>\n      </div>\n    </nav>\n\n    <section data-toggle=\"wy-nav-shift\" class=\"wy-nav-content-wrap\">\n\n      \n      <nav class=\"wy-nav-top\" aria-label=\"top navigation\">\n        \n          <i data-toggle=\"wy-nav-top\" class=\"fa fa-bars\"></i>\n          <a href=\"../../index.html\">wukong-robot</a>\n        \n      </nav>\n\n\n      <div class=\"wy-nav-content\">\n        \n        <div class=\"rst-content\">\n        \n          \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<div role=\"navigation\" aria-label=\"breadcrumbs navigation\">\n\n  <ul class=\"wy-breadcrumbs\">\n    \n      <li><a href=\"../../index.html\">Docs</a> &raquo;</li>\n        \n          <li><a href=\"../index.html\">模块代码</a> &raquo;</li>\n        \n      <li>robot.logging</li>\n    \n    \n      <li class=\"wy-breadcrumbs-aside\">\n        \n      </li>\n    \n  </ul>\n\n  \n  <hr/>\n</div>\n          <div role=\"main\" class=\"document\" itemscope=\"itemscope\" itemtype=\"http://schema.org/Article\">\n           <div itemprop=\"articleBody\">\n            \n  <h1>robot.logging 源代码</h1><div class=\"highlight\"><pre>\n<span></span><span class=\"kn\">import</span> <span class=\"nn\">logging</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">from</span> <span class=\"nn\">robot</span> <span class=\"k\">import</span> <span class=\"n\">constants</span>\n<span class=\"kn\">from</span> <span class=\"nn\">logging.handlers</span> <span class=\"k\">import</span> <span class=\"n\">RotatingFileHandler</span>\n\n<span class=\"n\">PAGE</span> <span class=\"o\">=</span> <span class=\"mi\">4096</span>\n\n<span class=\"n\">DEBUG</span> <span class=\"o\">=</span> <span class=\"n\">logging</span><span class=\"o\">.</span><span class=\"n\">DEBUG</span>\n<span class=\"n\">INFO</span> <span class=\"o\">=</span> <span class=\"n\">logging</span><span class=\"o\">.</span><span class=\"n\">INFO</span>\n<span class=\"n\">WARNING</span> <span class=\"o\">=</span> <span class=\"n\">logging</span><span class=\"o\">.</span><span class=\"n\">WARNING</span>\n<span class=\"n\">ERROR</span> <span class=\"o\">=</span> <span class=\"n\">logging</span><span class=\"o\">.</span><span class=\"n\">ERROR</span>\n\n<div class=\"viewcode-block\" id=\"tail\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.logging.tail\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">tail</span><span class=\"p\">(</span><span class=\"n\">filepath</span><span class=\"p\">,</span> <span class=\"n\">n</span><span class=\"o\">=</span><span class=\"mi\">10</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    实现 tail -n</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"n\">res</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;&quot;</span>\n    <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">filepath</span><span class=\"p\">,</span> <span class=\"s1\">&#39;rb&#39;</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n        <span class=\"n\">f_len</span> <span class=\"o\">=</span> <span class=\"n\">f</span><span class=\"o\">.</span><span class=\"n\">seek</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">)</span>\n        <span class=\"n\">rem</span> <span class=\"o\">=</span> <span class=\"n\">f_len</span> <span class=\"o\">%</span> <span class=\"n\">PAGE</span>\n        <span class=\"n\">page_n</span> <span class=\"o\">=</span> <span class=\"n\">f_len</span> <span class=\"o\">//</span> <span class=\"n\">PAGE</span>\n        <span class=\"n\">r_len</span> <span class=\"o\">=</span> <span class=\"n\">rem</span> <span class=\"k\">if</span> <span class=\"n\">rem</span> <span class=\"k\">else</span> <span class=\"n\">PAGE</span>\n        <span class=\"k\">while</span> <span class=\"kc\">True</span><span class=\"p\">:</span>\n            <span class=\"c1\"># 如果读取的页大小&gt;=文件大小，直接读取数据输出</span>\n            <span class=\"k\">if</span> <span class=\"n\">r_len</span> <span class=\"o\">&gt;=</span> <span class=\"n\">f_len</span><span class=\"p\">:</span>\n                <span class=\"n\">f</span><span class=\"o\">.</span><span class=\"n\">seek</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">)</span>\n                <span class=\"n\">lines</span> <span class=\"o\">=</span> <span class=\"n\">f</span><span class=\"o\">.</span><span class=\"n\">readlines</span><span class=\"p\">()[::</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n                <span class=\"k\">break</span>\n\n            <span class=\"n\">f</span><span class=\"o\">.</span><span class=\"n\">seek</span><span class=\"p\">(</span><span class=\"o\">-</span><span class=\"n\">r_len</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">)</span>\n            <span class=\"c1\"># print(&#39;f_len: {}, rem: {}, page_n: {}, r_len: {}&#39;.format(f_len, rem, page_n, r_len))</span>\n            <span class=\"n\">lines</span> <span class=\"o\">=</span> <span class=\"n\">f</span><span class=\"o\">.</span><span class=\"n\">readlines</span><span class=\"p\">()[::</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n            <span class=\"n\">count</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">lines</span><span class=\"p\">)</span> <span class=\"o\">-</span><span class=\"mi\">1</span>   <span class=\"c1\"># 末行可能不完整，减一行，加大读取量</span>\n\n            <span class=\"k\">if</span> <span class=\"n\">count</span> <span class=\"o\">&gt;=</span> <span class=\"n\">n</span><span class=\"p\">:</span>  <span class=\"c1\"># 如果读取到的行数&gt;=指定行数，则退出循环读取数据</span>\n                <span class=\"k\">break</span>\n            <span class=\"k\">else</span><span class=\"p\">:</span>   <span class=\"c1\"># 如果读取行数不够，载入更多的页大小读取数据</span>\n                <span class=\"n\">r_len</span> <span class=\"o\">+=</span> <span class=\"n\">PAGE</span>\n                <span class=\"n\">page_n</span> <span class=\"o\">-=</span> <span class=\"mi\">1</span>\n\n    <span class=\"k\">for</span> <span class=\"n\">line</span> <span class=\"ow\">in</span> <span class=\"n\">lines</span><span class=\"p\">[:</span><span class=\"n\">n</span><span class=\"p\">][::</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">]:</span>\n        <span class=\"n\">res</span> <span class=\"o\">+=</span> <span class=\"n\">line</span><span class=\"o\">.</span><span class=\"n\">decode</span><span class=\"p\">(</span><span class=\"s1\">&#39;utf-8&#39;</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">res</span></div>\n\n<div class=\"viewcode-block\" id=\"getLogger\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.logging.getLogger\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">getLogger</span><span class=\"p\">(</span><span class=\"n\">name</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot; </span>\n<span class=\"sd\">    作用同标准模块 logging.getLogger(name) </span>\n<span class=\"sd\">    </span>\n<span class=\"sd\">    :returns: logger</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"n\">formatter</span> <span class=\"o\">=</span> <span class=\"n\">logging</span><span class=\"o\">.</span><span class=\"n\">Formatter</span><span class=\"p\">(</span><span class=\"s1\">&#39;</span><span class=\"si\">%(asctime)s</span><span class=\"s1\"> - </span><span class=\"si\">%(name)s</span><span class=\"s1\"> - </span><span class=\"si\">%(levelname)s</span><span class=\"s1\"> - </span><span class=\"si\">%(message)s</span><span class=\"s1\">&#39;</span><span class=\"p\">)</span>\n\n    <span class=\"n\">logger</span> <span class=\"o\">=</span> <span class=\"n\">logging</span><span class=\"o\">.</span><span class=\"n\">getLogger</span><span class=\"p\">(</span><span class=\"n\">name</span><span class=\"p\">)</span>\n    <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">setLevel</span><span class=\"p\">(</span><span class=\"n\">logging</span><span class=\"o\">.</span><span class=\"n\">INFO</span><span class=\"p\">)</span>\n    \n    <span class=\"c1\"># FileHandler</span>\n    <span class=\"n\">file_handler</span> <span class=\"o\">=</span> <span class=\"n\">RotatingFileHandler</span><span class=\"p\">(</span><span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">constants</span><span class=\"o\">.</span><span class=\"n\">TEMP_PATH</span><span class=\"p\">,</span> <span class=\"s1\">&#39;wukong.log&#39;</span><span class=\"p\">),</span> <span class=\"n\">maxBytes</span><span class=\"o\">=</span><span class=\"mi\">1024</span><span class=\"o\">*</span><span class=\"mi\">1024</span><span class=\"p\">,</span><span class=\"n\">backupCount</span><span class=\"o\">=</span><span class=\"mi\">5</span><span class=\"p\">)</span>\n    <span class=\"n\">file_handler</span><span class=\"o\">.</span><span class=\"n\">setLevel</span><span class=\"p\">(</span><span class=\"n\">level</span><span class=\"o\">=</span><span class=\"n\">logging</span><span class=\"o\">.</span><span class=\"n\">DEBUG</span><span class=\"p\">)</span>\n    <span class=\"n\">file_handler</span><span class=\"o\">.</span><span class=\"n\">setFormatter</span><span class=\"p\">(</span><span class=\"n\">formatter</span><span class=\"p\">)</span>\n    <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">addHandler</span><span class=\"p\">(</span><span class=\"n\">file_handler</span><span class=\"p\">)</span>\n\n    <span class=\"k\">return</span> <span class=\"n\">logger</span></div>\n\n<div class=\"viewcode-block\" id=\"readLog\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.logging.readLog\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">readLog</span><span class=\"p\">(</span><span class=\"n\">lines</span><span class=\"o\">=</span><span class=\"mi\">200</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot; </span>\n<span class=\"sd\">    获取最新的指定行数的 log</span>\n\n<span class=\"sd\">    :param lines: 最大的行数</span>\n<span class=\"sd\">    :returns: 最新指定行数的 log</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"n\">log_path</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">constants</span><span class=\"o\">.</span><span class=\"n\">TEMP_PATH</span><span class=\"p\">,</span> <span class=\"s1\">&#39;wukong.log&#39;</span><span class=\"p\">)</span>\n    <span class=\"k\">if</span> <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">exists</span><span class=\"p\">(</span><span class=\"n\">log_path</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"n\">tail</span><span class=\"p\">(</span><span class=\"n\">log_path</span><span class=\"p\">,</span> <span class=\"n\">lines</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"s1\">&#39;&#39;</span></div>\n    \n</pre></div>\n\n           </div>\n           \n          </div>\n          <footer>\n  \n\n  <hr/>\n\n  <div role=\"contentinfo\">\n    <p>\n        &copy; Copyright 2019, wzpan\n\n    </p>\n  </div>\n  Built with <a href=\"http://sphinx-doc.org/\">Sphinx</a> using a <a href=\"https://github.com/rtfd/sphinx_rtd_theme\">theme</a> provided by <a href=\"https://readthedocs.org\">Read the Docs</a>. \n\n</footer>\n\n        </div>\n      </div>\n\n    </section>\n\n  </div>\n  \n\n\n  <script type=\"text/javascript\">\n      jQuery(function () {\n          SphinxRtdTheme.Navigation.enable(true);\n      });\n  </script>\n\n  \n  \n    \n   \n\n</body>\n</html>"
  },
  {
    "path": "docs/_modules/robot/plugin_loader.html",
    "content": "\n\n<!DOCTYPE html>\n<!--[if IE 8]><html class=\"no-js lt-ie9\" lang=\"zh-CN\" > <![endif]-->\n<!--[if gt IE 8]><!--> <html class=\"no-js\" lang=\"zh-CN\" > <!--<![endif]-->\n<head>\n  <meta charset=\"utf-8\">\n  \n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  \n  <title>robot.plugin_loader &mdash; wukong-robot 1.2.0 文档</title>\n  \n\n  \n  \n  \n  \n\n  \n  <script type=\"text/javascript\" src=\"../../_static/js/modernizr.min.js\"></script>\n  \n    \n      <script type=\"text/javascript\" id=\"documentation_options\" data-url_root=\"../../\" src=\"../../_static/documentation_options.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/jquery.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/underscore.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/doctools.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/language_data.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/translations.js\"></script>\n    \n    <script type=\"text/javascript\" src=\"../../_static/js/theme.js\"></script>\n\n    \n\n  \n  <link rel=\"stylesheet\" href=\"../../_static/css/theme.css\" type=\"text/css\" />\n  <link rel=\"stylesheet\" href=\"../../_static/pygments.css\" type=\"text/css\" />\n    <link rel=\"index\" title=\"索引\" href=\"../../genindex.html\" />\n    <link rel=\"search\" title=\"搜索\" href=\"../../search.html\" /> \n</head>\n\n<body class=\"wy-body-for-nav\">\n\n   \n  <div class=\"wy-grid-for-nav\">\n    \n    <nav data-toggle=\"wy-nav-shift\" class=\"wy-nav-side\">\n      <div class=\"wy-side-scroll\">\n        <div class=\"wy-side-nav-search\" >\n          \n\n          \n            <a href=\"../../index.html\" class=\"icon icon-home\"> wukong-robot\n          \n\n          \n          </a>\n\n          \n            \n            \n          \n\n          \n<div role=\"search\">\n  <form id=\"rtd-search-form\" class=\"wy-form\" action=\"../../search.html\" method=\"get\">\n    <input type=\"text\" name=\"q\" placeholder=\"Search docs\" />\n    <input type=\"hidden\" name=\"check_keywords\" value=\"yes\" />\n    <input type=\"hidden\" name=\"area\" value=\"default\" />\n  </form>\n</div>\n\n          \n        </div>\n\n        <div class=\"wy-menu wy-menu-vertical\" data-spy=\"affix\" role=\"navigation\" aria-label=\"main navigation\">\n          \n            \n            \n              \n            \n            \n              <!-- Local TOC -->\n              <div class=\"local-toc\"></div>\n            \n          \n        </div>\n      </div>\n    </nav>\n\n    <section data-toggle=\"wy-nav-shift\" class=\"wy-nav-content-wrap\">\n\n      \n      <nav class=\"wy-nav-top\" aria-label=\"top navigation\">\n        \n          <i data-toggle=\"wy-nav-top\" class=\"fa fa-bars\"></i>\n          <a href=\"../../index.html\">wukong-robot</a>\n        \n      </nav>\n\n\n      <div class=\"wy-nav-content\">\n        \n        <div class=\"rst-content\">\n        \n          \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<div role=\"navigation\" aria-label=\"breadcrumbs navigation\">\n\n  <ul class=\"wy-breadcrumbs\">\n    \n      <li><a href=\"../../index.html\">Docs</a> &raquo;</li>\n        \n          <li><a href=\"../index.html\">模块代码</a> &raquo;</li>\n        \n      <li>robot.plugin_loader</li>\n    \n    \n      <li class=\"wy-breadcrumbs-aside\">\n        \n      </li>\n    \n  </ul>\n\n  \n  <hr/>\n</div>\n          <div role=\"main\" class=\"document\" itemscope=\"itemscope\" itemtype=\"http://schema.org/Article\">\n           <div itemprop=\"articleBody\">\n            \n  <h1>robot.plugin_loader 源代码</h1><div class=\"highlight\"><pre>\n<span></span><span class=\"c1\"># -*- coding: utf-8-*-</span>\n<span class=\"kn\">import</span> <span class=\"nn\">pkgutil</span>\n<span class=\"kn\">from</span> <span class=\"nn\">.</span> <span class=\"k\">import</span> <span class=\"n\">constants</span>\n<span class=\"kn\">from</span> <span class=\"nn\">.</span> <span class=\"k\">import</span> <span class=\"n\">config</span>\n<span class=\"kn\">from</span> <span class=\"nn\">robot</span> <span class=\"k\">import</span> <span class=\"n\">logging</span>\n<span class=\"kn\">from</span> <span class=\"nn\">robot.sdk.AbstractPlugin</span> <span class=\"k\">import</span> <span class=\"n\">AbstractPlugin</span>\n\n<span class=\"n\">logger</span> <span class=\"o\">=</span> <span class=\"n\">logging</span><span class=\"o\">.</span><span class=\"n\">getLogger</span><span class=\"p\">(</span><span class=\"vm\">__name__</span><span class=\"p\">)</span>\n<span class=\"n\">_has_init</span> <span class=\"o\">=</span> <span class=\"kc\">False</span>\n\n<span class=\"c1\"># plugins run at query</span>\n<span class=\"n\">_plugins_query</span> <span class=\"o\">=</span> <span class=\"p\">[]</span>\n\n<div class=\"viewcode-block\" id=\"init_plugins\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.plugin_loader.init_plugins\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">init_plugins</span><span class=\"p\">(</span><span class=\"n\">con</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    动态加载技能插件</span>\n\n<span class=\"sd\">    参数：</span>\n<span class=\"sd\">    con -- 会话模块</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n\n    <span class=\"k\">global</span> <span class=\"n\">_has_init</span>\n    <span class=\"n\">locations</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n        <span class=\"n\">constants</span><span class=\"o\">.</span><span class=\"n\">PLUGIN_PATH</span><span class=\"p\">,</span>\n        <span class=\"n\">constants</span><span class=\"o\">.</span><span class=\"n\">CONTRIB_PATH</span><span class=\"p\">,</span>\n        <span class=\"n\">constants</span><span class=\"o\">.</span><span class=\"n\">CUSTOM_PATH</span>\n    <span class=\"p\">]</span>\n    <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">debug</span><span class=\"p\">(</span><span class=\"s2\">&quot;检查插件目录：</span><span class=\"si\">{}</span><span class=\"s2\">&quot;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">locations</span><span class=\"p\">))</span>\n\n    <span class=\"k\">global</span> <span class=\"n\">_plugins_query</span>\n    <span class=\"n\">nameSet</span> <span class=\"o\">=</span> <span class=\"nb\">set</span><span class=\"p\">()</span>\n\n    <span class=\"k\">for</span> <span class=\"n\">finder</span><span class=\"p\">,</span> <span class=\"n\">name</span><span class=\"p\">,</span> <span class=\"n\">ispkg</span> <span class=\"ow\">in</span> <span class=\"n\">pkgutil</span><span class=\"o\">.</span><span class=\"n\">walk_packages</span><span class=\"p\">(</span><span class=\"n\">locations</span><span class=\"p\">):</span>\n        <span class=\"k\">try</span><span class=\"p\">:</span>\n            <span class=\"n\">loader</span> <span class=\"o\">=</span> <span class=\"n\">finder</span><span class=\"o\">.</span><span class=\"n\">find_module</span><span class=\"p\">(</span><span class=\"n\">name</span><span class=\"p\">)</span>\n            <span class=\"n\">mod</span> <span class=\"o\">=</span> <span class=\"n\">loader</span><span class=\"o\">.</span><span class=\"n\">load_module</span><span class=\"p\">(</span><span class=\"n\">name</span><span class=\"p\">)</span>\n        <span class=\"k\">except</span> <span class=\"ne\">Exception</span><span class=\"p\">:</span>\n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">warning</span><span class=\"p\">(</span><span class=\"s2\">&quot;插件 </span><span class=\"si\">{}</span><span class=\"s2\"> 加载出错，跳过&quot;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">name</span><span class=\"p\">),</span>\n                            <span class=\"n\">exc_info</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">)</span>\n            <span class=\"k\">continue</span>\n\n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"nb\">hasattr</span><span class=\"p\">(</span><span class=\"n\">mod</span><span class=\"p\">,</span> <span class=\"s1\">&#39;Plugin&#39;</span><span class=\"p\">):</span>\n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">debug</span><span class=\"p\">(</span><span class=\"s2\">&quot;模块 </span><span class=\"si\">{}</span><span class=\"s2\"> 非插件，跳过&quot;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">name</span><span class=\"p\">))</span>\n            <span class=\"k\">continue</span>\n\n        <span class=\"c1\"># plugins run at query</span>\n        <span class=\"n\">plugin</span> <span class=\"o\">=</span> <span class=\"n\">mod</span><span class=\"o\">.</span><span class=\"n\">Plugin</span><span class=\"p\">(</span><span class=\"n\">con</span><span class=\"p\">)</span>\n\n        <span class=\"k\">if</span> <span class=\"n\">plugin</span><span class=\"o\">.</span><span class=\"n\">SLUG</span> <span class=\"o\">==</span> <span class=\"s1\">&#39;AbstractPlugin&#39;</span><span class=\"p\">:</span>\n            <span class=\"n\">plugin</span><span class=\"o\">.</span><span class=\"n\">SLUG</span> <span class=\"o\">=</span> <span class=\"n\">name</span>\n\n        <span class=\"c1\"># check conflict</span>\n        <span class=\"k\">if</span> <span class=\"n\">plugin</span><span class=\"o\">.</span><span class=\"n\">SLUG</span> <span class=\"ow\">in</span> <span class=\"n\">nameSet</span><span class=\"p\">:</span>\n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">warning</span><span class=\"p\">(</span><span class=\"s2\">&quot;插件 </span><span class=\"si\">{}</span><span class=\"s2\"> SLUG(</span><span class=\"si\">{}</span><span class=\"s2\">) 重复，跳过&quot;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">name</span><span class=\"p\">,</span>\n                                                                 <span class=\"n\">plugin</span><span class=\"o\">.</span><span class=\"n\">SLUG</span><span class=\"p\">))</span>\n            <span class=\"k\">continue</span>\n        <span class=\"n\">nameSet</span><span class=\"o\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">plugin</span><span class=\"o\">.</span><span class=\"n\">SLUG</span><span class=\"p\">)</span>\n\n        <span class=\"c1\"># whether a plugin is enabled</span>\n        <span class=\"k\">if</span> <span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">has</span><span class=\"p\">(</span><span class=\"n\">plugin</span><span class=\"o\">.</span><span class=\"n\">SLUG</span><span class=\"p\">)</span> <span class=\"ow\">and</span> <span class=\"s1\">&#39;enable&#39;</span> <span class=\"ow\">in</span> <span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">plugin</span><span class=\"o\">.</span><span class=\"n\">SLUG</span><span class=\"p\">):</span>\n            <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">plugin</span><span class=\"o\">.</span><span class=\"n\">SLUG</span><span class=\"p\">)[</span><span class=\"s1\">&#39;enable&#39;</span><span class=\"p\">]:</span>\n                <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s2\">&quot;插件 </span><span class=\"si\">{}</span><span class=\"s2\"> 已被禁用&quot;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">name</span><span class=\"p\">))</span>\n                <span class=\"k\">continue</span>\n\n        <span class=\"k\">if</span> <span class=\"nb\">issubclass</span><span class=\"p\">(</span><span class=\"n\">mod</span><span class=\"o\">.</span><span class=\"n\">Plugin</span><span class=\"p\">,</span> <span class=\"n\">AbstractPlugin</span><span class=\"p\">):</span>\n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s2\">&quot;插件 </span><span class=\"si\">{}</span><span class=\"s2\"> 加载成功 &quot;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">name</span><span class=\"p\">))</span>\n            <span class=\"n\">_plugins_query</span><span class=\"o\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">plugin</span><span class=\"p\">)</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">sort_priority</span><span class=\"p\">(</span><span class=\"n\">m</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"nb\">hasattr</span><span class=\"p\">(</span><span class=\"n\">m</span><span class=\"p\">,</span> <span class=\"s1\">&#39;PRIORITY&#39;</span><span class=\"p\">):</span>\n            <span class=\"k\">return</span> <span class=\"n\">m</span><span class=\"o\">.</span><span class=\"n\">PRIORITY</span>\n        <span class=\"k\">return</span> <span class=\"mi\">0</span>\n\n    <span class=\"n\">_plugins_query</span><span class=\"o\">.</span><span class=\"n\">sort</span><span class=\"p\">(</span><span class=\"n\">key</span><span class=\"o\">=</span><span class=\"n\">sort_priority</span><span class=\"p\">,</span> <span class=\"n\">reverse</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">)</span>\n    <span class=\"n\">_has_init</span> <span class=\"o\">=</span> <span class=\"kc\">True</span></div>\n\n\n<div class=\"viewcode-block\" id=\"get_plugins\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.plugin_loader.get_plugins\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">get_plugins</span><span class=\"p\">(</span><span class=\"n\">con</span><span class=\"p\">):</span>\n    <span class=\"k\">global</span> <span class=\"n\">_plugins_query</span>\n    <span class=\"n\">_plugins_query</span> <span class=\"o\">=</span> <span class=\"p\">[]</span>\n    <span class=\"n\">init_plugins</span><span class=\"p\">(</span><span class=\"n\">con</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">_plugins_query</span></div>\n\n</pre></div>\n\n           </div>\n           \n          </div>\n          <footer>\n  \n\n  <hr/>\n\n  <div role=\"contentinfo\">\n    <p>\n        &copy; Copyright 2019, wzpan\n\n    </p>\n  </div>\n  Built with <a href=\"http://sphinx-doc.org/\">Sphinx</a> using a <a href=\"https://github.com/rtfd/sphinx_rtd_theme\">theme</a> provided by <a href=\"https://readthedocs.org\">Read the Docs</a>. \n\n</footer>\n\n        </div>\n      </div>\n\n    </section>\n\n  </div>\n  \n\n\n  <script type=\"text/javascript\">\n      jQuery(function () {\n          SphinxRtdTheme.Navigation.enable(true);\n      });\n  </script>\n\n  \n  \n    \n   \n\n</body>\n</html>"
  },
  {
    "path": "docs/_modules/robot/sdk/AbstractPlugin.html",
    "content": "\n\n<!DOCTYPE html>\n<!--[if IE 8]><html class=\"no-js lt-ie9\" lang=\"zh-CN\" > <![endif]-->\n<!--[if gt IE 8]><!--> <html class=\"no-js\" lang=\"zh-CN\" > <!--<![endif]-->\n<head>\n  <meta charset=\"utf-8\">\n  \n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  \n  <title>robot.sdk.AbstractPlugin &mdash; wukong-robot 1.2.0 文档</title>\n  \n\n  \n  \n  \n  \n\n  \n  <script type=\"text/javascript\" src=\"../../../_static/js/modernizr.min.js\"></script>\n  \n    \n      <script type=\"text/javascript\" id=\"documentation_options\" data-url_root=\"../../../\" src=\"../../../_static/documentation_options.js\"></script>\n        <script type=\"text/javascript\" src=\"../../../_static/jquery.js\"></script>\n        <script type=\"text/javascript\" src=\"../../../_static/underscore.js\"></script>\n        <script type=\"text/javascript\" src=\"../../../_static/doctools.js\"></script>\n        <script type=\"text/javascript\" src=\"../../../_static/language_data.js\"></script>\n        <script type=\"text/javascript\" src=\"../../../_static/translations.js\"></script>\n    \n    <script type=\"text/javascript\" src=\"../../../_static/js/theme.js\"></script>\n\n    \n\n  \n  <link rel=\"stylesheet\" href=\"../../../_static/css/theme.css\" type=\"text/css\" />\n  <link rel=\"stylesheet\" href=\"../../../_static/pygments.css\" type=\"text/css\" />\n    <link rel=\"index\" title=\"索引\" href=\"../../../genindex.html\" />\n    <link rel=\"search\" title=\"搜索\" href=\"../../../search.html\" /> \n</head>\n\n<body class=\"wy-body-for-nav\">\n\n   \n  <div class=\"wy-grid-for-nav\">\n    \n    <nav data-toggle=\"wy-nav-shift\" class=\"wy-nav-side\">\n      <div class=\"wy-side-scroll\">\n        <div class=\"wy-side-nav-search\" >\n          \n\n          \n            <a href=\"../../../index.html\" class=\"icon icon-home\"> wukong-robot\n          \n\n          \n          </a>\n\n          \n            \n            \n          \n\n          \n<div role=\"search\">\n  <form id=\"rtd-search-form\" class=\"wy-form\" action=\"../../../search.html\" method=\"get\">\n    <input type=\"text\" name=\"q\" placeholder=\"Search docs\" />\n    <input type=\"hidden\" name=\"check_keywords\" value=\"yes\" />\n    <input type=\"hidden\" name=\"area\" value=\"default\" />\n  </form>\n</div>\n\n          \n        </div>\n\n        <div class=\"wy-menu wy-menu-vertical\" data-spy=\"affix\" role=\"navigation\" aria-label=\"main navigation\">\n          \n            \n            \n              \n            \n            \n              <!-- Local TOC -->\n              <div class=\"local-toc\"></div>\n            \n          \n        </div>\n      </div>\n    </nav>\n\n    <section data-toggle=\"wy-nav-shift\" class=\"wy-nav-content-wrap\">\n\n      \n      <nav class=\"wy-nav-top\" aria-label=\"top navigation\">\n        \n          <i data-toggle=\"wy-nav-top\" class=\"fa fa-bars\"></i>\n          <a href=\"../../../index.html\">wukong-robot</a>\n        \n      </nav>\n\n\n      <div class=\"wy-nav-content\">\n        \n        <div class=\"rst-content\">\n        \n          \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<div role=\"navigation\" aria-label=\"breadcrumbs navigation\">\n\n  <ul class=\"wy-breadcrumbs\">\n    \n      <li><a href=\"../../../index.html\">Docs</a> &raquo;</li>\n        \n          <li><a href=\"../../index.html\">模块代码</a> &raquo;</li>\n        \n      <li>robot.sdk.AbstractPlugin</li>\n    \n    \n      <li class=\"wy-breadcrumbs-aside\">\n        \n      </li>\n    \n  </ul>\n\n  \n  <hr/>\n</div>\n          <div role=\"main\" class=\"document\" itemscope=\"itemscope\" itemtype=\"http://schema.org/Article\">\n           <div itemprop=\"articleBody\">\n            \n  <h1>robot.sdk.AbstractPlugin 源代码</h1><div class=\"highlight\"><pre>\n<span></span><span class=\"kn\">from</span> <span class=\"nn\">abc</span> <span class=\"k\">import</span> <span class=\"n\">ABCMeta</span><span class=\"p\">,</span> <span class=\"n\">abstractmethod</span>\n<span class=\"kn\">from</span> <span class=\"nn\">robot</span> <span class=\"k\">import</span> <span class=\"n\">constants</span>\n<span class=\"kn\">from</span> <span class=\"nn\">robot</span> <span class=\"k\">import</span> <span class=\"n\">logging</span>\n<span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n\n<span class=\"n\">logger</span> <span class=\"o\">=</span> <span class=\"n\">logging</span><span class=\"o\">.</span><span class=\"n\">getLogger</span><span class=\"p\">(</span><span class=\"vm\">__name__</span><span class=\"p\">)</span>\n\n<span class=\"k\">try</span><span class=\"p\">:</span>\n    <span class=\"n\">sys</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">constants</span><span class=\"o\">.</span><span class=\"n\">CONTRIB_PATH</span><span class=\"p\">)</span>\n<span class=\"k\">except</span> <span class=\"ne\">Exception</span> <span class=\"k\">as</span> <span class=\"n\">e</span><span class=\"p\">:</span>\n    <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">debug</span><span class=\"p\">(</span><span class=\"s2\">&quot;未检测到插件目录,Error:</span><span class=\"si\">{}</span><span class=\"s2\">&quot;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">e</span><span class=\"p\">))</span>\n    \n<div class=\"viewcode-block\" id=\"AbstractPlugin\"><a class=\"viewcode-back\" href=\"../../../robot.sdk.html#robot.sdk.AbstractPlugin.AbstractPlugin\">[文档]</a><span class=\"k\">class</span> <span class=\"nc\">AbstractPlugin</span><span class=\"p\">(</span><span class=\"n\">metaclass</span><span class=\"o\">=</span><span class=\"n\">ABCMeta</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot; 技能插件基类 &quot;&quot;&quot;</span>\n\n    <span class=\"n\">SLUG</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;AbstractPlugin&#39;</span>\n    <span class=\"n\">IS_IMMERSIVE</span> <span class=\"o\">=</span> <span class=\"kc\">False</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">con</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">IS_IMMERSIVE</span> <span class=\"ow\">is</span> <span class=\"ow\">not</span> <span class=\"kc\">None</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">isImmersive</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">IS_IMMERSIVE</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">isImmersive</span> <span class=\"o\">=</span> <span class=\"kc\">False</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">priority</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">con</span> <span class=\"o\">=</span> <span class=\"n\">con</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">nlu</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">con</span><span class=\"o\">.</span><span class=\"n\">nlu</span>\n\n<div class=\"viewcode-block\" id=\"AbstractPlugin.play\"><a class=\"viewcode-back\" href=\"../../../robot.sdk.html#robot.sdk.AbstractPlugin.AbstractPlugin.play\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">play</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">src</span><span class=\"p\">,</span> <span class=\"n\">delete</span><span class=\"o\">=</span><span class=\"kc\">False</span><span class=\"p\">,</span> <span class=\"n\">onCompleted</span><span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">,</span> <span class=\"n\">volume</span><span class=\"o\">=</span><span class=\"mi\">1</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">con</span><span class=\"o\">.</span><span class=\"n\">play</span><span class=\"p\">(</span><span class=\"n\">src</span><span class=\"p\">,</span> <span class=\"n\">delete</span><span class=\"p\">,</span> <span class=\"n\">onCompleted</span><span class=\"p\">,</span> <span class=\"n\">volume</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"AbstractPlugin.say\"><a class=\"viewcode-back\" href=\"../../../robot.sdk.html#robot.sdk.AbstractPlugin.AbstractPlugin.say\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">say</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">text</span><span class=\"p\">,</span> <span class=\"n\">cache</span><span class=\"o\">=</span><span class=\"kc\">False</span><span class=\"p\">,</span> <span class=\"n\">onCompleted</span><span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">,</span> <span class=\"n\">wait</span><span class=\"o\">=</span><span class=\"kc\">False</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">con</span><span class=\"o\">.</span><span class=\"n\">say</span><span class=\"p\">(</span><span class=\"n\">text</span><span class=\"p\">,</span> <span class=\"n\">cache</span><span class=\"o\">=</span><span class=\"n\">cache</span><span class=\"p\">,</span> <span class=\"n\">plugin</span><span class=\"o\">=</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">SLUG</span><span class=\"p\">,</span> <span class=\"n\">onCompleted</span><span class=\"o\">=</span><span class=\"n\">onCompleted</span><span class=\"p\">,</span> <span class=\"n\">wait</span><span class=\"o\">=</span><span class=\"n\">wait</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"AbstractPlugin.activeListen\"><a class=\"viewcode-back\" href=\"../../../robot.sdk.html#robot.sdk.AbstractPlugin.AbstractPlugin.activeListen\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">activeListen</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">silent</span><span class=\"o\">=</span><span class=\"kc\">False</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">con</span><span class=\"o\">.</span><span class=\"n\">activeListen</span><span class=\"p\">(</span><span class=\"n\">silent</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"AbstractPlugin.clearImmersive\"><a class=\"viewcode-back\" href=\"../../../robot.sdk.html#robot.sdk.AbstractPlugin.AbstractPlugin.clearImmersive\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">clearImmersive</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">con</span><span class=\"o\">.</span><span class=\"n\">setImmersiveMode</span><span class=\"p\">(</span><span class=\"kc\">None</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"AbstractPlugin.isValid\"><a class=\"viewcode-back\" href=\"../../../robot.sdk.html#robot.sdk.AbstractPlugin.AbstractPlugin.isValid\">[文档]</a>    <span class=\"nd\">@abstractmethod</span>\n    <span class=\"k\">def</span> <span class=\"nf\">isValid</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">query</span><span class=\"p\">,</span> <span class=\"n\">parsed</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        是否适合由该插件处理</span>\n\n<span class=\"sd\">        参数：</span>\n<span class=\"sd\">        query -- 用户的指令字符串</span>\n<span class=\"sd\">        parsed -- 用户指令经过 NLU 解析后的结果</span>\n\n<span class=\"sd\">        返回：</span>\n<span class=\"sd\">        True: 适合由该插件处理</span>\n<span class=\"sd\">        False: 不适合由该插件处理</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"k\">return</span> <span class=\"kc\">False</span></div>\n\n<div class=\"viewcode-block\" id=\"AbstractPlugin.handle\"><a class=\"viewcode-back\" href=\"../../../robot.sdk.html#robot.sdk.AbstractPlugin.AbstractPlugin.handle\">[文档]</a>    <span class=\"nd\">@abstractmethod</span>\n    <span class=\"k\">def</span> <span class=\"nf\">handle</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">query</span><span class=\"p\">,</span> <span class=\"n\">parsed</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        处理逻辑</span>\n\n<span class=\"sd\">        参数：</span>\n<span class=\"sd\">        query -- 用户的指令字符串</span>\n<span class=\"sd\">        parsed -- 用户指令经过 NLU 解析后的结果</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"k\">pass</span></div>\n\n<div class=\"viewcode-block\" id=\"AbstractPlugin.isValidImmersive\"><a class=\"viewcode-back\" href=\"../../../robot.sdk.html#robot.sdk.AbstractPlugin.AbstractPlugin.isValidImmersive\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">isValidImmersive</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">query</span><span class=\"p\">,</span> <span class=\"n\">parsed</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        是否适合在沉浸模式下处理，</span>\n<span class=\"sd\">        仅适用于有沉浸模式的插件（如音乐等）</span>\n<span class=\"sd\">        当用户唤醒时，可以响应更多指令集。</span>\n<span class=\"sd\">        例如：“&quot;上一首&quot;、&quot;下一首&quot; 等</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"k\">return</span> <span class=\"kc\">False</span></div>\n\n<div class=\"viewcode-block\" id=\"AbstractPlugin.pause\"><a class=\"viewcode-back\" href=\"../../../robot.sdk.html#robot.sdk.AbstractPlugin.AbstractPlugin.pause\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">pause</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        暂停当前正在处理的任务，</span>\n<span class=\"sd\">        当处于该沉浸模式下且被唤醒时，</span>\n<span class=\"sd\">        将自动触发这个方法，</span>\n<span class=\"sd\">        可以用于强制暂停一个耗时的操作        </span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"k\">return</span></div>\n\n<div class=\"viewcode-block\" id=\"AbstractPlugin.restore\"><a class=\"viewcode-back\" href=\"../../../robot.sdk.html#robot.sdk.AbstractPlugin.AbstractPlugin.restore\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">restore</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        恢复当前插件，</span>\n<span class=\"sd\">        仅适用于有沉浸模式的插件（如音乐等）</span>\n<span class=\"sd\">        当用户误唤醒或者唤醒进行闲聊后，</span>\n<span class=\"sd\">        可以自动恢复当前插件的处理逻辑</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"k\">return</span></div></div>\n    \n</pre></div>\n\n           </div>\n           \n          </div>\n          <footer>\n  \n\n  <hr/>\n\n  <div role=\"contentinfo\">\n    <p>\n        &copy; Copyright 2019, wzpan\n\n    </p>\n  </div>\n  Built with <a href=\"http://sphinx-doc.org/\">Sphinx</a> using a <a href=\"https://github.com/rtfd/sphinx_rtd_theme\">theme</a> provided by <a href=\"https://readthedocs.org\">Read the Docs</a>. \n\n</footer>\n\n        </div>\n      </div>\n\n    </section>\n\n  </div>\n  \n\n\n  <script type=\"text/javascript\">\n      jQuery(function () {\n          SphinxRtdTheme.Navigation.enable(true);\n      });\n  </script>\n\n  \n  \n    \n   \n\n</body>\n</html>"
  },
  {
    "path": "docs/_modules/robot/sdk/AliSpeech.html",
    "content": "\n\n<!DOCTYPE html>\n<!--[if IE 8]><html class=\"no-js lt-ie9\" lang=\"zh-CN\" > <![endif]-->\n<!--[if gt IE 8]><!--> <html class=\"no-js\" lang=\"zh-CN\" > <!--<![endif]-->\n<head>\n  <meta charset=\"utf-8\">\n  \n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  \n  <title>robot.sdk.AliSpeech &mdash; wukong-robot 1.2.0 文档</title>\n  \n\n  \n  \n  \n  \n\n  \n  <script type=\"text/javascript\" src=\"../../../_static/js/modernizr.min.js\"></script>\n  \n    \n      <script type=\"text/javascript\" id=\"documentation_options\" data-url_root=\"../../../\" src=\"../../../_static/documentation_options.js\"></script>\n        <script type=\"text/javascript\" src=\"../../../_static/jquery.js\"></script>\n        <script type=\"text/javascript\" src=\"../../../_static/underscore.js\"></script>\n        <script type=\"text/javascript\" src=\"../../../_static/doctools.js\"></script>\n        <script type=\"text/javascript\" src=\"../../../_static/language_data.js\"></script>\n        <script type=\"text/javascript\" src=\"../../../_static/translations.js\"></script>\n    \n    <script type=\"text/javascript\" src=\"../../../_static/js/theme.js\"></script>\n\n    \n\n  \n  <link rel=\"stylesheet\" href=\"../../../_static/css/theme.css\" type=\"text/css\" />\n  <link rel=\"stylesheet\" href=\"../../../_static/pygments.css\" type=\"text/css\" />\n    <link rel=\"index\" title=\"索引\" href=\"../../../genindex.html\" />\n    <link rel=\"search\" title=\"搜索\" href=\"../../../search.html\" /> \n</head>\n\n<body class=\"wy-body-for-nav\">\n\n   \n  <div class=\"wy-grid-for-nav\">\n    \n    <nav data-toggle=\"wy-nav-shift\" class=\"wy-nav-side\">\n      <div class=\"wy-side-scroll\">\n        <div class=\"wy-side-nav-search\" >\n          \n\n          \n            <a href=\"../../../index.html\" class=\"icon icon-home\"> wukong-robot\n          \n\n          \n          </a>\n\n          \n            \n            \n          \n\n          \n<div role=\"search\">\n  <form id=\"rtd-search-form\" class=\"wy-form\" action=\"../../../search.html\" method=\"get\">\n    <input type=\"text\" name=\"q\" placeholder=\"Search docs\" />\n    <input type=\"hidden\" name=\"check_keywords\" value=\"yes\" />\n    <input type=\"hidden\" name=\"area\" value=\"default\" />\n  </form>\n</div>\n\n          \n        </div>\n\n        <div class=\"wy-menu wy-menu-vertical\" data-spy=\"affix\" role=\"navigation\" aria-label=\"main navigation\">\n          \n            \n            \n              \n            \n            \n              <!-- Local TOC -->\n              <div class=\"local-toc\"></div>\n            \n          \n        </div>\n      </div>\n    </nav>\n\n    <section data-toggle=\"wy-nav-shift\" class=\"wy-nav-content-wrap\">\n\n      \n      <nav class=\"wy-nav-top\" aria-label=\"top navigation\">\n        \n          <i data-toggle=\"wy-nav-top\" class=\"fa fa-bars\"></i>\n          <a href=\"../../../index.html\">wukong-robot</a>\n        \n      </nav>\n\n\n      <div class=\"wy-nav-content\">\n        \n        <div class=\"rst-content\">\n        \n          \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<div role=\"navigation\" aria-label=\"breadcrumbs navigation\">\n\n  <ul class=\"wy-breadcrumbs\">\n    \n      <li><a href=\"../../../index.html\">Docs</a> &raquo;</li>\n        \n          <li><a href=\"../../index.html\">模块代码</a> &raquo;</li>\n        \n      <li>robot.sdk.AliSpeech</li>\n    \n    \n      <li class=\"wy-breadcrumbs-aside\">\n        \n      </li>\n    \n  </ul>\n\n  \n  <hr/>\n</div>\n          <div role=\"main\" class=\"document\" itemscope=\"itemscope\" itemtype=\"http://schema.org/Article\">\n           <div itemprop=\"articleBody\">\n            \n  <h1>robot.sdk.AliSpeech 源代码</h1><div class=\"highlight\"><pre>\n<span></span><span class=\"c1\"># -*- coding: UTF-8 -*-</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">http.client</span>\n<span class=\"kn\">import</span> <span class=\"nn\">urllib.parse</span>\n<span class=\"kn\">import</span> <span class=\"nn\">json</span>\n<span class=\"kn\">from</span> <span class=\"nn\">robot</span> <span class=\"k\">import</span> <span class=\"n\">utils</span>\n<span class=\"kn\">from</span> <span class=\"nn\">robot</span> <span class=\"k\">import</span> <span class=\"n\">logging</span>\n\n<span class=\"n\">logger</span> <span class=\"o\">=</span> <span class=\"n\">logging</span><span class=\"o\">.</span><span class=\"n\">getLogger</span><span class=\"p\">(</span><span class=\"vm\">__name__</span><span class=\"p\">)</span>\n\n<div class=\"viewcode-block\" id=\"processGETRequest\"><a class=\"viewcode-back\" href=\"../../../robot.sdk.html#robot.sdk.AliSpeech.processGETRequest\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">processGETRequest</span><span class=\"p\">(</span><span class=\"n\">appKey</span><span class=\"p\">,</span> <span class=\"n\">token</span><span class=\"p\">,</span> <span class=\"n\">voice</span><span class=\"p\">,</span> <span class=\"n\">text</span><span class=\"p\">,</span> <span class=\"nb\">format</span><span class=\"p\">,</span> <span class=\"n\">sampleRate</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"n\">host</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;nls-gateway.cn-shanghai.aliyuncs.com&#39;</span>\n    <span class=\"n\">url</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;https://&#39;</span> <span class=\"o\">+</span> <span class=\"n\">host</span> <span class=\"o\">+</span> <span class=\"s1\">&#39;/stream/v1/tts&#39;</span>\n    <span class=\"c1\"># 设置URL请求参数</span>\n    <span class=\"n\">url</span> <span class=\"o\">=</span> <span class=\"n\">url</span> <span class=\"o\">+</span> <span class=\"s1\">&#39;?appkey=&#39;</span> <span class=\"o\">+</span> <span class=\"n\">appKey</span>\n    <span class=\"n\">url</span> <span class=\"o\">=</span> <span class=\"n\">url</span> <span class=\"o\">+</span> <span class=\"s1\">&#39;&amp;token=&#39;</span> <span class=\"o\">+</span> <span class=\"n\">token</span>\n    <span class=\"n\">url</span> <span class=\"o\">=</span> <span class=\"n\">url</span> <span class=\"o\">+</span> <span class=\"s1\">&#39;&amp;text=&#39;</span> <span class=\"o\">+</span> <span class=\"n\">text</span>\n    <span class=\"n\">url</span> <span class=\"o\">=</span> <span class=\"n\">url</span> <span class=\"o\">+</span> <span class=\"s1\">&#39;&amp;format=&#39;</span> <span class=\"o\">+</span> <span class=\"nb\">format</span>\n    <span class=\"n\">url</span> <span class=\"o\">=</span> <span class=\"n\">url</span> <span class=\"o\">+</span> <span class=\"s1\">&#39;&amp;sample_rate=&#39;</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">sampleRate</span><span class=\"p\">)</span>\n    <span class=\"n\">url</span> <span class=\"o\">=</span> <span class=\"n\">url</span> <span class=\"o\">+</span> <span class=\"s1\">&#39;&amp;voice=&#39;</span> <span class=\"o\">+</span> <span class=\"n\">voice</span>\n    <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">debug</span><span class=\"p\">(</span><span class=\"n\">url</span><span class=\"p\">)</span>\n    <span class=\"n\">conn</span> <span class=\"o\">=</span> <span class=\"n\">http</span><span class=\"o\">.</span><span class=\"n\">client</span><span class=\"o\">.</span><span class=\"n\">HTTPSConnection</span><span class=\"p\">(</span><span class=\"n\">host</span><span class=\"p\">)</span>\n    <span class=\"n\">conn</span><span class=\"o\">.</span><span class=\"n\">request</span><span class=\"p\">(</span><span class=\"n\">method</span><span class=\"o\">=</span><span class=\"s1\">&#39;GET&#39;</span><span class=\"p\">,</span> <span class=\"n\">url</span><span class=\"o\">=</span><span class=\"n\">url</span><span class=\"p\">)</span>\n    <span class=\"c1\"># 处理服务端返回的响应</span>\n    <span class=\"n\">response</span> <span class=\"o\">=</span> <span class=\"n\">conn</span><span class=\"o\">.</span><span class=\"n\">getresponse</span><span class=\"p\">()</span>\n    <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">debug</span><span class=\"p\">(</span><span class=\"s1\">&#39;Response status and response reason:&#39;</span><span class=\"p\">)</span>\n    <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">debug</span><span class=\"p\">(</span><span class=\"n\">response</span><span class=\"o\">.</span><span class=\"n\">status</span> <span class=\"p\">,</span><span class=\"n\">response</span><span class=\"o\">.</span><span class=\"n\">reason</span><span class=\"p\">)</span>\n    <span class=\"n\">contentType</span> <span class=\"o\">=</span> <span class=\"n\">response</span><span class=\"o\">.</span><span class=\"n\">getheader</span><span class=\"p\">(</span><span class=\"s1\">&#39;Content-Type&#39;</span><span class=\"p\">)</span>\n    <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">debug</span><span class=\"p\">(</span><span class=\"n\">contentType</span><span class=\"p\">)</span>\n    <span class=\"n\">body</span> <span class=\"o\">=</span> <span class=\"n\">response</span><span class=\"o\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n    <span class=\"k\">if</span> <span class=\"s1\">&#39;audio/mpeg&#39;</span> <span class=\"o\">==</span> <span class=\"n\">contentType</span> <span class=\"p\">:</span>\n        <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">debug</span><span class=\"p\">(</span><span class=\"s1\">&#39;The GET request succeed!&#39;</span><span class=\"p\">)</span>\n        <span class=\"n\">tmpfile</span> <span class=\"o\">=</span> <span class=\"n\">utils</span><span class=\"o\">.</span><span class=\"n\">write_temp_file</span><span class=\"p\">(</span><span class=\"n\">body</span><span class=\"p\">,</span> <span class=\"s1\">&#39;.mp3&#39;</span><span class=\"p\">)</span>\n        <span class=\"n\">conn</span><span class=\"o\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n        <span class=\"k\">return</span> <span class=\"n\">tmpfile</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">debug</span><span class=\"p\">(</span><span class=\"s1\">&#39;The GET request failed: &#39;</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">body</span><span class=\"p\">))</span>\n        <span class=\"n\">conn</span><span class=\"o\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n        <span class=\"k\">return</span> <span class=\"kc\">None</span></div>\n\n<div class=\"viewcode-block\" id=\"processPOSTRequest\"><a class=\"viewcode-back\" href=\"../../../robot.sdk.html#robot.sdk.AliSpeech.processPOSTRequest\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">processPOSTRequest</span><span class=\"p\">(</span><span class=\"n\">appKey</span><span class=\"p\">,</span> <span class=\"n\">token</span><span class=\"p\">,</span> <span class=\"n\">voice</span><span class=\"p\">,</span> <span class=\"n\">text</span><span class=\"p\">,</span> <span class=\"nb\">format</span><span class=\"p\">,</span> <span class=\"n\">sampleRate</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"n\">host</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;nls-gateway.cn-shanghai.aliyuncs.com&#39;</span>\n    <span class=\"n\">url</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;https://&#39;</span> <span class=\"o\">+</span> <span class=\"n\">host</span> <span class=\"o\">+</span> <span class=\"s1\">&#39;/stream/v1/tts&#39;</span>\n    <span class=\"c1\"># 设置HTTPS Headers</span>\n    <span class=\"n\">httpHeaders</span> <span class=\"o\">=</span> <span class=\"p\">{</span>\n        <span class=\"s1\">&#39;Content-Type&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;application/json&#39;</span>\n        <span class=\"p\">}</span>\n    <span class=\"c1\"># 设置HTTPS Body</span>\n    <span class=\"n\">body</span> <span class=\"o\">=</span> <span class=\"p\">{</span><span class=\"s1\">&#39;appkey&#39;</span><span class=\"p\">:</span> <span class=\"n\">appKey</span><span class=\"p\">,</span> <span class=\"s1\">&#39;token&#39;</span><span class=\"p\">:</span> <span class=\"n\">token</span><span class=\"p\">,</span> <span class=\"s1\">&#39;text&#39;</span><span class=\"p\">:</span> <span class=\"n\">text</span><span class=\"p\">,</span> <span class=\"s1\">&#39;format&#39;</span><span class=\"p\">:</span> <span class=\"nb\">format</span><span class=\"p\">,</span> <span class=\"s1\">&#39;sample_rate&#39;</span><span class=\"p\">:</span> <span class=\"n\">sampleRate</span><span class=\"p\">,</span> <span class=\"s1\">&#39;voice&#39;</span><span class=\"p\">:</span> <span class=\"n\">voice</span><span class=\"p\">}</span>\n    <span class=\"n\">body</span> <span class=\"o\">=</span> <span class=\"n\">json</span><span class=\"o\">.</span><span class=\"n\">dumps</span><span class=\"p\">(</span><span class=\"n\">body</span><span class=\"p\">)</span>\n    <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">debug</span><span class=\"p\">(</span><span class=\"s1\">&#39;The POST request body content: &#39;</span> <span class=\"o\">+</span> <span class=\"n\">body</span><span class=\"p\">)</span>\n    <span class=\"c1\"># Python 2.x 请使用httplib</span>\n    <span class=\"c1\"># conn = httplib.HTTPSConnection(host)</span>\n    <span class=\"c1\"># Python 3.x 请使用http.client</span>\n    <span class=\"n\">conn</span> <span class=\"o\">=</span> <span class=\"n\">http</span><span class=\"o\">.</span><span class=\"n\">client</span><span class=\"o\">.</span><span class=\"n\">HTTPSConnection</span><span class=\"p\">(</span><span class=\"n\">host</span><span class=\"p\">)</span>\n    <span class=\"n\">conn</span><span class=\"o\">.</span><span class=\"n\">request</span><span class=\"p\">(</span><span class=\"n\">method</span><span class=\"o\">=</span><span class=\"s1\">&#39;POST&#39;</span><span class=\"p\">,</span> <span class=\"n\">url</span><span class=\"o\">=</span><span class=\"n\">url</span><span class=\"p\">,</span> <span class=\"n\">body</span><span class=\"o\">=</span><span class=\"n\">body</span><span class=\"p\">,</span> <span class=\"n\">headers</span><span class=\"o\">=</span><span class=\"n\">httpHeaders</span><span class=\"p\">)</span>\n    <span class=\"c1\"># 处理服务端返回的响应</span>\n    <span class=\"n\">response</span> <span class=\"o\">=</span> <span class=\"n\">conn</span><span class=\"o\">.</span><span class=\"n\">getresponse</span><span class=\"p\">()</span>\n    <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">debug</span><span class=\"p\">(</span><span class=\"s1\">&#39;Response status and response reason:&#39;</span><span class=\"p\">)</span>\n    <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">debug</span><span class=\"p\">(</span><span class=\"n\">response</span><span class=\"o\">.</span><span class=\"n\">status</span> <span class=\"p\">,</span><span class=\"n\">response</span><span class=\"o\">.</span><span class=\"n\">reason</span><span class=\"p\">)</span>\n    <span class=\"n\">contentType</span> <span class=\"o\">=</span> <span class=\"n\">response</span><span class=\"o\">.</span><span class=\"n\">getheader</span><span class=\"p\">(</span><span class=\"s1\">&#39;Content-Type&#39;</span><span class=\"p\">)</span>\n    <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">debug</span><span class=\"p\">(</span><span class=\"n\">contentType</span><span class=\"p\">)</span>\n    <span class=\"n\">body</span> <span class=\"o\">=</span> <span class=\"n\">response</span><span class=\"o\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n    <span class=\"k\">if</span> <span class=\"s1\">&#39;audio/mpeg&#39;</span> <span class=\"o\">==</span> <span class=\"n\">contentType</span> <span class=\"p\">:</span>\n        <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">debug</span><span class=\"p\">(</span><span class=\"s1\">&#39;The POST request succeed!&#39;</span><span class=\"p\">)</span>\n        <span class=\"n\">tmpfile</span> <span class=\"o\">=</span> <span class=\"n\">utils</span><span class=\"o\">.</span><span class=\"n\">write_temp_file</span><span class=\"p\">(</span><span class=\"n\">body</span><span class=\"p\">,</span> <span class=\"s1\">&#39;.mp3&#39;</span><span class=\"p\">)</span>\n        <span class=\"n\">conn</span><span class=\"o\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n        <span class=\"k\">return</span> <span class=\"n\">tmpfile</span>\n    <span class=\"k\">else</span> <span class=\"p\">:</span>\n        <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">critical</span><span class=\"p\">(</span><span class=\"s1\">&#39;The POST request failed: &#39;</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">body</span><span class=\"p\">))</span>\n        <span class=\"n\">conn</span><span class=\"o\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n        <span class=\"k\">return</span> <span class=\"kc\">None</span></div>\n\n<div class=\"viewcode-block\" id=\"process\"><a class=\"viewcode-back\" href=\"../../../robot.sdk.html#robot.sdk.AliSpeech.process\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">process</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"p\">,</span> <span class=\"n\">token</span><span class=\"p\">,</span> <span class=\"n\">audioContent</span><span class=\"p\">)</span> <span class=\"p\">:</span>\n    <span class=\"c1\"># 读取音频文件</span>\n    <span class=\"n\">host</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;nls-gateway.cn-shanghai.aliyuncs.com&#39;</span>\n    <span class=\"c1\"># 设置HTTP请求头部</span>\n    <span class=\"n\">httpHeaders</span> <span class=\"o\">=</span> <span class=\"p\">{</span>\n        <span class=\"s1\">&#39;X-NLS-Token&#39;</span><span class=\"p\">:</span> <span class=\"n\">token</span><span class=\"p\">,</span>\n        <span class=\"s1\">&#39;Content-type&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;application/octet-stream&#39;</span><span class=\"p\">,</span>\n        <span class=\"s1\">&#39;Content-Length&#39;</span><span class=\"p\">:</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">audioContent</span><span class=\"p\">)</span>\n        <span class=\"p\">}</span>\n    <span class=\"n\">conn</span> <span class=\"o\">=</span> <span class=\"n\">http</span><span class=\"o\">.</span><span class=\"n\">client</span><span class=\"o\">.</span><span class=\"n\">HTTPConnection</span><span class=\"p\">(</span><span class=\"n\">host</span><span class=\"p\">)</span>\n    <span class=\"n\">conn</span><span class=\"o\">.</span><span class=\"n\">request</span><span class=\"p\">(</span><span class=\"n\">method</span><span class=\"o\">=</span><span class=\"s1\">&#39;POST&#39;</span><span class=\"p\">,</span> <span class=\"n\">url</span><span class=\"o\">=</span><span class=\"n\">request</span><span class=\"p\">,</span> <span class=\"n\">body</span><span class=\"o\">=</span><span class=\"n\">audioContent</span><span class=\"p\">,</span> <span class=\"n\">headers</span><span class=\"o\">=</span><span class=\"n\">httpHeaders</span><span class=\"p\">)</span>\n    <span class=\"n\">response</span> <span class=\"o\">=</span> <span class=\"n\">conn</span><span class=\"o\">.</span><span class=\"n\">getresponse</span><span class=\"p\">()</span>\n    <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">debug</span><span class=\"p\">(</span><span class=\"s1\">&#39;Response status and response reason:&#39;</span><span class=\"p\">)</span>\n    <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">debug</span><span class=\"p\">(</span><span class=\"n\">response</span><span class=\"o\">.</span><span class=\"n\">status</span> <span class=\"p\">,</span><span class=\"n\">response</span><span class=\"o\">.</span><span class=\"n\">reason</span><span class=\"p\">)</span>\n    <span class=\"n\">body</span> <span class=\"o\">=</span> <span class=\"n\">response</span><span class=\"o\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n    <span class=\"k\">try</span><span class=\"p\">:</span>\n        <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">debug</span><span class=\"p\">(</span><span class=\"s1\">&#39;Recognize response is:&#39;</span><span class=\"p\">)</span>\n        <span class=\"n\">body</span> <span class=\"o\">=</span> <span class=\"n\">json</span><span class=\"o\">.</span><span class=\"n\">loads</span><span class=\"p\">(</span><span class=\"n\">body</span><span class=\"p\">)</span>\n        <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">debug</span><span class=\"p\">(</span><span class=\"n\">body</span><span class=\"p\">)</span>\n        <span class=\"n\">status</span> <span class=\"o\">=</span> <span class=\"n\">body</span><span class=\"p\">[</span><span class=\"s1\">&#39;status&#39;</span><span class=\"p\">]</span>\n        <span class=\"k\">if</span> <span class=\"n\">status</span> <span class=\"o\">==</span> <span class=\"mi\">20000000</span> <span class=\"p\">:</span>\n            <span class=\"n\">result</span> <span class=\"o\">=</span> <span class=\"n\">body</span><span class=\"p\">[</span><span class=\"s1\">&#39;result&#39;</span><span class=\"p\">]</span>\n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">debug</span><span class=\"p\">(</span><span class=\"s1\">&#39;Recognize result: &#39;</span> <span class=\"o\">+</span> <span class=\"n\">result</span><span class=\"p\">)</span>\n            <span class=\"n\">conn</span><span class=\"o\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n            <span class=\"k\">return</span> <span class=\"n\">result</span>\n        <span class=\"k\">else</span> <span class=\"p\">:</span>\n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">critical</span><span class=\"p\">(</span><span class=\"s1\">&#39;Recognizer failed!&#39;</span><span class=\"p\">)</span>\n            <span class=\"n\">conn</span><span class=\"o\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n            <span class=\"k\">return</span> <span class=\"kc\">None</span>\n    <span class=\"k\">except</span> <span class=\"ne\">ValueError</span><span class=\"p\">:</span>\n        <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">debug</span><span class=\"p\">(</span><span class=\"s1\">&#39;The response is not json format string&#39;</span><span class=\"p\">)</span>\n        <span class=\"n\">conn</span><span class=\"o\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n        <span class=\"k\">return</span> <span class=\"kc\">None</span></div>\n\n<div class=\"viewcode-block\" id=\"tts\"><a class=\"viewcode-back\" href=\"../../../robot.sdk.html#robot.sdk.AliSpeech.tts\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">tts</span><span class=\"p\">(</span><span class=\"n\">appKey</span><span class=\"p\">,</span> <span class=\"n\">token</span><span class=\"p\">,</span> <span class=\"n\">voice</span><span class=\"p\">,</span> <span class=\"n\">text</span><span class=\"p\">):</span>\n    <span class=\"c1\"># 采用RFC 3986规范进行urlencode编码</span>\n    <span class=\"n\">textUrlencode</span> <span class=\"o\">=</span> <span class=\"n\">text</span>\n    <span class=\"n\">textUrlencode</span> <span class=\"o\">=</span> <span class=\"n\">urllib</span><span class=\"o\">.</span><span class=\"n\">parse</span><span class=\"o\">.</span><span class=\"n\">quote_plus</span><span class=\"p\">(</span><span class=\"n\">textUrlencode</span><span class=\"p\">)</span>\n    <span class=\"n\">textUrlencode</span> <span class=\"o\">=</span> <span class=\"n\">textUrlencode</span><span class=\"o\">.</span><span class=\"n\">replace</span><span class=\"p\">(</span><span class=\"s2\">&quot;+&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;%20&quot;</span><span class=\"p\">)</span>\n    <span class=\"n\">textUrlencode</span> <span class=\"o\">=</span> <span class=\"n\">textUrlencode</span><span class=\"o\">.</span><span class=\"n\">replace</span><span class=\"p\">(</span><span class=\"s2\">&quot;*&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;%2A&quot;</span><span class=\"p\">)</span>\n    <span class=\"n\">textUrlencode</span> <span class=\"o\">=</span> <span class=\"n\">textUrlencode</span><span class=\"o\">.</span><span class=\"n\">replace</span><span class=\"p\">(</span><span class=\"s2\">&quot;</span><span class=\"si\">%7E</span><span class=\"s2\">&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;~&quot;</span><span class=\"p\">)</span>\n    <span class=\"nb\">format</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;mp3&#39;</span>\n    <span class=\"n\">sampleRate</span> <span class=\"o\">=</span> <span class=\"mi\">16000</span>\n    <span class=\"k\">return</span> <span class=\"n\">processPOSTRequest</span><span class=\"p\">(</span><span class=\"n\">appKey</span><span class=\"p\">,</span> <span class=\"n\">token</span><span class=\"p\">,</span> <span class=\"n\">voice</span><span class=\"p\">,</span> <span class=\"n\">text</span><span class=\"p\">,</span> <span class=\"nb\">format</span><span class=\"p\">,</span> <span class=\"n\">sampleRate</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"asr\"><a class=\"viewcode-back\" href=\"../../../robot.sdk.html#robot.sdk.AliSpeech.asr\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">asr</span><span class=\"p\">(</span><span class=\"n\">appKey</span><span class=\"p\">,</span> <span class=\"n\">token</span><span class=\"p\">,</span> <span class=\"n\">wave_file</span><span class=\"p\">):</span>\n    <span class=\"c1\"># 服务请求地址</span>\n    <span class=\"n\">url</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;http://nls-gateway.cn-shanghai.aliyuncs.com/stream/v1/asr&#39;</span>\n    <span class=\"n\">pcm</span> <span class=\"o\">=</span> <span class=\"n\">utils</span><span class=\"o\">.</span><span class=\"n\">get_pcm_from_wav</span><span class=\"p\">(</span><span class=\"n\">wave_file</span><span class=\"p\">)</span>\n    <span class=\"c1\"># 音频文件</span>\n    <span class=\"nb\">format</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;pcm&#39;</span>\n    <span class=\"n\">sampleRate</span> <span class=\"o\">=</span> <span class=\"mi\">16000</span>\n    <span class=\"n\">enablePunctuationPrediction</span>  <span class=\"o\">=</span> <span class=\"kc\">True</span>\n    <span class=\"n\">enableInverseTextNormalization</span> <span class=\"o\">=</span> <span class=\"kc\">True</span>\n    <span class=\"n\">enableVoiceDetection</span>  <span class=\"o\">=</span> <span class=\"kc\">False</span>\n    <span class=\"c1\"># 设置RESTful请求参数</span>\n    <span class=\"n\">request</span> <span class=\"o\">=</span> <span class=\"n\">url</span> <span class=\"o\">+</span> <span class=\"s1\">&#39;?appkey=&#39;</span> <span class=\"o\">+</span> <span class=\"n\">appKey</span>\n    <span class=\"n\">request</span> <span class=\"o\">=</span> <span class=\"n\">request</span> <span class=\"o\">+</span> <span class=\"s1\">&#39;&amp;format=&#39;</span> <span class=\"o\">+</span> <span class=\"nb\">format</span>\n    <span class=\"n\">request</span> <span class=\"o\">=</span> <span class=\"n\">request</span> <span class=\"o\">+</span> <span class=\"s1\">&#39;&amp;sample_rate=&#39;</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">sampleRate</span><span class=\"p\">)</span>\n    <span class=\"k\">if</span> <span class=\"n\">enablePunctuationPrediction</span> <span class=\"p\">:</span>\n        <span class=\"n\">request</span> <span class=\"o\">=</span> <span class=\"n\">request</span> <span class=\"o\">+</span> <span class=\"s1\">&#39;&amp;enable_punctuation_prediction=&#39;</span> <span class=\"o\">+</span> <span class=\"s1\">&#39;true&#39;</span>\n    <span class=\"k\">if</span> <span class=\"n\">enableInverseTextNormalization</span> <span class=\"p\">:</span>\n        <span class=\"n\">request</span> <span class=\"o\">=</span> <span class=\"n\">request</span> <span class=\"o\">+</span> <span class=\"s1\">&#39;&amp;enable_inverse_text_normalization=&#39;</span> <span class=\"o\">+</span> <span class=\"s1\">&#39;true&#39;</span>\n    <span class=\"k\">if</span> <span class=\"n\">enableVoiceDetection</span> <span class=\"p\">:</span>\n        <span class=\"n\">request</span> <span class=\"o\">=</span> <span class=\"n\">request</span> <span class=\"o\">+</span> <span class=\"s1\">&#39;&amp;enable_voice_detection=&#39;</span> <span class=\"o\">+</span> <span class=\"s1\">&#39;true&#39;</span>\n    <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">debug</span><span class=\"p\">(</span><span class=\"s1\">&#39;Request: &#39;</span> <span class=\"o\">+</span> <span class=\"n\">request</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">process</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"p\">,</span> <span class=\"n\">token</span><span class=\"p\">,</span> <span class=\"n\">pcm</span><span class=\"p\">)</span></div>\n    \n</pre></div>\n\n           </div>\n           \n          </div>\n          <footer>\n  \n\n  <hr/>\n\n  <div role=\"contentinfo\">\n    <p>\n        &copy; Copyright 2019, wzpan\n\n    </p>\n  </div>\n  Built with <a href=\"http://sphinx-doc.org/\">Sphinx</a> using a <a href=\"https://github.com/rtfd/sphinx_rtd_theme\">theme</a> provided by <a href=\"https://readthedocs.org\">Read the Docs</a>. \n\n</footer>\n\n        </div>\n      </div>\n\n    </section>\n\n  </div>\n  \n\n\n  <script type=\"text/javascript\">\n      jQuery(function () {\n          SphinxRtdTheme.Navigation.enable(true);\n      });\n  </script>\n\n  \n  \n    \n   \n\n</body>\n</html>"
  },
  {
    "path": "docs/_modules/robot/sdk/RASRsdk.html",
    "content": "\n\n<!DOCTYPE html>\n<!--[if IE 8]><html class=\"no-js lt-ie9\" lang=\"zh-CN\" > <![endif]-->\n<!--[if gt IE 8]><!--> <html class=\"no-js\" lang=\"zh-CN\" > <!--<![endif]-->\n<head>\n  <meta charset=\"utf-8\">\n  \n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  \n  <title>robot.sdk.RASRsdk &mdash; wukong-robot 1.2.0 文档</title>\n  \n\n  \n  \n  \n  \n\n  \n  <script type=\"text/javascript\" src=\"../../../_static/js/modernizr.min.js\"></script>\n  \n    \n      <script type=\"text/javascript\" id=\"documentation_options\" data-url_root=\"../../../\" src=\"../../../_static/documentation_options.js\"></script>\n        <script type=\"text/javascript\" src=\"../../../_static/jquery.js\"></script>\n        <script type=\"text/javascript\" src=\"../../../_static/underscore.js\"></script>\n        <script type=\"text/javascript\" src=\"../../../_static/doctools.js\"></script>\n        <script type=\"text/javascript\" src=\"../../../_static/language_data.js\"></script>\n        <script type=\"text/javascript\" src=\"../../../_static/translations.js\"></script>\n    \n    <script type=\"text/javascript\" src=\"../../../_static/js/theme.js\"></script>\n\n    \n\n  \n  <link rel=\"stylesheet\" href=\"../../../_static/css/theme.css\" type=\"text/css\" />\n  <link rel=\"stylesheet\" href=\"../../../_static/pygments.css\" type=\"text/css\" />\n    <link rel=\"index\" title=\"索引\" href=\"../../../genindex.html\" />\n    <link rel=\"search\" title=\"搜索\" href=\"../../../search.html\" /> \n</head>\n\n<body class=\"wy-body-for-nav\">\n\n   \n  <div class=\"wy-grid-for-nav\">\n    \n    <nav data-toggle=\"wy-nav-shift\" class=\"wy-nav-side\">\n      <div class=\"wy-side-scroll\">\n        <div class=\"wy-side-nav-search\" >\n          \n\n          \n            <a href=\"../../../index.html\" class=\"icon icon-home\"> wukong-robot\n          \n\n          \n          </a>\n\n          \n            \n            \n          \n\n          \n<div role=\"search\">\n  <form id=\"rtd-search-form\" class=\"wy-form\" action=\"../../../search.html\" method=\"get\">\n    <input type=\"text\" name=\"q\" placeholder=\"Search docs\" />\n    <input type=\"hidden\" name=\"check_keywords\" value=\"yes\" />\n    <input type=\"hidden\" name=\"area\" value=\"default\" />\n  </form>\n</div>\n\n          \n        </div>\n\n        <div class=\"wy-menu wy-menu-vertical\" data-spy=\"affix\" role=\"navigation\" aria-label=\"main navigation\">\n          \n            \n            \n              \n            \n            \n              <!-- Local TOC -->\n              <div class=\"local-toc\"></div>\n            \n          \n        </div>\n      </div>\n    </nav>\n\n    <section data-toggle=\"wy-nav-shift\" class=\"wy-nav-content-wrap\">\n\n      \n      <nav class=\"wy-nav-top\" aria-label=\"top navigation\">\n        \n          <i data-toggle=\"wy-nav-top\" class=\"fa fa-bars\"></i>\n          <a href=\"../../../index.html\">wukong-robot</a>\n        \n      </nav>\n\n\n      <div class=\"wy-nav-content\">\n        \n        <div class=\"rst-content\">\n        \n          \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<div role=\"navigation\" aria-label=\"breadcrumbs navigation\">\n\n  <ul class=\"wy-breadcrumbs\">\n    \n      <li><a href=\"../../../index.html\">Docs</a> &raquo;</li>\n        \n          <li><a href=\"../../index.html\">模块代码</a> &raquo;</li>\n        \n      <li>robot.sdk.RASRsdk</li>\n    \n    \n      <li class=\"wy-breadcrumbs-aside\">\n        \n      </li>\n    \n  </ul>\n\n  \n  <hr/>\n</div>\n          <div role=\"main\" class=\"document\" itemscope=\"itemscope\" itemtype=\"http://schema.org/Article\">\n           <div itemprop=\"articleBody\">\n            \n  <h1>robot.sdk.RASRsdk 源代码</h1><div class=\"highlight\"><pre>\n<span></span><span class=\"c1\"># -*- coding:utf-8 -*-</span>\n<span class=\"kn\">import</span> <span class=\"nn\">urllib.request</span>\n<span class=\"kn\">import</span> <span class=\"nn\">hmac</span>\n<span class=\"kn\">import</span> <span class=\"nn\">hashlib</span>\n<span class=\"kn\">import</span> <span class=\"nn\">base64</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">random</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">import</span> <span class=\"nn\">json</span>\n\n\n<div class=\"viewcode-block\" id=\"formatSignString\"><a class=\"viewcode-back\" href=\"../../../robot.sdk.html#robot.sdk.RASRsdk.formatSignString\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">formatSignString</span><span class=\"p\">(</span><span class=\"n\">param</span><span class=\"p\">):</span>\n    <span class=\"n\">signstr</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;POSTaai.qcloud.com/asr/v1/&quot;</span>\n    <span class=\"k\">for</span> <span class=\"n\">t</span> <span class=\"ow\">in</span> <span class=\"n\">param</span><span class=\"p\">:</span>\n        <span class=\"k\">if</span> <span class=\"s1\">&#39;appid&#39;</span> <span class=\"ow\">in</span> <span class=\"n\">t</span><span class=\"p\">:</span>\n            <span class=\"n\">signstr</span> <span class=\"o\">+=</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">t</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">])</span>\n            <span class=\"k\">break</span>\n    <span class=\"n\">signstr</span> <span class=\"o\">+=</span> <span class=\"s2\">&quot;?&quot;</span>\n    <span class=\"k\">for</span> <span class=\"n\">x</span> <span class=\"ow\">in</span> <span class=\"n\">param</span><span class=\"p\">:</span>\n        <span class=\"n\">tmp</span> <span class=\"o\">=</span> <span class=\"n\">x</span>\n        <span class=\"k\">if</span> <span class=\"s1\">&#39;appid&#39;</span> <span class=\"ow\">in</span> <span class=\"n\">x</span><span class=\"p\">:</span>\n            <span class=\"k\">continue</span>\n        <span class=\"k\">for</span> <span class=\"n\">t</span> <span class=\"ow\">in</span> <span class=\"n\">tmp</span><span class=\"p\">:</span>\n            <span class=\"n\">signstr</span> <span class=\"o\">+=</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">t</span><span class=\"p\">)</span>\n            <span class=\"n\">signstr</span> <span class=\"o\">+=</span> <span class=\"s2\">&quot;=&quot;</span>\n        <span class=\"n\">signstr</span> <span class=\"o\">=</span> <span class=\"n\">signstr</span><span class=\"p\">[:</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n        <span class=\"n\">signstr</span> <span class=\"o\">+=</span> <span class=\"s2\">&quot;&amp;&quot;</span>\n    <span class=\"n\">signstr</span> <span class=\"o\">=</span> <span class=\"n\">signstr</span><span class=\"p\">[:</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n    <span class=\"c1\"># print &#39;signstr&#39;,signstr</span>\n    <span class=\"k\">return</span> <span class=\"n\">signstr</span></div>\n\n\n<div class=\"viewcode-block\" id=\"sign\"><a class=\"viewcode-back\" href=\"../../../robot.sdk.html#robot.sdk.RASRsdk.sign\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">sign</span><span class=\"p\">(</span><span class=\"n\">signstr</span><span class=\"p\">,</span> <span class=\"n\">secret_key</span><span class=\"p\">):</span>\n    <span class=\"n\">sign_bytes</span><span class=\"o\">=</span> <span class=\"nb\">bytes</span><span class=\"p\">(</span><span class=\"n\">signstr</span> <span class=\"p\">,</span> <span class=\"s1\">&#39;utf-8&#39;</span><span class=\"p\">)</span>\n    <span class=\"n\">secret_bytes</span> <span class=\"o\">=</span> <span class=\"nb\">bytes</span><span class=\"p\">(</span><span class=\"n\">secret_key</span><span class=\"p\">,</span> <span class=\"s1\">&#39;utf-8&#39;</span><span class=\"p\">)</span>\n    <span class=\"n\">hmacstr</span> <span class=\"o\">=</span> <span class=\"n\">hmac</span><span class=\"o\">.</span><span class=\"n\">new</span><span class=\"p\">(</span><span class=\"n\">secret_bytes</span><span class=\"p\">,</span> <span class=\"n\">sign_bytes</span><span class=\"p\">,</span> <span class=\"n\">hashlib</span><span class=\"o\">.</span><span class=\"n\">sha1</span><span class=\"p\">)</span><span class=\"o\">.</span><span class=\"n\">digest</span><span class=\"p\">()</span>\n    <span class=\"n\">s</span> <span class=\"o\">=</span> <span class=\"n\">base64</span><span class=\"o\">.</span><span class=\"n\">b64encode</span><span class=\"p\">(</span><span class=\"n\">hmacstr</span><span class=\"p\">)</span><span class=\"o\">.</span><span class=\"n\">decode</span><span class=\"p\">(</span><span class=\"s1\">&#39;utf-8&#39;</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">s</span></div>\n\n\n<div class=\"viewcode-block\" id=\"randstr\"><a class=\"viewcode-back\" href=\"../../../robot.sdk.html#robot.sdk.RASRsdk.randstr\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">randstr</span><span class=\"p\">(</span><span class=\"n\">n</span><span class=\"p\">):</span>\n    <span class=\"n\">seed</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ&quot;</span>\n    <span class=\"n\">sa</span> <span class=\"o\">=</span> <span class=\"p\">[]</span>\n    <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">n</span><span class=\"p\">):</span>\n        <span class=\"n\">sa</span><span class=\"o\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">random</span><span class=\"o\">.</span><span class=\"n\">choice</span><span class=\"p\">(</span><span class=\"n\">seed</span><span class=\"p\">))</span>\n    <span class=\"n\">salt</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;&#39;</span><span class=\"o\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">sa</span><span class=\"p\">)</span>\n    <span class=\"c1\"># print salt</span>\n    <span class=\"k\">return</span> <span class=\"n\">salt</span></div>\n\n\n<div class=\"viewcode-block\" id=\"sendVoice\"><a class=\"viewcode-back\" href=\"../../../robot.sdk.html#robot.sdk.RASRsdk.sendVoice\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">sendVoice</span><span class=\"p\">(</span><span class=\"n\">secret_key</span><span class=\"p\">,</span> <span class=\"n\">secretid</span><span class=\"p\">,</span> <span class=\"n\">appid</span><span class=\"p\">,</span> <span class=\"n\">engine_model_type</span><span class=\"p\">,</span> <span class=\"n\">res_type</span><span class=\"p\">,</span> <span class=\"n\">result_text_format</span><span class=\"p\">,</span> <span class=\"n\">voice_format</span><span class=\"p\">,</span> <span class=\"n\">filepath</span><span class=\"p\">,</span> <span class=\"n\">cutlength</span><span class=\"p\">,</span> <span class=\"n\">template_name</span><span class=\"o\">=</span><span class=\"s2\">&quot;&quot;</span><span class=\"p\">):</span>\n    <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">secret_key</span><span class=\"p\">))</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"s1\">&#39;secretKey can not empty&#39;</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span>\n    <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">secretid</span><span class=\"p\">))</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"s1\">&#39;secretid can not empty&#39;</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span>\n    <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">appid</span><span class=\"p\">))</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"s1\">&#39;appid can not empty&#39;</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span>\n    <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">engine_model_type</span><span class=\"p\">))</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">or</span> <span class=\"p\">(</span>\n            <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">engine_model_type</span><span class=\"p\">)</span> <span class=\"o\">!=</span> <span class=\"s1\">&#39;8k_0&#39;</span> <span class=\"ow\">and</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">engine_model_type</span><span class=\"p\">)</span> <span class=\"o\">!=</span> <span class=\"s1\">&#39;16k_0&#39;</span> <span class=\"ow\">and</span> <span class=\"nb\">str</span><span class=\"p\">(</span>\n        <span class=\"n\">engine_model_type</span><span class=\"p\">)</span> <span class=\"o\">!=</span> <span class=\"s1\">&#39;16k_en&#39;</span><span class=\"p\">):</span>\n        <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"s1\">&#39;engine_model_type is not right&#39;</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span>\n    <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">res_type</span><span class=\"p\">))</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">or</span> <span class=\"p\">(</span><span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">res_type</span><span class=\"p\">)</span> <span class=\"o\">!=</span> <span class=\"s1\">&#39;0&#39;</span> <span class=\"ow\">and</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">res_type</span><span class=\"p\">)</span> <span class=\"o\">!=</span> <span class=\"s1\">&#39;1&#39;</span><span class=\"p\">):</span>\n        <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"s1\">&#39;res_type is not right&#39;</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span>\n    <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">result_text_format</span><span class=\"p\">))</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">or</span> <span class=\"p\">(</span><span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">result_text_format</span><span class=\"p\">)</span> <span class=\"o\">!=</span> <span class=\"s1\">&#39;0&#39;</span> <span class=\"ow\">and</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">result_text_format</span><span class=\"p\">)</span> <span class=\"o\">!=</span> <span class=\"s1\">&#39;1&#39;</span> <span class=\"ow\">and</span> <span class=\"nb\">str</span><span class=\"p\">(</span>\n            <span class=\"n\">result_text_format</span><span class=\"p\">)</span> <span class=\"o\">!=</span> <span class=\"s1\">&#39;2&#39;</span> <span class=\"ow\">and</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">result_text_format</span><span class=\"p\">)</span> <span class=\"o\">!=</span> <span class=\"s1\">&#39;3&#39;</span><span class=\"p\">):</span>\n        <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"s1\">&#39;result_text_format is not right&#39;</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span>\n    <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">voice_format</span><span class=\"p\">))</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">or</span> <span class=\"p\">(</span>\n            <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">voice_format</span><span class=\"p\">)</span> <span class=\"o\">!=</span> <span class=\"s1\">&#39;1&#39;</span> <span class=\"ow\">and</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">voice_format</span><span class=\"p\">)</span> <span class=\"o\">!=</span> <span class=\"s1\">&#39;4&#39;</span> <span class=\"ow\">and</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">voice_format</span><span class=\"p\">)</span> <span class=\"o\">!=</span> <span class=\"s1\">&#39;6&#39;</span><span class=\"p\">):</span>\n        <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"s1\">&#39;voice_format is not right&#39;</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span>\n    <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">filepath</span><span class=\"p\">))</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"s1\">&#39;filepath can not empty&#39;</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span>\n    <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">cutlength</span><span class=\"p\">))</span> <span class=\"o\">==</span> <span class=\"mi\">0</span> <span class=\"ow\">or</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">cutlength</span><span class=\"p\">)</span><span class=\"o\">.</span><span class=\"n\">isdigit</span><span class=\"p\">()</span> <span class=\"o\">==</span> <span class=\"kc\">False</span> <span class=\"ow\">or</span> <span class=\"n\">cutlength</span> <span class=\"o\">&gt;</span> <span class=\"mi\">200000</span><span class=\"p\">:</span>\n        <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"s1\">&#39;cutlength can not empty&#39;</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span>\n    <span class=\"c1\"># secret_key = &quot;oaYWFO70LGDmcpfwo8uF1IInayysGtgZ&quot;</span>\n    <span class=\"n\">query_arr</span> <span class=\"o\">=</span> <span class=\"nb\">dict</span><span class=\"p\">()</span>\n    <span class=\"n\">query_arr</span><span class=\"p\">[</span><span class=\"s1\">&#39;appid&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">appid</span>\n    <span class=\"n\">query_arr</span><span class=\"p\">[</span><span class=\"s1\">&#39;projectid&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"mi\">1013976</span>\n    <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">template_name</span><span class=\"p\">)</span> <span class=\"o\">&gt;</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n        <span class=\"n\">query_arr</span><span class=\"p\">[</span><span class=\"s1\">&#39;template_name&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">template_name</span>\n    <span class=\"n\">query_arr</span><span class=\"p\">[</span><span class=\"s1\">&#39;sub_service_type&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n    <span class=\"n\">query_arr</span><span class=\"p\">[</span><span class=\"s1\">&#39;engine_model_type&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">engine_model_type</span>\n    <span class=\"n\">query_arr</span><span class=\"p\">[</span><span class=\"s1\">&#39;res_type&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">res_type</span>\n    <span class=\"n\">query_arr</span><span class=\"p\">[</span><span class=\"s1\">&#39;result_text_format&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">result_text_format</span>\n    <span class=\"n\">query_arr</span><span class=\"p\">[</span><span class=\"s1\">&#39;voice_id&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">randstr</span><span class=\"p\">(</span><span class=\"mi\">16</span><span class=\"p\">)</span>\n    <span class=\"n\">query_arr</span><span class=\"p\">[</span><span class=\"s1\">&#39;timeout&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"mi\">100</span>\n    <span class=\"n\">query_arr</span><span class=\"p\">[</span><span class=\"s1\">&#39;source&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">query_arr</span><span class=\"p\">[</span><span class=\"s1\">&#39;secretid&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">secretid</span>\n    <span class=\"n\">query_arr</span><span class=\"p\">[</span><span class=\"s1\">&#39;timestamp&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"o\">.</span><span class=\"n\">time</span><span class=\"p\">()))</span>\n    <span class=\"n\">query_arr</span><span class=\"p\">[</span><span class=\"s1\">&#39;expired&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"o\">.</span><span class=\"n\">time</span><span class=\"p\">())</span> <span class=\"o\">+</span> <span class=\"mi\">24</span> <span class=\"o\">*</span> <span class=\"mi\">60</span> <span class=\"o\">*</span> <span class=\"mi\">60</span>\n    <span class=\"n\">query_arr</span><span class=\"p\">[</span><span class=\"s1\">&#39;nonce&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">query_arr</span><span class=\"p\">[</span><span class=\"s1\">&#39;timestamp&#39;</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">:</span><span class=\"mi\">4</span><span class=\"p\">]</span>\n    <span class=\"n\">query_arr</span><span class=\"p\">[</span><span class=\"s1\">&#39;voice_format&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">voice_format</span>\n    <span class=\"n\">file_object</span> <span class=\"o\">=</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">filepath</span><span class=\"p\">,</span> <span class=\"s1\">&#39;rb&#39;</span><span class=\"p\">)</span>\n    <span class=\"n\">file_object</span><span class=\"o\">.</span><span class=\"n\">seek</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">SEEK_END</span><span class=\"p\">)</span>\n    <span class=\"n\">datalen</span> <span class=\"o\">=</span> <span class=\"n\">file_object</span><span class=\"o\">.</span><span class=\"n\">tell</span><span class=\"p\">()</span>\n    <span class=\"n\">file_object</span><span class=\"o\">.</span><span class=\"n\">seek</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">SEEK_SET</span><span class=\"p\">)</span>\n    <span class=\"n\">seq</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n    <span class=\"n\">response</span> <span class=\"o\">=</span> <span class=\"p\">[]</span>\n    <span class=\"k\">while</span> <span class=\"p\">(</span><span class=\"n\">datalen</span> <span class=\"o\">&gt;</span> <span class=\"mi\">0</span><span class=\"p\">):</span>\n        <span class=\"n\">end</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n        <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">datalen</span> <span class=\"o\">&lt;</span> <span class=\"n\">cutlength</span><span class=\"p\">):</span>\n            <span class=\"n\">end</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n        <span class=\"n\">query_arr</span><span class=\"p\">[</span><span class=\"s1\">&#39;end&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">end</span>\n        <span class=\"n\">query_arr</span><span class=\"p\">[</span><span class=\"s1\">&#39;seq&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">seq</span>\n        <span class=\"n\">query</span> <span class=\"o\">=</span> <span class=\"nb\">sorted</span><span class=\"p\">(</span><span class=\"n\">query_arr</span><span class=\"o\">.</span><span class=\"n\">items</span><span class=\"p\">(),</span> <span class=\"n\">key</span><span class=\"o\">=</span><span class=\"k\">lambda</span> <span class=\"n\">d</span><span class=\"p\">:</span> <span class=\"n\">d</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n        <span class=\"n\">signstr</span> <span class=\"o\">=</span> <span class=\"n\">formatSignString</span><span class=\"p\">(</span><span class=\"n\">query</span><span class=\"p\">)</span>\n        <span class=\"n\">autho</span> <span class=\"o\">=</span> <span class=\"n\">sign</span><span class=\"p\">(</span><span class=\"n\">signstr</span><span class=\"p\">,</span> <span class=\"n\">secret_key</span><span class=\"p\">)</span>\n\n        <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">datalen</span> <span class=\"o\">&lt;</span> <span class=\"n\">cutlength</span><span class=\"p\">):</span>\n            <span class=\"n\">content</span> <span class=\"o\">=</span> <span class=\"n\">file_object</span><span class=\"o\">.</span><span class=\"n\">read</span><span class=\"p\">(</span><span class=\"n\">datalen</span><span class=\"p\">)</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"n\">content</span> <span class=\"o\">=</span> <span class=\"n\">file_object</span><span class=\"o\">.</span><span class=\"n\">read</span><span class=\"p\">(</span><span class=\"n\">cutlength</span><span class=\"p\">)</span>\n        <span class=\"n\">seq</span> <span class=\"o\">=</span> <span class=\"n\">seq</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n        <span class=\"n\">datalen</span> <span class=\"o\">=</span> <span class=\"n\">datalen</span> <span class=\"o\">-</span> <span class=\"n\">cutlength</span>\n        <span class=\"n\">headers</span> <span class=\"o\">=</span> <span class=\"nb\">dict</span><span class=\"p\">()</span>\n        <span class=\"n\">headers</span><span class=\"p\">[</span><span class=\"s1\">&#39;Authorization&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">autho</span>\n        <span class=\"n\">headers</span><span class=\"p\">[</span><span class=\"s1\">&#39;Content-Length&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">content</span><span class=\"p\">)</span>\n        <span class=\"n\">requrl</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;http://&quot;</span>\n        <span class=\"n\">requrl</span> <span class=\"o\">+=</span> <span class=\"n\">signstr</span><span class=\"p\">[</span><span class=\"mi\">4</span><span class=\"p\">::]</span>\n        <span class=\"n\">req</span> <span class=\"o\">=</span> <span class=\"n\">urllib</span><span class=\"o\">.</span><span class=\"n\">request</span><span class=\"o\">.</span><span class=\"n\">Request</span><span class=\"p\">(</span><span class=\"n\">requrl</span><span class=\"p\">,</span> <span class=\"n\">data</span><span class=\"o\">=</span><span class=\"n\">content</span><span class=\"p\">,</span> <span class=\"n\">headers</span><span class=\"o\">=</span><span class=\"n\">headers</span><span class=\"p\">)</span>        \n        <span class=\"n\">res_data</span> <span class=\"o\">=</span> <span class=\"n\">urllib</span><span class=\"o\">.</span><span class=\"n\">request</span><span class=\"o\">.</span><span class=\"n\">urlopen</span><span class=\"p\">(</span><span class=\"n\">req</span><span class=\"p\">)</span>\n        <span class=\"n\">r</span> <span class=\"o\">=</span> <span class=\"n\">res_data</span><span class=\"o\">.</span><span class=\"n\">read</span><span class=\"p\">()</span><span class=\"o\">.</span><span class=\"n\">decode</span><span class=\"p\">(</span><span class=\"s1\">&#39;utf-8&#39;</span><span class=\"p\">)</span>\n        <span class=\"n\">res</span> <span class=\"o\">=</span> <span class=\"n\">json</span><span class=\"o\">.</span><span class=\"n\">loads</span><span class=\"p\">(</span><span class=\"n\">r</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">res</span><span class=\"p\">[</span><span class=\"s1\">&#39;code&#39;</span><span class=\"p\">]</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"n\">response</span><span class=\"o\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">res</span><span class=\"p\">[</span><span class=\"s1\">&#39;text&#39;</span><span class=\"p\">])</span>    \n    <span class=\"n\">file_object</span><span class=\"o\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n    <span class=\"k\">return</span> <span class=\"n\">response</span><span class=\"p\">[</span><span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">response</span><span class=\"p\">)</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">]</span></div>\n\n\n</pre></div>\n\n           </div>\n           \n          </div>\n          <footer>\n  \n\n  <hr/>\n\n  <div role=\"contentinfo\">\n    <p>\n        &copy; Copyright 2019, wzpan\n\n    </p>\n  </div>\n  Built with <a href=\"http://sphinx-doc.org/\">Sphinx</a> using a <a href=\"https://github.com/rtfd/sphinx_rtd_theme\">theme</a> provided by <a href=\"https://readthedocs.org\">Read the Docs</a>. \n\n</footer>\n\n        </div>\n      </div>\n\n    </section>\n\n  </div>\n  \n\n\n  <script type=\"text/javascript\">\n      jQuery(function () {\n          SphinxRtdTheme.Navigation.enable(true);\n      });\n  </script>\n\n  \n  \n    \n   \n\n</body>\n</html>"
  },
  {
    "path": "docs/_modules/robot/sdk/TencentSpeech.html",
    "content": "\n\n<!DOCTYPE html>\n<!--[if IE 8]><html class=\"no-js lt-ie9\" lang=\"zh-CN\" > <![endif]-->\n<!--[if gt IE 8]><!--> <html class=\"no-js\" lang=\"zh-CN\" > <!--<![endif]-->\n<head>\n  <meta charset=\"utf-8\">\n  \n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  \n  <title>robot.sdk.TencentSpeech &mdash; wukong-robot 1.2.0 文档</title>\n  \n\n  \n  \n  \n  \n\n  \n  <script type=\"text/javascript\" src=\"../../../_static/js/modernizr.min.js\"></script>\n  \n    \n      <script type=\"text/javascript\" id=\"documentation_options\" data-url_root=\"../../../\" src=\"../../../_static/documentation_options.js\"></script>\n        <script type=\"text/javascript\" src=\"../../../_static/jquery.js\"></script>\n        <script type=\"text/javascript\" src=\"../../../_static/underscore.js\"></script>\n        <script type=\"text/javascript\" src=\"../../../_static/doctools.js\"></script>\n        <script type=\"text/javascript\" src=\"../../../_static/language_data.js\"></script>\n        <script type=\"text/javascript\" src=\"../../../_static/translations.js\"></script>\n    \n    <script type=\"text/javascript\" src=\"../../../_static/js/theme.js\"></script>\n\n    \n\n  \n  <link rel=\"stylesheet\" href=\"../../../_static/css/theme.css\" type=\"text/css\" />\n  <link rel=\"stylesheet\" href=\"../../../_static/pygments.css\" type=\"text/css\" />\n    <link rel=\"index\" title=\"索引\" href=\"../../../genindex.html\" />\n    <link rel=\"search\" title=\"搜索\" href=\"../../../search.html\" /> \n</head>\n\n<body class=\"wy-body-for-nav\">\n\n   \n  <div class=\"wy-grid-for-nav\">\n    \n    <nav data-toggle=\"wy-nav-shift\" class=\"wy-nav-side\">\n      <div class=\"wy-side-scroll\">\n        <div class=\"wy-side-nav-search\" >\n          \n\n          \n            <a href=\"../../../index.html\" class=\"icon icon-home\"> wukong-robot\n          \n\n          \n          </a>\n\n          \n            \n            \n          \n\n          \n<div role=\"search\">\n  <form id=\"rtd-search-form\" class=\"wy-form\" action=\"../../../search.html\" method=\"get\">\n    <input type=\"text\" name=\"q\" placeholder=\"Search docs\" />\n    <input type=\"hidden\" name=\"check_keywords\" value=\"yes\" />\n    <input type=\"hidden\" name=\"area\" value=\"default\" />\n  </form>\n</div>\n\n          \n        </div>\n\n        <div class=\"wy-menu wy-menu-vertical\" data-spy=\"affix\" role=\"navigation\" aria-label=\"main navigation\">\n          \n            \n            \n              \n            \n            \n              <!-- Local TOC -->\n              <div class=\"local-toc\"></div>\n            \n          \n        </div>\n      </div>\n    </nav>\n\n    <section data-toggle=\"wy-nav-shift\" class=\"wy-nav-content-wrap\">\n\n      \n      <nav class=\"wy-nav-top\" aria-label=\"top navigation\">\n        \n          <i data-toggle=\"wy-nav-top\" class=\"fa fa-bars\"></i>\n          <a href=\"../../../index.html\">wukong-robot</a>\n        \n      </nav>\n\n\n      <div class=\"wy-nav-content\">\n        \n        <div class=\"rst-content\">\n        \n          \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<div role=\"navigation\" aria-label=\"breadcrumbs navigation\">\n\n  <ul class=\"wy-breadcrumbs\">\n    \n      <li><a href=\"../../../index.html\">Docs</a> &raquo;</li>\n        \n          <li><a href=\"../../index.html\">模块代码</a> &raquo;</li>\n        \n      <li>robot.sdk.TencentSpeech</li>\n    \n    \n      <li class=\"wy-breadcrumbs-aside\">\n        \n      </li>\n    \n  </ul>\n\n  \n  <hr/>\n</div>\n          <div role=\"main\" class=\"document\" itemscope=\"itemscope\" itemtype=\"http://schema.org/Article\">\n           <div itemprop=\"articleBody\">\n            \n  <h1>robot.sdk.TencentSpeech 源代码</h1><div class=\"highlight\"><pre>\n<span></span><span class=\"c1\"># coding: utf-8</span>\n<span class=\"c1\">#!/usr/bin/env python3</span>\n\n\n<span class=\"s1\">&#39;Tencent ASR &amp;&amp; TTS API&#39;</span>\n<span class=\"n\">__author__</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;Charles Li, Joseph Pan&#39;</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">uuid</span>\n<span class=\"kn\">import</span> <span class=\"nn\">json</span>\n<span class=\"kn\">import</span> <span class=\"nn\">random</span>\n<span class=\"kn\">import</span> <span class=\"nn\">requests</span>\n<span class=\"kn\">import</span> <span class=\"nn\">hmac</span>\n<span class=\"kn\">import</span> <span class=\"nn\">base64</span>\n<span class=\"kn\">import</span> <span class=\"nn\">urllib</span>\n<span class=\"c1\">#腾讯web API一句话识别请求</span>\n<div class=\"viewcode-block\" id=\"tencentSpeech\"><a class=\"viewcode-back\" href=\"../../../robot.sdk.html#robot.sdk.TencentSpeech.tencentSpeech\">[文档]</a><span class=\"k\">class</span> <span class=\"nc\">tencentSpeech</span><span class=\"p\">(</span><span class=\"nb\">object</span><span class=\"p\">):</span>\n    <span class=\"vm\">__slots__</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;SECRET_ID&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;SECRET_KEY&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;SourceType&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;URL&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;VoiceFormat&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;PrimaryLanguage&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;Text&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;VoiceType&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;Region&#39;</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">SECRET_KEY</span><span class=\"p\">,</span> <span class=\"n\">SECRET_ID</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">SECRET_KEY</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">SECRET_ID</span> <span class=\"o\">=</span> <span class=\"n\">SECRET_KEY</span><span class=\"p\">,</span> <span class=\"n\">SECRET_ID</span>\n    <span class=\"nd\">@property</span>\n    <span class=\"k\">def</span> <span class=\"nf\">secret_id</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">SECRET_ID</span>\n    <span class=\"nd\">@secret_id</span><span class=\"o\">.</span><span class=\"n\">setter</span>\n    <span class=\"k\">def</span> <span class=\"nf\">secret_id</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">SECRET_ID</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"nb\">isinstance</span><span class=\"p\">(</span><span class=\"n\">SECRET_ID</span><span class=\"p\">,</span> <span class=\"nb\">str</span><span class=\"p\">):</span>\n            <span class=\"k\">raise</span> <span class=\"ne\">ValueError</span><span class=\"p\">(</span><span class=\"s1\">&#39;SecretId must be a string!&#39;</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">SECRET_ID</span><span class=\"p\">)</span><span class=\"o\">==</span><span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"k\">raise</span> <span class=\"ne\">ValueError</span><span class=\"p\">(</span><span class=\"s1\">&#39;SecretId can not be empty!&#39;</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">SECRET_ID</span> <span class=\"o\">=</span> <span class=\"n\">SECRET_ID</span>\n    <span class=\"nd\">@property</span>\n    <span class=\"k\">def</span> <span class=\"nf\">secret_key</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">SECRET_KEY</span>\n    <span class=\"nd\">@secret_key</span><span class=\"o\">.</span><span class=\"n\">setter</span>\n    <span class=\"k\">def</span> <span class=\"nf\">secret_key</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">SECRET_KEY</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"nb\">isinstance</span><span class=\"p\">(</span><span class=\"n\">SECRET_KEY</span><span class=\"p\">,</span> <span class=\"nb\">str</span><span class=\"p\">):</span>\n            <span class=\"k\">raise</span> <span class=\"ne\">ValueError</span><span class=\"p\">(</span><span class=\"s1\">&#39;SecretKey must be a string!&#39;</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">SECRET_KEY</span><span class=\"p\">)</span><span class=\"o\">==</span><span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"k\">raise</span> <span class=\"ne\">ValueError</span><span class=\"p\">(</span><span class=\"s1\">&#39;SecretKey can not be empty!&#39;</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">SECRET_KEY</span> <span class=\"o\">=</span> <span class=\"n\">SECRET_KEY</span>\n    <span class=\"nd\">@property</span>\n    <span class=\"k\">def</span> <span class=\"nf\">source_type</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">sourcetype</span>\n    <span class=\"nd\">@source_type</span><span class=\"o\">.</span><span class=\"n\">setter</span>\n    <span class=\"k\">def</span> <span class=\"nf\">source_type</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">SourceType</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"nb\">isinstance</span><span class=\"p\">(</span><span class=\"n\">SourceType</span><span class=\"p\">,</span> <span class=\"nb\">str</span><span class=\"p\">):</span>\n            <span class=\"k\">raise</span> <span class=\"ne\">ValueError</span><span class=\"p\">(</span><span class=\"s1\">&#39;SecretType must be an string!&#39;</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">SourceType</span><span class=\"p\">)</span><span class=\"o\">==</span><span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"k\">raise</span> <span class=\"ne\">ValueError</span><span class=\"p\">(</span><span class=\"s1\">&#39;SourceType can not be empty!&#39;</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">SourceType</span> <span class=\"o\">=</span> <span class=\"n\">SourceType</span>\n    <span class=\"nd\">@property</span>\n    <span class=\"k\">def</span> <span class=\"nf\">url</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">URL</span>\n    <span class=\"nd\">@url</span><span class=\"o\">.</span><span class=\"n\">setter</span>\n    <span class=\"k\">def</span> <span class=\"nf\">url</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">URL</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"nb\">isinstance</span><span class=\"p\">(</span><span class=\"n\">URL</span><span class=\"p\">,</span> <span class=\"nb\">str</span><span class=\"p\">):</span>\n            <span class=\"k\">raise</span> <span class=\"ne\">ValueError</span><span class=\"p\">(</span><span class=\"s1\">&#39;url must be an string!&#39;</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">URL</span><span class=\"p\">)</span><span class=\"o\">==</span><span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"k\">raise</span> <span class=\"ne\">ValueError</span><span class=\"p\">(</span><span class=\"s1\">&#39;url can not be empty!&#39;</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">URL</span> <span class=\"o\">=</span> <span class=\"n\">URL</span>\n    <span class=\"nd\">@property</span>\n    <span class=\"k\">def</span> <span class=\"nf\">voiceformat</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">VoiceFormat</span>\n    <span class=\"nd\">@voiceformat</span><span class=\"o\">.</span><span class=\"n\">setter</span>\n    <span class=\"k\">def</span> <span class=\"nf\">voiceformat</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">VoiceFormat</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"nb\">isinstance</span><span class=\"p\">(</span><span class=\"n\">VoiceFormat</span><span class=\"p\">,</span> <span class=\"nb\">str</span><span class=\"p\">):</span>\n            <span class=\"k\">raise</span> <span class=\"ne\">ValueError</span><span class=\"p\">(</span><span class=\"s1\">&#39;voiceformat must be an string!&#39;</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">VoiceFormat</span><span class=\"p\">)</span><span class=\"o\">==</span><span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"k\">raise</span> <span class=\"ne\">ValueError</span><span class=\"p\">(</span><span class=\"s1\">&#39;voiceformat can not be empty!&#39;</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">VoiceFormat</span> <span class=\"o\">=</span> <span class=\"n\">VoiceFormat</span>\n    <span class=\"nd\">@property</span>\n    <span class=\"k\">def</span> <span class=\"nf\">text</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">Text</span>\n    <span class=\"nd\">@text</span><span class=\"o\">.</span><span class=\"n\">setter</span>\n    <span class=\"k\">def</span> <span class=\"nf\">text</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">Text</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"nb\">isinstance</span><span class=\"p\">(</span><span class=\"n\">Text</span><span class=\"p\">,</span> <span class=\"nb\">str</span><span class=\"p\">):</span>\n            <span class=\"k\">raise</span> <span class=\"ne\">ValueError</span><span class=\"p\">(</span><span class=\"s1\">&#39;text must be an string!&#39;</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">Text</span><span class=\"p\">)</span><span class=\"o\">==</span><span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"k\">raise</span> <span class=\"ne\">ValueError</span><span class=\"p\">(</span><span class=\"s1\">&#39;text can not be empty!&#39;</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">Text</span> <span class=\"o\">=</span> <span class=\"n\">Text</span>\n    <span class=\"nd\">@property</span>\n    <span class=\"k\">def</span> <span class=\"nf\">region</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">Region</span>\n    <span class=\"nd\">@region</span><span class=\"o\">.</span><span class=\"n\">setter</span>\n    <span class=\"k\">def</span> <span class=\"nf\">region</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">Region</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"nb\">isinstance</span><span class=\"p\">(</span><span class=\"n\">Region</span><span class=\"p\">,</span> <span class=\"nb\">str</span><span class=\"p\">):</span>\n            <span class=\"k\">raise</span> <span class=\"ne\">ValueError</span><span class=\"p\">(</span><span class=\"s1\">&#39;region must be an string!&#39;</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">Region</span><span class=\"p\">)</span><span class=\"o\">==</span><span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"k\">raise</span> <span class=\"ne\">ValueError</span><span class=\"p\">(</span><span class=\"s1\">&#39;region can not be empty!&#39;</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">Region</span> <span class=\"o\">=</span> <span class=\"n\">Region</span>\n    <span class=\"nd\">@property</span>\n    <span class=\"k\">def</span> <span class=\"nf\">primarylanguage</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">PrimaryLanguage</span>\n    <span class=\"nd\">@primarylanguage</span><span class=\"o\">.</span><span class=\"n\">setter</span>\n    <span class=\"k\">def</span> <span class=\"nf\">primarylanguage</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">PrimaryLanguage</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">PrimaryLanguage</span> <span class=\"o\">=</span> <span class=\"n\">PrimaryLanguage</span>\n    <span class=\"nd\">@property</span>\n    <span class=\"k\">def</span> <span class=\"nf\">voicetype</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">VoiceType</span>\n    <span class=\"nd\">@voicetype</span><span class=\"o\">.</span><span class=\"n\">setter</span>\n    <span class=\"k\">def</span> <span class=\"nf\">voicetype</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">VoiceType</span><span class=\"p\">):</span>        \n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">VoiceType</span> <span class=\"o\">=</span> <span class=\"n\">VoiceType</span>\n<div class=\"viewcode-block\" id=\"tencentSpeech.TTS\"><a class=\"viewcode-back\" href=\"../../../robot.sdk.html#robot.sdk.TencentSpeech.tencentSpeech.TTS\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">TTS</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">text</span><span class=\"p\">,</span> <span class=\"n\">voicetype</span><span class=\"p\">,</span> <span class=\"n\">primarylanguage</span><span class=\"p\">,</span> <span class=\"n\">region</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">text</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">voicetype</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">primarylanguage</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">region</span> <span class=\"o\">=</span> <span class=\"n\">text</span><span class=\"p\">,</span> <span class=\"n\">voicetype</span><span class=\"p\">,</span> <span class=\"n\">primarylanguage</span><span class=\"p\">,</span> <span class=\"n\">region</span>\n        <span class=\"k\">return</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">textToSpeech</span><span class=\"p\">()</span></div>\n<div class=\"viewcode-block\" id=\"tencentSpeech.textToSpeech\"><a class=\"viewcode-back\" href=\"../../../robot.sdk.html#robot.sdk.TencentSpeech.tencentSpeech.textToSpeech\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">textToSpeech</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"c1\">#生成body</span>\n        <span class=\"k\">def</span> <span class=\"nf\">make_body</span><span class=\"p\">(</span><span class=\"n\">config_dict</span><span class=\"p\">,</span> <span class=\"n\">sign_encode</span><span class=\"p\">):</span>\n            <span class=\"c1\">##注意URL编码的时候分str编码，整段编码会丢data</span>\n            <span class=\"n\">body</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;&#39;</span>\n            <span class=\"k\">for</span> <span class=\"n\">a</span><span class=\"p\">,</span> <span class=\"n\">b</span> <span class=\"ow\">in</span> <span class=\"n\">config_dict</span><span class=\"p\">:</span>\n                <span class=\"n\">body</span> <span class=\"o\">+=</span> <span class=\"n\">urllib</span><span class=\"o\">.</span><span class=\"n\">parse</span><span class=\"o\">.</span><span class=\"n\">quote</span><span class=\"p\">(</span><span class=\"n\">a</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"s1\">&#39;=&#39;</span> <span class=\"o\">+</span> <span class=\"n\">urllib</span><span class=\"o\">.</span><span class=\"n\">parse</span><span class=\"o\">.</span><span class=\"n\">quote</span><span class=\"p\">(</span><span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">b</span><span class=\"p\">))</span> <span class=\"o\">+</span> <span class=\"s1\">&#39;&amp;&#39;</span>\n            <span class=\"k\">return</span> <span class=\"n\">body</span> <span class=\"o\">+</span> <span class=\"s1\">&#39;Signature=&#39;</span> <span class=\"o\">+</span> <span class=\"n\">sign_encode</span>\n        <span class=\"n\">HOST</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;aai.tencentcloudapi.com&#39;</span>\n        <span class=\"n\">config_dict</span><span class=\"o\">=</span> <span class=\"p\">{</span>\n                        <span class=\"s1\">&#39;Action&#39;</span>         <span class=\"p\">:</span> <span class=\"s1\">&#39;TextToVoice&#39;</span><span class=\"p\">,</span>\n                        <span class=\"s1\">&#39;Version&#39;</span>        <span class=\"p\">:</span> <span class=\"s1\">&#39;2018-05-22&#39;</span><span class=\"p\">,</span>\n                        <span class=\"s1\">&#39;ProjectId&#39;</span>      <span class=\"p\">:</span> <span class=\"mi\">0</span><span class=\"p\">,</span>\n                        <span class=\"s1\">&#39;Region&#39;</span>         <span class=\"p\">:</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">Region</span><span class=\"p\">,</span>\n                        <span class=\"s1\">&#39;VoiceType&#39;</span>      <span class=\"p\">:</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">VoiceType</span><span class=\"p\">,</span>\n                        <span class=\"s1\">&#39;Timestamp&#39;</span>      <span class=\"p\">:</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"o\">.</span><span class=\"n\">time</span><span class=\"p\">()),</span>\n                        <span class=\"s1\">&#39;Nonce&#39;</span>          <span class=\"p\">:</span> <span class=\"n\">random</span><span class=\"o\">.</span><span class=\"n\">randint</span><span class=\"p\">(</span><span class=\"mi\">100000</span><span class=\"p\">,</span> <span class=\"mi\">200000</span><span class=\"p\">),</span>\n                        <span class=\"s1\">&#39;SecretId&#39;</span>       <span class=\"p\">:</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">SECRET_ID</span><span class=\"p\">,</span>\n                        <span class=\"s1\">&#39;Text&#39;</span>           <span class=\"p\">:</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">Text</span><span class=\"p\">,</span>\n                        <span class=\"s1\">&#39;PrimaryLanguage&#39;</span><span class=\"p\">:</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">PrimaryLanguage</span><span class=\"p\">,</span>\n                        <span class=\"s1\">&#39;ModelType&#39;</span>      <span class=\"p\">:</span> <span class=\"mi\">1</span><span class=\"p\">,</span>\n                        <span class=\"s1\">&#39;SessionId&#39;</span>      <span class=\"p\">:</span> <span class=\"n\">uuid</span><span class=\"o\">.</span><span class=\"n\">uuid1</span><span class=\"p\">()</span>\n        <span class=\"p\">}</span>\n        <span class=\"c1\">#按key排序</span>\n        <span class=\"n\">config_dict</span> <span class=\"o\">=</span> <span class=\"nb\">sorted</span><span class=\"p\">(</span><span class=\"n\">config_dict</span><span class=\"o\">.</span><span class=\"n\">items</span><span class=\"p\">())</span>\n        <span class=\"n\">signstr</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">formatSignString</span><span class=\"p\">(</span><span class=\"n\">config_dict</span><span class=\"p\">)</span>\n        <span class=\"n\">sign_encode</span> <span class=\"o\">=</span> <span class=\"n\">urllib</span><span class=\"o\">.</span><span class=\"n\">parse</span><span class=\"o\">.</span><span class=\"n\">quote</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">encode_sign</span><span class=\"p\">(</span><span class=\"n\">signstr</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">SECRET_KEY</span><span class=\"p\">))</span>\n        <span class=\"n\">body</span> <span class=\"o\">=</span> <span class=\"n\">make_body</span><span class=\"p\">(</span><span class=\"n\">config_dict</span><span class=\"p\">,</span> <span class=\"n\">sign_encode</span><span class=\"p\">)</span>\n        <span class=\"c1\">#Get URL</span>\n        <span class=\"n\">req_url</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;https://aai.tencentcloudapi.com&quot;</span>\n        <span class=\"n\">header</span> <span class=\"o\">=</span> <span class=\"p\">{</span>\n            <span class=\"s1\">&#39;Host&#39;</span> <span class=\"p\">:</span> <span class=\"n\">HOST</span><span class=\"p\">,</span>\n            <span class=\"s1\">&#39;Content-Type&#39;</span> <span class=\"p\">:</span> <span class=\"s1\">&#39;application/x-www-form-urlencoded&#39;</span><span class=\"p\">,</span>\n            <span class=\"s1\">&#39;Charset&#39;</span> <span class=\"p\">:</span> <span class=\"s1\">&#39;UTF-8&#39;</span>\n        <span class=\"p\">}</span>\n        <span class=\"n\">request</span> <span class=\"o\">=</span> <span class=\"n\">requests</span><span class=\"o\">.</span><span class=\"n\">post</span><span class=\"p\">(</span><span class=\"n\">req_url</span><span class=\"p\">,</span> <span class=\"n\">headers</span> <span class=\"o\">=</span> <span class=\"n\">header</span><span class=\"p\">,</span> <span class=\"n\">data</span> <span class=\"o\">=</span> <span class=\"n\">body</span><span class=\"p\">)</span>\n        <span class=\"c1\">#有些音频utf8解码失败，存在编码错误</span>\n        <span class=\"n\">s</span> <span class=\"o\">=</span> <span class=\"n\">request</span><span class=\"o\">.</span><span class=\"n\">content</span><span class=\"o\">.</span><span class=\"n\">decode</span><span class=\"p\">(</span><span class=\"s2\">&quot;utf8&quot;</span><span class=\"p\">,</span><span class=\"s2\">&quot;ignore&quot;</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span> <span class=\"n\">json</span><span class=\"o\">.</span><span class=\"n\">loads</span><span class=\"p\">(</span><span class=\"n\">s</span><span class=\"p\">)</span></div>\n<div class=\"viewcode-block\" id=\"tencentSpeech.ASR\"><a class=\"viewcode-back\" href=\"../../../robot.sdk.html#robot.sdk.TencentSpeech.tencentSpeech.ASR\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">ASR</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">URL</span><span class=\"p\">,</span> <span class=\"n\">voiceformat</span><span class=\"p\">,</span> <span class=\"n\">sourcetype</span><span class=\"p\">,</span> <span class=\"n\">region</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">url</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">voiceformat</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">source_type</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">region</span> <span class=\"o\">=</span> <span class=\"n\">URL</span><span class=\"p\">,</span> <span class=\"n\">voiceformat</span><span class=\"p\">,</span> <span class=\"n\">sourcetype</span><span class=\"p\">,</span> <span class=\"n\">region</span>\n        <span class=\"k\">return</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">oneSentenceRecognition</span><span class=\"p\">()</span></div>\n<div class=\"viewcode-block\" id=\"tencentSpeech.oneSentenceRecognition\"><a class=\"viewcode-back\" href=\"../../../robot.sdk.html#robot.sdk.TencentSpeech.tencentSpeech.oneSentenceRecognition\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">oneSentenceRecognition</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"c1\">#生成body</span>\n        <span class=\"k\">def</span> <span class=\"nf\">make_body</span><span class=\"p\">(</span><span class=\"n\">config_dict</span><span class=\"p\">,</span> <span class=\"n\">sign_encode</span><span class=\"p\">):</span>\n            <span class=\"c1\">##注意URL编码的时候分str编码，整段编码会丢data</span>\n            <span class=\"n\">body</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;&#39;</span>\n            <span class=\"k\">for</span> <span class=\"n\">a</span><span class=\"p\">,</span> <span class=\"n\">b</span> <span class=\"ow\">in</span> <span class=\"n\">config_dict</span><span class=\"p\">:</span>\n                <span class=\"n\">body</span> <span class=\"o\">+=</span> <span class=\"n\">urllib</span><span class=\"o\">.</span><span class=\"n\">parse</span><span class=\"o\">.</span><span class=\"n\">quote</span><span class=\"p\">(</span><span class=\"n\">a</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"s1\">&#39;=&#39;</span> <span class=\"o\">+</span> <span class=\"n\">urllib</span><span class=\"o\">.</span><span class=\"n\">parse</span><span class=\"o\">.</span><span class=\"n\">quote</span><span class=\"p\">(</span><span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">b</span><span class=\"p\">))</span> <span class=\"o\">+</span> <span class=\"s1\">&#39;&amp;&#39;</span>\n            <span class=\"k\">return</span> <span class=\"n\">body</span> <span class=\"o\">+</span> <span class=\"s1\">&#39;Signature=&#39;</span> <span class=\"o\">+</span> <span class=\"n\">sign_encode</span>\n        <span class=\"n\">HOST</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;aai.tencentcloudapi.com&#39;</span>\n        <span class=\"n\">config_dict</span><span class=\"o\">=</span> <span class=\"p\">{</span>\n                        <span class=\"s1\">&#39;Action&#39;</span>         <span class=\"p\">:</span> <span class=\"s1\">&#39;SentenceRecognition&#39;</span><span class=\"p\">,</span>\n                        <span class=\"s1\">&#39;Version&#39;</span>        <span class=\"p\">:</span> <span class=\"s1\">&#39;2018-05-22&#39;</span><span class=\"p\">,</span>\n                        <span class=\"s1\">&#39;Region&#39;</span>         <span class=\"p\">:</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">Region</span><span class=\"p\">,</span>\n                        <span class=\"s1\">&#39;ProjectId&#39;</span>      <span class=\"p\">:</span> <span class=\"mi\">0</span><span class=\"p\">,</span>\n                        <span class=\"s1\">&#39;SubServiceType&#39;</span> <span class=\"p\">:</span> <span class=\"mi\">2</span><span class=\"p\">,</span>\n                        <span class=\"s1\">&#39;EngSerViceType&#39;</span> <span class=\"p\">:</span> <span class=\"s1\">&#39;16k&#39;</span><span class=\"p\">,</span>\n                        <span class=\"s1\">&#39;VoiceFormat&#39;</span>    <span class=\"p\">:</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">VoiceFormat</span><span class=\"p\">,</span>\n                        <span class=\"s1\">&#39;UsrAudioKey&#39;</span>    <span class=\"p\">:</span> <span class=\"n\">random</span><span class=\"o\">.</span><span class=\"n\">randint</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">20</span><span class=\"p\">),</span>\n                        <span class=\"s1\">&#39;Timestamp&#39;</span>      <span class=\"p\">:</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"o\">.</span><span class=\"n\">time</span><span class=\"p\">()),</span>\n                        <span class=\"s1\">&#39;Nonce&#39;</span>          <span class=\"p\">:</span> <span class=\"n\">random</span><span class=\"o\">.</span><span class=\"n\">randint</span><span class=\"p\">(</span><span class=\"mi\">100000</span><span class=\"p\">,</span> <span class=\"mi\">200000</span><span class=\"p\">),</span>\n                        <span class=\"s1\">&#39;SecretId&#39;</span>       <span class=\"p\">:</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">SECRET_ID</span><span class=\"p\">,</span>\n                        <span class=\"s1\">&#39;SourceType&#39;</span>     <span class=\"p\">:</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">SourceType</span>\n        <span class=\"p\">}</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">SourceType</span> <span class=\"o\">==</span> <span class=\"s1\">&#39;0&#39;</span><span class=\"p\">:</span>\n            <span class=\"n\">config_dict</span><span class=\"p\">[</span><span class=\"s1\">&#39;Url&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">urllib</span><span class=\"o\">.</span><span class=\"n\">parse</span><span class=\"o\">.</span><span class=\"n\">quote</span><span class=\"p\">(</span><span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">url</span><span class=\"p\">))</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"c1\">#不能大于1M</span>\n            <span class=\"n\">file_path</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">URL</span>\n            <span class=\"n\">file</span> <span class=\"o\">=</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">file_path</span><span class=\"p\">,</span> <span class=\"s1\">&#39;rb&#39;</span><span class=\"p\">)</span>\n            <span class=\"n\">content</span> <span class=\"o\">=</span> <span class=\"n\">file</span><span class=\"o\">.</span><span class=\"n\">read</span><span class=\"p\">()</span>\n            <span class=\"n\">config_dict</span><span class=\"p\">[</span><span class=\"s1\">&#39;DataLen&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">content</span><span class=\"p\">)</span>\n            <span class=\"n\">config_dict</span><span class=\"p\">[</span><span class=\"s1\">&#39;Data&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">base64</span><span class=\"o\">.</span><span class=\"n\">b64encode</span><span class=\"p\">(</span><span class=\"n\">content</span><span class=\"p\">)</span><span class=\"o\">.</span><span class=\"n\">decode</span><span class=\"p\">()</span>\n            <span class=\"c1\">#config_dict[&#39;Data&#39;] = content</span>\n            <span class=\"n\">file</span><span class=\"o\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n        <span class=\"c1\">#按key排序</span>\n        <span class=\"n\">config_dict</span> <span class=\"o\">=</span> <span class=\"nb\">sorted</span><span class=\"p\">(</span><span class=\"n\">config_dict</span><span class=\"o\">.</span><span class=\"n\">items</span><span class=\"p\">())</span>\n        <span class=\"n\">signstr</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">formatSignString</span><span class=\"p\">(</span><span class=\"n\">config_dict</span><span class=\"p\">)</span>\n        <span class=\"n\">sign_encode</span> <span class=\"o\">=</span> <span class=\"n\">urllib</span><span class=\"o\">.</span><span class=\"n\">parse</span><span class=\"o\">.</span><span class=\"n\">quote</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">encode_sign</span><span class=\"p\">(</span><span class=\"n\">signstr</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">SECRET_KEY</span><span class=\"p\">))</span>\n        <span class=\"n\">body</span> <span class=\"o\">=</span> <span class=\"n\">make_body</span><span class=\"p\">(</span><span class=\"n\">config_dict</span><span class=\"p\">,</span> <span class=\"n\">sign_encode</span><span class=\"p\">)</span>\n        <span class=\"c1\">#Get URL</span>\n        <span class=\"n\">req_url</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;https://aai.tencentcloudapi.com&quot;</span>\n        <span class=\"n\">header</span> <span class=\"o\">=</span> <span class=\"p\">{</span>\n            <span class=\"s1\">&#39;Host&#39;</span> <span class=\"p\">:</span> <span class=\"n\">HOST</span><span class=\"p\">,</span>\n            <span class=\"s1\">&#39;Content-Type&#39;</span> <span class=\"p\">:</span> <span class=\"s1\">&#39;application/x-www-form-urlencoded&#39;</span><span class=\"p\">,</span>\n            <span class=\"s1\">&#39;Charset&#39;</span> <span class=\"p\">:</span> <span class=\"s1\">&#39;UTF-8&#39;</span>\n        <span class=\"p\">}</span>\n        <span class=\"n\">request</span> <span class=\"o\">=</span> <span class=\"n\">requests</span><span class=\"o\">.</span><span class=\"n\">post</span><span class=\"p\">(</span><span class=\"n\">req_url</span><span class=\"p\">,</span> <span class=\"n\">headers</span> <span class=\"o\">=</span> <span class=\"n\">header</span><span class=\"p\">,</span> <span class=\"n\">data</span> <span class=\"o\">=</span> <span class=\"n\">body</span><span class=\"p\">)</span>\n        <span class=\"c1\">#有些音频utf8解码失败，存在编码错误</span>\n        <span class=\"n\">s</span> <span class=\"o\">=</span> <span class=\"n\">request</span><span class=\"o\">.</span><span class=\"n\">content</span><span class=\"o\">.</span><span class=\"n\">decode</span><span class=\"p\">(</span><span class=\"s2\">&quot;utf8&quot;</span><span class=\"p\">,</span><span class=\"s2\">&quot;ignore&quot;</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span> <span class=\"n\">s</span></div>\n    <span class=\"c1\">#拼接url和参数</span>\n<div class=\"viewcode-block\" id=\"tencentSpeech.formatSignString\"><a class=\"viewcode-back\" href=\"../../../robot.sdk.html#robot.sdk.TencentSpeech.tencentSpeech.formatSignString\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">formatSignString</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">config_dict</span><span class=\"p\">):</span>\n        <span class=\"n\">signstr</span><span class=\"o\">=</span><span class=\"s2\">&quot;POSTaai.tencentcloudapi.com/?&quot;</span>\n        <span class=\"n\">argArr</span> <span class=\"o\">=</span> <span class=\"p\">[]</span>\n        <span class=\"k\">for</span> <span class=\"n\">a</span><span class=\"p\">,</span> <span class=\"n\">b</span> <span class=\"ow\">in</span> <span class=\"n\">config_dict</span><span class=\"p\">:</span>\n            <span class=\"n\">argArr</span><span class=\"o\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">a</span> <span class=\"o\">+</span> <span class=\"s2\">&quot;=&quot;</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">b</span><span class=\"p\">))</span>\n        <span class=\"n\">config_str</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;&amp;&quot;</span><span class=\"o\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">argArr</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span> <span class=\"n\">signstr</span> <span class=\"o\">+</span> <span class=\"n\">config_str</span></div>\n    <span class=\"c1\">#生成签名</span>\n<div class=\"viewcode-block\" id=\"tencentSpeech.encode_sign\"><a class=\"viewcode-back\" href=\"../../../robot.sdk.html#robot.sdk.TencentSpeech.tencentSpeech.encode_sign\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">encode_sign</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">signstr</span><span class=\"p\">,</span> <span class=\"n\">SECRET_KEY</span><span class=\"p\">):</span>\n        <span class=\"n\">myhmac</span> <span class=\"o\">=</span> <span class=\"n\">hmac</span><span class=\"o\">.</span><span class=\"n\">new</span><span class=\"p\">(</span><span class=\"n\">SECRET_KEY</span><span class=\"o\">.</span><span class=\"n\">encode</span><span class=\"p\">(),</span> <span class=\"n\">signstr</span><span class=\"o\">.</span><span class=\"n\">encode</span><span class=\"p\">(),</span> <span class=\"n\">digestmod</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;sha1&#39;</span><span class=\"p\">)</span>\n        <span class=\"n\">code</span> <span class=\"o\">=</span> <span class=\"n\">myhmac</span><span class=\"o\">.</span><span class=\"n\">digest</span><span class=\"p\">()</span>\n        <span class=\"c1\">#hmac() 完一定要decode()和 python 2 hmac不一样</span>\n        <span class=\"n\">signature</span> <span class=\"o\">=</span> <span class=\"n\">base64</span><span class=\"o\">.</span><span class=\"n\">b64encode</span><span class=\"p\">(</span><span class=\"n\">code</span><span class=\"p\">)</span><span class=\"o\">.</span><span class=\"n\">decode</span><span class=\"p\">()</span>\n        <span class=\"k\">return</span> <span class=\"n\">signature</span></div></div>\n        \n</pre></div>\n\n           </div>\n           \n          </div>\n          <footer>\n  \n\n  <hr/>\n\n  <div role=\"contentinfo\">\n    <p>\n        &copy; Copyright 2019, wzpan\n\n    </p>\n  </div>\n  Built with <a href=\"http://sphinx-doc.org/\">Sphinx</a> using a <a href=\"https://github.com/rtfd/sphinx_rtd_theme\">theme</a> provided by <a href=\"https://readthedocs.org\">Read the Docs</a>. \n\n</footer>\n\n        </div>\n      </div>\n\n    </section>\n\n  </div>\n  \n\n\n  <script type=\"text/javascript\">\n      jQuery(function () {\n          SphinxRtdTheme.Navigation.enable(true);\n      });\n  </script>\n\n  \n  \n    \n   \n\n</body>\n</html>"
  },
  {
    "path": "docs/_modules/robot/sdk/XunfeiSpeech.html",
    "content": "\n\n<!DOCTYPE html>\n<!--[if IE 8]><html class=\"no-js lt-ie9\" lang=\"zh-CN\" > <![endif]-->\n<!--[if gt IE 8]><!--> <html class=\"no-js\" lang=\"zh-CN\" > <!--<![endif]-->\n<head>\n  <meta charset=\"utf-8\">\n  \n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  \n  <title>robot.sdk.XunfeiSpeech &mdash; wukong-robot 1.2.0 文档</title>\n  \n\n  \n  \n  \n  \n\n  \n  <script type=\"text/javascript\" src=\"../../../_static/js/modernizr.min.js\"></script>\n  \n    \n      <script type=\"text/javascript\" id=\"documentation_options\" data-url_root=\"../../../\" src=\"../../../_static/documentation_options.js\"></script>\n        <script type=\"text/javascript\" src=\"../../../_static/jquery.js\"></script>\n        <script type=\"text/javascript\" src=\"../../../_static/underscore.js\"></script>\n        <script type=\"text/javascript\" src=\"../../../_static/doctools.js\"></script>\n        <script type=\"text/javascript\" src=\"../../../_static/language_data.js\"></script>\n        <script type=\"text/javascript\" src=\"../../../_static/translations.js\"></script>\n    \n    <script type=\"text/javascript\" src=\"../../../_static/js/theme.js\"></script>\n\n    \n\n  \n  <link rel=\"stylesheet\" href=\"../../../_static/css/theme.css\" type=\"text/css\" />\n  <link rel=\"stylesheet\" href=\"../../../_static/pygments.css\" type=\"text/css\" />\n    <link rel=\"index\" title=\"索引\" href=\"../../../genindex.html\" />\n    <link rel=\"search\" title=\"搜索\" href=\"../../../search.html\" /> \n</head>\n\n<body class=\"wy-body-for-nav\">\n\n   \n  <div class=\"wy-grid-for-nav\">\n    \n    <nav data-toggle=\"wy-nav-shift\" class=\"wy-nav-side\">\n      <div class=\"wy-side-scroll\">\n        <div class=\"wy-side-nav-search\" >\n          \n\n          \n            <a href=\"../../../index.html\" class=\"icon icon-home\"> wukong-robot\n          \n\n          \n          </a>\n\n          \n            \n            \n          \n\n          \n<div role=\"search\">\n  <form id=\"rtd-search-form\" class=\"wy-form\" action=\"../../../search.html\" method=\"get\">\n    <input type=\"text\" name=\"q\" placeholder=\"Search docs\" />\n    <input type=\"hidden\" name=\"check_keywords\" value=\"yes\" />\n    <input type=\"hidden\" name=\"area\" value=\"default\" />\n  </form>\n</div>\n\n          \n        </div>\n\n        <div class=\"wy-menu wy-menu-vertical\" data-spy=\"affix\" role=\"navigation\" aria-label=\"main navigation\">\n          \n            \n            \n              \n            \n            \n              <!-- Local TOC -->\n              <div class=\"local-toc\"></div>\n            \n          \n        </div>\n      </div>\n    </nav>\n\n    <section data-toggle=\"wy-nav-shift\" class=\"wy-nav-content-wrap\">\n\n      \n      <nav class=\"wy-nav-top\" aria-label=\"top navigation\">\n        \n          <i data-toggle=\"wy-nav-top\" class=\"fa fa-bars\"></i>\n          <a href=\"../../../index.html\">wukong-robot</a>\n        \n      </nav>\n\n\n      <div class=\"wy-nav-content\">\n        \n        <div class=\"rst-content\">\n        \n          \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<div role=\"navigation\" aria-label=\"breadcrumbs navigation\">\n\n  <ul class=\"wy-breadcrumbs\">\n    \n      <li><a href=\"../../../index.html\">Docs</a> &raquo;</li>\n        \n          <li><a href=\"../../index.html\">模块代码</a> &raquo;</li>\n        \n      <li>robot.sdk.XunfeiSpeech</li>\n    \n    \n      <li class=\"wy-breadcrumbs-aside\">\n        \n      </li>\n    \n  </ul>\n\n  \n  <hr/>\n</div>\n          <div role=\"main\" class=\"document\" itemscope=\"itemscope\" itemtype=\"http://schema.org/Article\">\n           <div itemprop=\"articleBody\">\n            \n  <h1>robot.sdk.XunfeiSpeech 源代码</h1><div class=\"highlight\"><pre>\n<span></span><span class=\"kn\">import</span> <span class=\"nn\">websocket</span>\n<span class=\"kn\">import</span> <span class=\"nn\">hashlib</span>\n<span class=\"kn\">import</span> <span class=\"nn\">base64</span>\n<span class=\"kn\">import</span> <span class=\"nn\">hmac</span>\n<span class=\"kn\">import</span> <span class=\"nn\">json</span>\n<span class=\"kn\">from</span> <span class=\"nn\">urllib.parse</span> <span class=\"k\">import</span> <span class=\"n\">urlencode</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">ssl</span>\n<span class=\"kn\">from</span> <span class=\"nn\">wsgiref.handlers</span> <span class=\"k\">import</span> <span class=\"n\">format_date_time</span>\n<span class=\"kn\">from</span> <span class=\"nn\">datetime</span> <span class=\"k\">import</span> <span class=\"n\">datetime</span>\n<span class=\"kn\">from</span> <span class=\"nn\">time</span> <span class=\"k\">import</span> <span class=\"n\">mktime</span>\n<span class=\"kn\">import</span> <span class=\"nn\">_thread</span> <span class=\"k\">as</span> <span class=\"nn\">thread</span>\n\n<span class=\"kn\">from</span> <span class=\"nn\">robot</span> <span class=\"k\">import</span> <span class=\"n\">logging</span>\n<span class=\"n\">logger</span> <span class=\"o\">=</span> <span class=\"n\">logging</span><span class=\"o\">.</span><span class=\"n\">getLogger</span><span class=\"p\">(</span><span class=\"vm\">__name__</span><span class=\"p\">)</span>\n\n<span class=\"n\">STATUS_FIRST_FRAME</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>  <span class=\"c1\"># 第一帧的标识</span>\n<span class=\"n\">STATUS_CONTINUE_FRAME</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>  <span class=\"c1\"># 中间帧标识</span>\n<span class=\"n\">STATUS_LAST_FRAME</span> <span class=\"o\">=</span> <span class=\"mi\">2</span>  <span class=\"c1\"># 最后一帧的标识</span>\n\n<span class=\"n\">wsParam</span> <span class=\"o\">=</span> <span class=\"kc\">None</span>\n<span class=\"n\">gResult</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;&#39;</span>\n\n<div class=\"viewcode-block\" id=\"Ws_Param\"><a class=\"viewcode-back\" href=\"../../../robot.sdk.html#robot.sdk.XunfeiSpeech.Ws_Param\">[文档]</a><span class=\"k\">class</span> <span class=\"nc\">Ws_Param</span><span class=\"p\">(</span><span class=\"nb\">object</span><span class=\"p\">):</span>\n    <span class=\"c1\"># 初始化</span>\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">APPID</span><span class=\"p\">,</span> <span class=\"n\">APIKey</span><span class=\"p\">,</span> <span class=\"n\">APISecret</span><span class=\"p\">,</span> <span class=\"n\">AudioFile</span><span class=\"p\">):</span>\n        <span class=\"c1\"># 控制台鉴权信息</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">APPID</span> <span class=\"o\">=</span> <span class=\"n\">APPID</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">APIKey</span> <span class=\"o\">=</span> <span class=\"n\">APIKey</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">APISecret</span> <span class=\"o\">=</span> <span class=\"n\">APISecret</span>\n\n        <span class=\"c1\"># 固定参数，可不用修改</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">Host</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;iat-api.xfyun.cn/v2/iat&quot;</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">HttpProto</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;HTTP/1.1&quot;</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">HttpMethod</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;GET&quot;</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">RequestUri</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;/v2/iat&quot;</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">Algorithm</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;hmac-sha256&quot;</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">url</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;wss://&quot;</span> <span class=\"o\">+</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">Host</span> <span class=\"o\">+</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">RequestUri</span>\n\n        <span class=\"c1\"># 设置测试音频文件</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">AudioFile</span> <span class=\"o\">=</span> <span class=\"n\">AudioFile</span>\n        <span class=\"c1\"># 公共参数(common)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">CommonArgs</span> <span class=\"o\">=</span> <span class=\"p\">{</span><span class=\"s2\">&quot;app_id&quot;</span><span class=\"p\">:</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">APPID</span><span class=\"p\">}</span>\n        <span class=\"c1\"># 业务参数(business)，更多个性化参数可在官网查看</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">BusinessArgs</span> <span class=\"o\">=</span> <span class=\"p\">{</span><span class=\"s2\">&quot;domain&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;iat&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;language&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;zh_cn&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;accent&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;mandarin&quot;</span><span class=\"p\">}</span>\n\n    <span class=\"c1\"># 生成url</span>\n<div class=\"viewcode-block\" id=\"Ws_Param.create_url\"><a class=\"viewcode-back\" href=\"../../../robot.sdk.html#robot.sdk.XunfeiSpeech.Ws_Param.create_url\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">create_url</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"n\">url</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;wss://ws-api.xfyun.cn/v2/iat&#39;</span>\n        <span class=\"c1\"># 生成RFC1123格式的时间戳</span>\n        <span class=\"n\">now</span> <span class=\"o\">=</span> <span class=\"n\">datetime</span><span class=\"o\">.</span><span class=\"n\">now</span><span class=\"p\">()</span>\n        <span class=\"n\">date</span> <span class=\"o\">=</span> <span class=\"n\">format_date_time</span><span class=\"p\">(</span><span class=\"n\">mktime</span><span class=\"p\">(</span><span class=\"n\">now</span><span class=\"o\">.</span><span class=\"n\">timetuple</span><span class=\"p\">()))</span>\n\n        <span class=\"c1\"># 拼接字符串</span>\n        <span class=\"n\">signature_origin</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;host: &quot;</span> <span class=\"o\">+</span> <span class=\"s2\">&quot;ws-api.xfyun.cn&quot;</span> <span class=\"o\">+</span> <span class=\"s2\">&quot;</span><span class=\"se\">\\n</span><span class=\"s2\">&quot;</span>\n        <span class=\"n\">signature_origin</span> <span class=\"o\">+=</span> <span class=\"s2\">&quot;date: &quot;</span> <span class=\"o\">+</span> <span class=\"n\">date</span> <span class=\"o\">+</span> <span class=\"s2\">&quot;</span><span class=\"se\">\\n</span><span class=\"s2\">&quot;</span>\n        <span class=\"n\">signature_origin</span> <span class=\"o\">+=</span> <span class=\"s2\">&quot;GET &quot;</span> <span class=\"o\">+</span> <span class=\"s2\">&quot;/v2/iat &quot;</span> <span class=\"o\">+</span> <span class=\"s2\">&quot;HTTP/1.1&quot;</span>\n        <span class=\"c1\"># 进行hmac-sha256进行加密</span>\n        <span class=\"n\">signature_sha</span> <span class=\"o\">=</span> <span class=\"n\">hmac</span><span class=\"o\">.</span><span class=\"n\">new</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">APISecret</span><span class=\"o\">.</span><span class=\"n\">encode</span><span class=\"p\">(</span><span class=\"s1\">&#39;utf-8&#39;</span><span class=\"p\">),</span> <span class=\"n\">signature_origin</span><span class=\"o\">.</span><span class=\"n\">encode</span><span class=\"p\">(</span><span class=\"s1\">&#39;utf-8&#39;</span><span class=\"p\">),</span>\n                                 <span class=\"n\">digestmod</span><span class=\"o\">=</span><span class=\"n\">hashlib</span><span class=\"o\">.</span><span class=\"n\">sha256</span><span class=\"p\">)</span><span class=\"o\">.</span><span class=\"n\">digest</span><span class=\"p\">()</span>\n        <span class=\"n\">signature_sha</span> <span class=\"o\">=</span> <span class=\"n\">base64</span><span class=\"o\">.</span><span class=\"n\">b64encode</span><span class=\"p\">(</span><span class=\"n\">signature_sha</span><span class=\"p\">)</span><span class=\"o\">.</span><span class=\"n\">decode</span><span class=\"p\">(</span><span class=\"n\">encoding</span><span class=\"o\">=</span><span class=\"s1\">&#39;utf-8&#39;</span><span class=\"p\">)</span>\n\n        <span class=\"n\">authorization_origin</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;api_key=</span><span class=\"se\">\\&quot;</span><span class=\"si\">%s</span><span class=\"se\">\\&quot;</span><span class=\"s2\">, algorithm=</span><span class=\"se\">\\&quot;</span><span class=\"si\">%s</span><span class=\"se\">\\&quot;</span><span class=\"s2\">, headers=</span><span class=\"se\">\\&quot;</span><span class=\"si\">%s</span><span class=\"se\">\\&quot;</span><span class=\"s2\">, signature=</span><span class=\"se\">\\&quot;</span><span class=\"si\">%s</span><span class=\"se\">\\&quot;</span><span class=\"s2\">&quot;</span> <span class=\"o\">%</span> <span class=\"p\">(</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">APIKey</span><span class=\"p\">,</span> <span class=\"s2\">&quot;hmac-sha256&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;host date request-line&quot;</span><span class=\"p\">,</span> <span class=\"n\">signature_sha</span><span class=\"p\">)</span>\n        <span class=\"n\">authorization</span> <span class=\"o\">=</span> <span class=\"n\">base64</span><span class=\"o\">.</span><span class=\"n\">b64encode</span><span class=\"p\">(</span><span class=\"n\">authorization_origin</span><span class=\"o\">.</span><span class=\"n\">encode</span><span class=\"p\">(</span><span class=\"s1\">&#39;utf-8&#39;</span><span class=\"p\">))</span><span class=\"o\">.</span><span class=\"n\">decode</span><span class=\"p\">(</span><span class=\"n\">encoding</span><span class=\"o\">=</span><span class=\"s1\">&#39;utf-8&#39;</span><span class=\"p\">)</span>\n        <span class=\"c1\"># 将请求的鉴权参数组合为字典</span>\n        <span class=\"n\">v</span> <span class=\"o\">=</span> <span class=\"p\">{</span>\n            <span class=\"s2\">&quot;authorization&quot;</span><span class=\"p\">:</span> <span class=\"n\">authorization</span><span class=\"p\">,</span>\n            <span class=\"s2\">&quot;date&quot;</span><span class=\"p\">:</span> <span class=\"n\">date</span><span class=\"p\">,</span>\n            <span class=\"s2\">&quot;host&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;ws-api.xfyun.cn&quot;</span>\n        <span class=\"p\">}</span>\n        <span class=\"c1\"># 拼接鉴权参数，生成url</span>\n        <span class=\"n\">url</span> <span class=\"o\">=</span> <span class=\"n\">url</span> <span class=\"o\">+</span> <span class=\"s1\">&#39;?&#39;</span> <span class=\"o\">+</span> <span class=\"n\">urlencode</span><span class=\"p\">(</span><span class=\"n\">v</span><span class=\"p\">)</span>\n        <span class=\"c1\"># 此处打印出建立连接时候的url,参考本demo的时候可取消上方打印的注释，比对相同参数时生成的url与自己代码生成的url是否一致</span>\n        <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">debug</span><span class=\"p\">(</span><span class=\"s1\">&#39;websocket url :&#39;</span><span class=\"p\">,</span> <span class=\"n\">url</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span> <span class=\"n\">url</span></div></div>\n\n\n<span class=\"c1\"># 收到websocket消息的处理</span>\n<div class=\"viewcode-block\" id=\"on_message\"><a class=\"viewcode-back\" href=\"../../../robot.sdk.html#robot.sdk.XunfeiSpeech.on_message\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">on_message</span><span class=\"p\">(</span><span class=\"n\">ws</span><span class=\"p\">,</span> <span class=\"n\">message</span><span class=\"p\">):</span>\n    <span class=\"k\">global</span> <span class=\"n\">gResult</span>\n    <span class=\"k\">try</span><span class=\"p\">:</span>\n        <span class=\"n\">code</span> <span class=\"o\">=</span> <span class=\"n\">json</span><span class=\"o\">.</span><span class=\"n\">loads</span><span class=\"p\">(</span><span class=\"n\">message</span><span class=\"p\">)[</span><span class=\"s2\">&quot;code&quot;</span><span class=\"p\">]</span>\n        <span class=\"n\">sid</span> <span class=\"o\">=</span> <span class=\"n\">json</span><span class=\"o\">.</span><span class=\"n\">loads</span><span class=\"p\">(</span><span class=\"n\">message</span><span class=\"p\">)[</span><span class=\"s2\">&quot;sid&quot;</span><span class=\"p\">]</span>\n        <span class=\"k\">if</span> <span class=\"n\">code</span> <span class=\"o\">!=</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"n\">errMsg</span> <span class=\"o\">=</span> <span class=\"n\">json</span><span class=\"o\">.</span><span class=\"n\">loads</span><span class=\"p\">(</span><span class=\"n\">message</span><span class=\"p\">)[</span><span class=\"s2\">&quot;message&quot;</span><span class=\"p\">]</span>\n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">critical</span><span class=\"p\">(</span><span class=\"s2\">&quot;xunfei-asr 识别出错了：sid:</span><span class=\"si\">%s</span><span class=\"s2\"> call error:</span><span class=\"si\">%s</span><span class=\"s2\"> code is:</span><span class=\"si\">%s</span><span class=\"s2\">&quot;</span> <span class=\"o\">%</span> <span class=\"p\">(</span><span class=\"n\">sid</span><span class=\"p\">,</span> <span class=\"n\">errMsg</span><span class=\"p\">,</span> <span class=\"n\">code</span><span class=\"p\">))</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"n\">data</span> <span class=\"o\">=</span> <span class=\"n\">json</span><span class=\"o\">.</span><span class=\"n\">loads</span><span class=\"p\">(</span><span class=\"n\">message</span><span class=\"p\">)[</span><span class=\"s2\">&quot;data&quot;</span><span class=\"p\">][</span><span class=\"s2\">&quot;result&quot;</span><span class=\"p\">][</span><span class=\"s2\">&quot;ws&quot;</span><span class=\"p\">]</span>\n            <span class=\"n\">result</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;&quot;</span>\n            <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"n\">data</span><span class=\"p\">:</span>\n                <span class=\"k\">for</span> <span class=\"n\">w</span> <span class=\"ow\">in</span> <span class=\"n\">i</span><span class=\"p\">[</span><span class=\"s2\">&quot;cw&quot;</span><span class=\"p\">]:</span>\n                    <span class=\"n\">result</span> <span class=\"o\">+=</span> <span class=\"n\">w</span><span class=\"p\">[</span><span class=\"s2\">&quot;w&quot;</span><span class=\"p\">]</span>\n            <span class=\"n\">gResult</span> <span class=\"o\">=</span> <span class=\"n\">gResult</span> <span class=\"o\">+</span> <span class=\"n\">result</span>\n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s2\">&quot;sid:</span><span class=\"si\">%s</span><span class=\"s2\"> call success!,data is:</span><span class=\"si\">%s</span><span class=\"s2\">&quot;</span> <span class=\"o\">%</span> <span class=\"p\">(</span><span class=\"n\">sid</span><span class=\"p\">,</span> <span class=\"n\">json</span><span class=\"o\">.</span><span class=\"n\">dumps</span><span class=\"p\">(</span><span class=\"n\">data</span><span class=\"p\">,</span> <span class=\"n\">ensure_ascii</span><span class=\"o\">=</span><span class=\"kc\">False</span><span class=\"p\">)))</span>\n    <span class=\"k\">except</span> <span class=\"ne\">Exception</span> <span class=\"k\">as</span> <span class=\"n\">e</span><span class=\"p\">:</span>\n        <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">critical</span><span class=\"p\">(</span><span class=\"s2\">&quot;xunfei-asr 识别出错了：&quot;</span><span class=\"p\">,</span> <span class=\"n\">e</span><span class=\"p\">)</span></div>\n\n\n<span class=\"c1\"># 收到websocket错误的处理</span>\n<div class=\"viewcode-block\" id=\"on_error\"><a class=\"viewcode-back\" href=\"../../../robot.sdk.html#robot.sdk.XunfeiSpeech.on_error\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">on_error</span><span class=\"p\">(</span><span class=\"n\">ws</span><span class=\"p\">,</span> <span class=\"n\">error</span><span class=\"p\">):</span>\n    <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">error</span><span class=\"p\">(</span><span class=\"s2\">&quot;### error:&quot;</span><span class=\"p\">,</span> <span class=\"n\">error</span><span class=\"p\">)</span></div>\n\n\n<span class=\"c1\"># 收到websocket关闭的处理</span>\n<div class=\"viewcode-block\" id=\"on_close\"><a class=\"viewcode-back\" href=\"../../../robot.sdk.html#robot.sdk.XunfeiSpeech.on_close\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">on_close</span><span class=\"p\">(</span><span class=\"n\">ws</span><span class=\"p\">):</span>\n    <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">debug</span><span class=\"p\">(</span><span class=\"s2\">&quot;### closed ###&quot;</span><span class=\"p\">)</span></div>\n\n\n<span class=\"c1\"># 收到websocket连接建立的处理</span>\n<div class=\"viewcode-block\" id=\"on_open\"><a class=\"viewcode-back\" href=\"../../../robot.sdk.html#robot.sdk.XunfeiSpeech.on_open\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">on_open</span><span class=\"p\">(</span><span class=\"n\">ws</span><span class=\"p\">):</span>\n    <span class=\"k\">global</span> <span class=\"n\">wsParam</span>\n    <span class=\"k\">def</span> <span class=\"nf\">run</span><span class=\"p\">(</span><span class=\"o\">*</span><span class=\"n\">args</span><span class=\"p\">):</span>\n        <span class=\"n\">frameSize</span> <span class=\"o\">=</span> <span class=\"mi\">1220</span>  <span class=\"c1\"># 每一帧的音频大小</span>\n        <span class=\"n\">intervel</span> <span class=\"o\">=</span> <span class=\"mf\">0.04</span>  <span class=\"c1\"># 发送音频间隔(单位:s)</span>\n        <span class=\"n\">status</span> <span class=\"o\">=</span> <span class=\"n\">STATUS_FIRST_FRAME</span>  <span class=\"c1\"># 音频的状态信息，标识音频是第一帧，还是中间帧、最后一帧</span>\n        <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">wsParam</span><span class=\"o\">.</span><span class=\"n\">AudioFile</span><span class=\"p\">,</span> <span class=\"s2\">&quot;rb&quot;</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">fp</span><span class=\"p\">:</span>\n            <span class=\"k\">while</span> <span class=\"kc\">True</span><span class=\"p\">:</span>\n                <span class=\"n\">buf</span> <span class=\"o\">=</span> <span class=\"n\">fp</span><span class=\"o\">.</span><span class=\"n\">read</span><span class=\"p\">(</span><span class=\"n\">frameSize</span><span class=\"p\">)</span>\n                <span class=\"c1\"># 文件结束</span>\n                <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">buf</span><span class=\"p\">:</span>\n                    <span class=\"n\">status</span> <span class=\"o\">=</span> <span class=\"n\">STATUS_LAST_FRAME</span>\n                <span class=\"c1\"># 第一帧处理</span>\n                <span class=\"c1\"># 发送第一帧音频，带business 参数</span>\n                <span class=\"c1\"># appid 必须带上，只需第一帧发送</span>\n                <span class=\"k\">if</span> <span class=\"n\">status</span> <span class=\"o\">==</span> <span class=\"n\">STATUS_FIRST_FRAME</span><span class=\"p\">:</span>\n\n                    <span class=\"n\">d</span> <span class=\"o\">=</span> <span class=\"p\">{</span><span class=\"s2\">&quot;common&quot;</span><span class=\"p\">:</span> <span class=\"n\">wsParam</span><span class=\"o\">.</span><span class=\"n\">CommonArgs</span><span class=\"p\">,</span>\n                         <span class=\"s2\">&quot;business&quot;</span><span class=\"p\">:</span> <span class=\"n\">wsParam</span><span class=\"o\">.</span><span class=\"n\">BusinessArgs</span><span class=\"p\">,</span>\n                         <span class=\"s2\">&quot;data&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;status&quot;</span><span class=\"p\">:</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"s2\">&quot;format&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;audio/L16;rate=16000&quot;</span><span class=\"p\">,</span>\n                                  <span class=\"s2\">&quot;audio&quot;</span><span class=\"p\">:</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">base64</span><span class=\"o\">.</span><span class=\"n\">b64encode</span><span class=\"p\">(</span><span class=\"n\">buf</span><span class=\"p\">),</span> <span class=\"s1\">&#39;utf-8&#39;</span><span class=\"p\">),</span>\n                                  <span class=\"s2\">&quot;encoding&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;raw&quot;</span><span class=\"p\">}}</span>\n                    <span class=\"n\">d</span> <span class=\"o\">=</span> <span class=\"n\">json</span><span class=\"o\">.</span><span class=\"n\">dumps</span><span class=\"p\">(</span><span class=\"n\">d</span><span class=\"p\">)</span>\n                    <span class=\"n\">ws</span><span class=\"o\">.</span><span class=\"n\">send</span><span class=\"p\">(</span><span class=\"n\">d</span><span class=\"p\">)</span>\n                    <span class=\"n\">status</span> <span class=\"o\">=</span> <span class=\"n\">STATUS_CONTINUE_FRAME</span>\n                <span class=\"c1\"># 中间帧处理</span>\n                <span class=\"k\">elif</span> <span class=\"n\">status</span> <span class=\"o\">==</span> <span class=\"n\">STATUS_CONTINUE_FRAME</span><span class=\"p\">:</span>\n                    <span class=\"n\">d</span> <span class=\"o\">=</span> <span class=\"p\">{</span><span class=\"s2\">&quot;data&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;status&quot;</span><span class=\"p\">:</span> <span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"s2\">&quot;format&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;audio/L16;rate=16000&quot;</span><span class=\"p\">,</span>\n                                  <span class=\"s2\">&quot;audio&quot;</span><span class=\"p\">:</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">base64</span><span class=\"o\">.</span><span class=\"n\">b64encode</span><span class=\"p\">(</span><span class=\"n\">buf</span><span class=\"p\">),</span> <span class=\"s1\">&#39;utf-8&#39;</span><span class=\"p\">),</span>\n                                  <span class=\"s2\">&quot;encoding&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;raw&quot;</span><span class=\"p\">}}</span>\n                    <span class=\"n\">ws</span><span class=\"o\">.</span><span class=\"n\">send</span><span class=\"p\">(</span><span class=\"n\">json</span><span class=\"o\">.</span><span class=\"n\">dumps</span><span class=\"p\">(</span><span class=\"n\">d</span><span class=\"p\">))</span>\n                <span class=\"c1\"># 最后一帧处理</span>\n                <span class=\"k\">elif</span> <span class=\"n\">status</span> <span class=\"o\">==</span> <span class=\"n\">STATUS_LAST_FRAME</span><span class=\"p\">:</span>\n                    <span class=\"n\">d</span> <span class=\"o\">=</span> <span class=\"p\">{</span><span class=\"s2\">&quot;data&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;status&quot;</span><span class=\"p\">:</span> <span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"s2\">&quot;format&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;audio/L16;rate=16000&quot;</span><span class=\"p\">,</span>\n                                  <span class=\"s2\">&quot;audio&quot;</span><span class=\"p\">:</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">base64</span><span class=\"o\">.</span><span class=\"n\">b64encode</span><span class=\"p\">(</span><span class=\"n\">buf</span><span class=\"p\">),</span> <span class=\"s1\">&#39;utf-8&#39;</span><span class=\"p\">),</span>\n                                  <span class=\"s2\">&quot;encoding&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;raw&quot;</span><span class=\"p\">}}</span>\n                    <span class=\"n\">ws</span><span class=\"o\">.</span><span class=\"n\">send</span><span class=\"p\">(</span><span class=\"n\">json</span><span class=\"o\">.</span><span class=\"n\">dumps</span><span class=\"p\">(</span><span class=\"n\">d</span><span class=\"p\">))</span>\n                    <span class=\"n\">time</span><span class=\"o\">.</span><span class=\"n\">sleep</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n                    <span class=\"k\">break</span>\n                <span class=\"c1\"># 模拟音频采样间隔</span>\n                <span class=\"n\">time</span><span class=\"o\">.</span><span class=\"n\">sleep</span><span class=\"p\">(</span><span class=\"n\">intervel</span><span class=\"p\">)</span>\n        <span class=\"n\">ws</span><span class=\"o\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n\n    <span class=\"n\">thread</span><span class=\"o\">.</span><span class=\"n\">start_new_thread</span><span class=\"p\">(</span><span class=\"n\">run</span><span class=\"p\">,</span> <span class=\"p\">())</span></div>\n\n\n<div class=\"viewcode-block\" id=\"transcribe\"><a class=\"viewcode-back\" href=\"../../../robot.sdk.html#robot.sdk.XunfeiSpeech.transcribe\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">transcribe</span><span class=\"p\">(</span><span class=\"n\">fpath</span><span class=\"p\">,</span> <span class=\"n\">appid</span><span class=\"p\">,</span> <span class=\"n\">api_key</span><span class=\"p\">,</span> <span class=\"n\">api_secret</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    科大讯飞ASR</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"k\">global</span> <span class=\"n\">wsParam</span><span class=\"p\">,</span> <span class=\"n\">gResult</span>\n    <span class=\"n\">gResult</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;&#39;</span>\n    <span class=\"n\">wsParam</span> <span class=\"o\">=</span> <span class=\"n\">Ws_Param</span><span class=\"p\">(</span><span class=\"n\">appid</span><span class=\"p\">,</span> <span class=\"n\">api_key</span><span class=\"p\">,</span> <span class=\"n\">APISecret</span><span class=\"o\">=</span><span class=\"n\">api_secret</span><span class=\"p\">,</span> <span class=\"n\">AudioFile</span><span class=\"o\">=</span><span class=\"n\">fpath</span><span class=\"p\">)</span>\n    <span class=\"n\">websocket</span><span class=\"o\">.</span><span class=\"n\">enableTrace</span><span class=\"p\">(</span><span class=\"kc\">False</span><span class=\"p\">)</span>\n    <span class=\"n\">wsUrl</span> <span class=\"o\">=</span> <span class=\"n\">wsParam</span><span class=\"o\">.</span><span class=\"n\">create_url</span><span class=\"p\">()</span>\n    <span class=\"n\">ws</span> <span class=\"o\">=</span> <span class=\"n\">websocket</span><span class=\"o\">.</span><span class=\"n\">WebSocketApp</span><span class=\"p\">(</span><span class=\"n\">wsUrl</span><span class=\"p\">,</span> <span class=\"n\">on_message</span><span class=\"o\">=</span><span class=\"n\">on_message</span><span class=\"p\">,</span> <span class=\"n\">on_error</span><span class=\"o\">=</span><span class=\"n\">on_error</span><span class=\"p\">,</span> <span class=\"n\">on_close</span><span class=\"o\">=</span><span class=\"n\">on_close</span><span class=\"p\">)</span>\n    <span class=\"n\">ws</span><span class=\"o\">.</span><span class=\"n\">on_open</span> <span class=\"o\">=</span> <span class=\"n\">on_open</span>\n    <span class=\"n\">ws</span><span class=\"o\">.</span><span class=\"n\">run_forever</span><span class=\"p\">(</span><span class=\"n\">sslopt</span><span class=\"o\">=</span><span class=\"p\">{</span><span class=\"s2\">&quot;cert_reqs&quot;</span><span class=\"p\">:</span> <span class=\"n\">ssl</span><span class=\"o\">.</span><span class=\"n\">CERT_NONE</span><span class=\"p\">})</span>\n    <span class=\"k\">return</span> <span class=\"n\">gResult</span></div>\n</pre></div>\n\n           </div>\n           \n          </div>\n          <footer>\n  \n\n  <hr/>\n\n  <div role=\"contentinfo\">\n    <p>\n        &copy; Copyright 2019, wzpan\n\n    </p>\n  </div>\n  Built with <a href=\"http://sphinx-doc.org/\">Sphinx</a> using a <a href=\"https://github.com/rtfd/sphinx_rtd_theme\">theme</a> provided by <a href=\"https://readthedocs.org\">Read the Docs</a>. \n\n</footer>\n\n        </div>\n      </div>\n\n    </section>\n\n  </div>\n  \n\n\n  <script type=\"text/javascript\">\n      jQuery(function () {\n          SphinxRtdTheme.Navigation.enable(true);\n      });\n  </script>\n\n  \n  \n    \n   \n\n</body>\n</html>"
  },
  {
    "path": "docs/_modules/robot/sdk/unit.html",
    "content": "\n\n<!DOCTYPE html>\n<!--[if IE 8]><html class=\"no-js lt-ie9\" lang=\"zh-CN\" > <![endif]-->\n<!--[if gt IE 8]><!--> <html class=\"no-js\" lang=\"zh-CN\" > <!--<![endif]-->\n<head>\n  <meta charset=\"utf-8\">\n  \n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  \n  <title>robot.sdk.unit &mdash; wukong-robot 1.2.0 文档</title>\n  \n\n  \n  \n  \n  \n\n  \n  <script type=\"text/javascript\" src=\"../../../_static/js/modernizr.min.js\"></script>\n  \n    \n      <script type=\"text/javascript\" id=\"documentation_options\" data-url_root=\"../../../\" src=\"../../../_static/documentation_options.js\"></script>\n        <script type=\"text/javascript\" src=\"../../../_static/jquery.js\"></script>\n        <script type=\"text/javascript\" src=\"../../../_static/underscore.js\"></script>\n        <script type=\"text/javascript\" src=\"../../../_static/doctools.js\"></script>\n        <script type=\"text/javascript\" src=\"../../../_static/language_data.js\"></script>\n        <script type=\"text/javascript\" src=\"../../../_static/translations.js\"></script>\n    \n    <script type=\"text/javascript\" src=\"../../../_static/js/theme.js\"></script>\n\n    \n\n  \n  <link rel=\"stylesheet\" href=\"../../../_static/css/theme.css\" type=\"text/css\" />\n  <link rel=\"stylesheet\" href=\"../../../_static/pygments.css\" type=\"text/css\" />\n    <link rel=\"index\" title=\"索引\" href=\"../../../genindex.html\" />\n    <link rel=\"search\" title=\"搜索\" href=\"../../../search.html\" /> \n</head>\n\n<body class=\"wy-body-for-nav\">\n\n   \n  <div class=\"wy-grid-for-nav\">\n    \n    <nav data-toggle=\"wy-nav-shift\" class=\"wy-nav-side\">\n      <div class=\"wy-side-scroll\">\n        <div class=\"wy-side-nav-search\" >\n          \n\n          \n            <a href=\"../../../index.html\" class=\"icon icon-home\"> wukong-robot\n          \n\n          \n          </a>\n\n          \n            \n            \n          \n\n          \n<div role=\"search\">\n  <form id=\"rtd-search-form\" class=\"wy-form\" action=\"../../../search.html\" method=\"get\">\n    <input type=\"text\" name=\"q\" placeholder=\"Search docs\" />\n    <input type=\"hidden\" name=\"check_keywords\" value=\"yes\" />\n    <input type=\"hidden\" name=\"area\" value=\"default\" />\n  </form>\n</div>\n\n          \n        </div>\n\n        <div class=\"wy-menu wy-menu-vertical\" data-spy=\"affix\" role=\"navigation\" aria-label=\"main navigation\">\n          \n            \n            \n              \n            \n            \n              <!-- Local TOC -->\n              <div class=\"local-toc\"></div>\n            \n          \n        </div>\n      </div>\n    </nav>\n\n    <section data-toggle=\"wy-nav-shift\" class=\"wy-nav-content-wrap\">\n\n      \n      <nav class=\"wy-nav-top\" aria-label=\"top navigation\">\n        \n          <i data-toggle=\"wy-nav-top\" class=\"fa fa-bars\"></i>\n          <a href=\"../../../index.html\">wukong-robot</a>\n        \n      </nav>\n\n\n      <div class=\"wy-nav-content\">\n        \n        <div class=\"rst-content\">\n        \n          \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<div role=\"navigation\" aria-label=\"breadcrumbs navigation\">\n\n  <ul class=\"wy-breadcrumbs\">\n    \n      <li><a href=\"../../../index.html\">Docs</a> &raquo;</li>\n        \n          <li><a href=\"../../index.html\">模块代码</a> &raquo;</li>\n        \n      <li>robot.sdk.unit</li>\n    \n    \n      <li class=\"wy-breadcrumbs-aside\">\n        \n      </li>\n    \n  </ul>\n\n  \n  <hr/>\n</div>\n          <div role=\"main\" class=\"document\" itemscope=\"itemscope\" itemtype=\"http://schema.org/Article\">\n           <div itemprop=\"articleBody\">\n            \n  <h1>robot.sdk.unit 源代码</h1><div class=\"highlight\"><pre>\n<span></span><span class=\"c1\"># encoding:utf-8</span>\n<span class=\"kn\">import</span> <span class=\"nn\">requests</span>\n<span class=\"kn\">import</span> <span class=\"nn\">datetime</span>\n<span class=\"kn\">import</span> <span class=\"nn\">uuid</span>\n<span class=\"kn\">import</span> <span class=\"nn\">json</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">from</span> <span class=\"nn\">dateutil</span> <span class=\"k\">import</span> <span class=\"n\">parser</span> <span class=\"k\">as</span> <span class=\"n\">dparser</span>\n<span class=\"kn\">from</span> <span class=\"nn\">robot</span> <span class=\"k\">import</span> <span class=\"n\">constants</span><span class=\"p\">,</span> <span class=\"n\">logging</span>\n\n<span class=\"n\">logger</span> <span class=\"o\">=</span> <span class=\"n\">logging</span><span class=\"o\">.</span><span class=\"n\">getLogger</span><span class=\"p\">(</span><span class=\"vm\">__name__</span><span class=\"p\">)</span>\n\n<div class=\"viewcode-block\" id=\"get_token\"><a class=\"viewcode-back\" href=\"../../../robot.sdk.html#robot.sdk.unit.get_token\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">get_token</span><span class=\"p\">(</span><span class=\"n\">api_key</span><span class=\"p\">,</span> <span class=\"n\">secret_key</span><span class=\"p\">):</span>\n    <span class=\"n\">cache</span> <span class=\"o\">=</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">constants</span><span class=\"o\">.</span><span class=\"n\">TEMP_PATH</span><span class=\"p\">,</span> <span class=\"s1\">&#39;baidustt.ini&#39;</span><span class=\"p\">),</span> <span class=\"s1\">&#39;a+&#39;</span><span class=\"p\">)</span>\n    <span class=\"k\">try</span><span class=\"p\">:</span>\n        <span class=\"n\">pms</span> <span class=\"o\">=</span> <span class=\"n\">cache</span><span class=\"o\">.</span><span class=\"n\">readlines</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">pms</span><span class=\"p\">)</span> <span class=\"o\">&gt;</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"n\">time</span> <span class=\"o\">=</span> <span class=\"n\">pms</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n            <span class=\"n\">tk</span> <span class=\"o\">=</span> <span class=\"n\">pms</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n            <span class=\"c1\"># 计算token是否过期 官方说明一个月，这里保守29天</span>\n            <span class=\"n\">time</span> <span class=\"o\">=</span> <span class=\"n\">dparser</span><span class=\"o\">.</span><span class=\"n\">parse</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"p\">)</span>\n            <span class=\"n\">endtime</span> <span class=\"o\">=</span> <span class=\"n\">datetime</span><span class=\"o\">.</span><span class=\"n\">datetime</span><span class=\"o\">.</span><span class=\"n\">now</span><span class=\"p\">()</span>\n            <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">endtime</span> <span class=\"o\">-</span> <span class=\"n\">time</span><span class=\"p\">)</span><span class=\"o\">.</span><span class=\"n\">days</span> <span class=\"o\">&lt;=</span> <span class=\"mi\">29</span><span class=\"p\">:</span>\n                <span class=\"k\">return</span> <span class=\"n\">tk</span>\n    <span class=\"k\">finally</span><span class=\"p\">:</span>\n        <span class=\"n\">cache</span><span class=\"o\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n    <span class=\"n\">URL</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;http://openapi.baidu.com/oauth/2.0/token&#39;</span>\n    <span class=\"n\">params</span> <span class=\"o\">=</span> <span class=\"p\">{</span><span class=\"s1\">&#39;grant_type&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;client_credentials&#39;</span><span class=\"p\">,</span>\n              <span class=\"s1\">&#39;client_id&#39;</span><span class=\"p\">:</span> <span class=\"n\">api_key</span><span class=\"p\">,</span>\n              <span class=\"s1\">&#39;client_secret&#39;</span><span class=\"p\">:</span> <span class=\"n\">secret_key</span><span class=\"p\">}</span>\n    <span class=\"n\">r</span> <span class=\"o\">=</span> <span class=\"n\">requests</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">URL</span><span class=\"p\">,</span> <span class=\"n\">params</span><span class=\"o\">=</span><span class=\"n\">params</span><span class=\"p\">)</span>\n    <span class=\"k\">try</span><span class=\"p\">:</span>\n        <span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">raise_for_status</span><span class=\"p\">()</span>\n        <span class=\"n\">token</span> <span class=\"o\">=</span> <span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">json</span><span class=\"p\">()[</span><span class=\"s1\">&#39;access_token&#39;</span><span class=\"p\">]</span>\n        <span class=\"k\">return</span> <span class=\"n\">token</span>\n    <span class=\"k\">except</span> <span class=\"n\">requests</span><span class=\"o\">.</span><span class=\"n\">exceptions</span><span class=\"o\">.</span><span class=\"n\">HTTPError</span><span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"s1\">&#39;&#39;</span></div>\n\n<div class=\"viewcode-block\" id=\"getUnit\"><a class=\"viewcode-back\" href=\"../../../robot.sdk.html#robot.sdk.unit.getUnit\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">getUnit</span><span class=\"p\">(</span><span class=\"n\">query</span><span class=\"p\">,</span> <span class=\"n\">service_id</span><span class=\"p\">,</span> <span class=\"n\">api_key</span><span class=\"p\">,</span> <span class=\"n\">secret_key</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot; </span>\n<span class=\"sd\">    NLU 解析</span>\n\n<span class=\"sd\">    :param query: 用户的指令字符串</span>\n<span class=\"sd\">    :param service_id: UNIT 的 service_id</span>\n<span class=\"sd\">    :param api_key: UNIT apk_key</span>\n<span class=\"sd\">    :param secret_key: UNIT secret_key</span>\n<span class=\"sd\">    :returns: UNIT 解析结果。如果解析失败，返回 None</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"n\">access_token</span> <span class=\"o\">=</span> <span class=\"n\">get_token</span><span class=\"p\">(</span><span class=\"n\">api_key</span><span class=\"p\">,</span> <span class=\"n\">secret_key</span><span class=\"p\">)</span>\n    <span class=\"n\">url</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;https://aip.baidubce.com/rpc/2.0/unit/service/chat?access_token=&#39;</span> <span class=\"o\">+</span> <span class=\"n\">access_token</span>\n    <span class=\"n\">request</span><span class=\"o\">=</span><span class=\"p\">{</span>\n        <span class=\"s2\">&quot;query&quot;</span><span class=\"p\">:</span><span class=\"n\">query</span><span class=\"p\">,</span>\n        <span class=\"s2\">&quot;user_id&quot;</span><span class=\"p\">:</span><span class=\"s2\">&quot;888888&quot;</span><span class=\"p\">,</span>\n    <span class=\"p\">}</span>\n    <span class=\"n\">body</span><span class=\"o\">=</span><span class=\"p\">{</span>\n        <span class=\"s2\">&quot;log_id&quot;</span><span class=\"p\">:</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">uuid</span><span class=\"o\">.</span><span class=\"n\">uuid1</span><span class=\"p\">()),</span>\n        <span class=\"s2\">&quot;version&quot;</span><span class=\"p\">:</span><span class=\"s2\">&quot;2.0&quot;</span><span class=\"p\">,</span>\n        <span class=\"s2\">&quot;service_id&quot;</span><span class=\"p\">:</span> <span class=\"n\">service_id</span><span class=\"p\">,</span>\n        <span class=\"s2\">&quot;session_id&quot;</span><span class=\"p\">:</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">uuid</span><span class=\"o\">.</span><span class=\"n\">uuid1</span><span class=\"p\">()),</span>\n        <span class=\"s2\">&quot;request&quot;</span><span class=\"p\">:</span><span class=\"n\">request</span>\n    <span class=\"p\">}</span>\n    <span class=\"k\">try</span><span class=\"p\">:</span>\n        <span class=\"n\">headers</span> <span class=\"o\">=</span> <span class=\"p\">{</span><span class=\"s1\">&#39;Content-Type&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;application/json&#39;</span><span class=\"p\">}</span>\n        <span class=\"n\">request</span> <span class=\"o\">=</span> <span class=\"n\">requests</span><span class=\"o\">.</span><span class=\"n\">post</span><span class=\"p\">(</span><span class=\"n\">url</span><span class=\"p\">,</span> <span class=\"n\">json</span><span class=\"o\">=</span><span class=\"n\">body</span><span class=\"p\">,</span> <span class=\"n\">headers</span><span class=\"o\">=</span><span class=\"n\">headers</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span> <span class=\"n\">json</span><span class=\"o\">.</span><span class=\"n\">loads</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"o\">.</span><span class=\"n\">text</span><span class=\"p\">)</span>\n    <span class=\"k\">except</span> <span class=\"ne\">Exception</span><span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"kc\">None</span></div>\n\n\n<div class=\"viewcode-block\" id=\"getIntent\"><a class=\"viewcode-back\" href=\"../../../robot.sdk.html#robot.sdk.unit.getIntent\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">getIntent</span><span class=\"p\">(</span><span class=\"n\">parsed</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot; </span>\n<span class=\"sd\">    提取意图</span>\n\n<span class=\"sd\">    :param parsed: UNIT 解析结果</span>\n<span class=\"sd\">    :returns: 意图数组</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"k\">if</span> <span class=\"n\">parsed</span> <span class=\"ow\">is</span> <span class=\"ow\">not</span> <span class=\"kc\">None</span> <span class=\"ow\">and</span> <span class=\"s1\">&#39;result&#39;</span> <span class=\"ow\">in</span> <span class=\"n\">parsed</span> <span class=\"ow\">and</span> \\\n       <span class=\"s1\">&#39;response_list&#39;</span> <span class=\"ow\">in</span> <span class=\"n\">parsed</span><span class=\"p\">[</span><span class=\"s1\">&#39;result&#39;</span><span class=\"p\">]:</span>\n        <span class=\"k\">return</span> <span class=\"n\">parsed</span><span class=\"p\">[</span><span class=\"s1\">&#39;result&#39;</span><span class=\"p\">][</span><span class=\"s1\">&#39;response_list&#39;</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">][</span><span class=\"s1\">&#39;schema&#39;</span><span class=\"p\">][</span><span class=\"s1\">&#39;intent&#39;</span><span class=\"p\">]</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"s1\">&#39;&#39;</span></div>\n\n\n<div class=\"viewcode-block\" id=\"hasIntent\"><a class=\"viewcode-back\" href=\"../../../robot.sdk.html#robot.sdk.unit.hasIntent\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">hasIntent</span><span class=\"p\">(</span><span class=\"n\">parsed</span><span class=\"p\">,</span> <span class=\"n\">intent</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot; </span>\n<span class=\"sd\">    判断是否包含某个意图</span>\n\n<span class=\"sd\">    :param parsed: UNIT 解析结果</span>\n<span class=\"sd\">    :param intent: 意图的名称</span>\n<span class=\"sd\">    :returns: True: 包含; False: 不包含</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"k\">if</span> <span class=\"n\">parsed</span> <span class=\"ow\">is</span> <span class=\"ow\">not</span> <span class=\"kc\">None</span> <span class=\"ow\">and</span> <span class=\"s1\">&#39;result&#39;</span> <span class=\"ow\">in</span> <span class=\"n\">parsed</span> <span class=\"ow\">and</span> \\\n       <span class=\"s1\">&#39;response_list&#39;</span> <span class=\"ow\">in</span> <span class=\"n\">parsed</span><span class=\"p\">[</span><span class=\"s1\">&#39;result&#39;</span><span class=\"p\">]:</span>\n        <span class=\"n\">response_list</span> <span class=\"o\">=</span> <span class=\"n\">parsed</span><span class=\"p\">[</span><span class=\"s1\">&#39;result&#39;</span><span class=\"p\">][</span><span class=\"s1\">&#39;response_list&#39;</span><span class=\"p\">]</span>\n        <span class=\"k\">for</span> <span class=\"n\">response</span> <span class=\"ow\">in</span> <span class=\"n\">response_list</span><span class=\"p\">:</span>\n            <span class=\"k\">if</span> <span class=\"n\">response</span><span class=\"p\">[</span><span class=\"s1\">&#39;schema&#39;</span><span class=\"p\">][</span><span class=\"s1\">&#39;intent&#39;</span><span class=\"p\">]</span> <span class=\"o\">==</span> <span class=\"n\">intent</span><span class=\"p\">:</span>\n                <span class=\"k\">return</span> <span class=\"kc\">True</span>\n        <span class=\"k\">return</span> <span class=\"kc\">False</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"kc\">False</span></div>\n\n\n<div class=\"viewcode-block\" id=\"getSlots\"><a class=\"viewcode-back\" href=\"../../../robot.sdk.html#robot.sdk.unit.getSlots\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">getSlots</span><span class=\"p\">(</span><span class=\"n\">parsed</span><span class=\"p\">,</span> <span class=\"n\">intent</span><span class=\"o\">=</span><span class=\"s1\">&#39;&#39;</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot; </span>\n<span class=\"sd\">    提取某个意图的所有词槽</span>\n<span class=\"sd\">    </span>\n<span class=\"sd\">    :param parsed: UNIT 解析结果</span>\n<span class=\"sd\">    :param intent: 意图的名称</span>\n<span class=\"sd\">    :returns: 词槽列表。你可以通过 name 属性筛选词槽，</span>\n<span class=\"sd\">再通过 normalized_word 属性取出相应的值</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"k\">if</span> <span class=\"n\">parsed</span> <span class=\"ow\">is</span> <span class=\"ow\">not</span> <span class=\"kc\">None</span> <span class=\"ow\">and</span> <span class=\"s1\">&#39;result&#39;</span> <span class=\"ow\">in</span> <span class=\"n\">parsed</span> <span class=\"ow\">and</span> \\\n       <span class=\"s1\">&#39;response_list&#39;</span> <span class=\"ow\">in</span> <span class=\"n\">parsed</span><span class=\"p\">[</span><span class=\"s1\">&#39;result&#39;</span><span class=\"p\">]:</span>\n        <span class=\"n\">response_list</span> <span class=\"o\">=</span> <span class=\"n\">parsed</span><span class=\"p\">[</span><span class=\"s1\">&#39;result&#39;</span><span class=\"p\">][</span><span class=\"s1\">&#39;response_list&#39;</span><span class=\"p\">]</span>\n        <span class=\"k\">if</span> <span class=\"n\">intent</span> <span class=\"o\">==</span> <span class=\"s1\">&#39;&#39;</span><span class=\"p\">:</span>\n            <span class=\"k\">return</span> <span class=\"n\">parsed</span><span class=\"p\">[</span><span class=\"s1\">&#39;result&#39;</span><span class=\"p\">][</span><span class=\"s1\">&#39;response_list&#39;</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">][</span><span class=\"s1\">&#39;schema&#39;</span><span class=\"p\">][</span><span class=\"s1\">&#39;slots&#39;</span><span class=\"p\">]</span>\n        <span class=\"k\">for</span> <span class=\"n\">response</span> <span class=\"ow\">in</span> <span class=\"n\">response_list</span><span class=\"p\">:</span>\n            <span class=\"k\">if</span> <span class=\"n\">response</span><span class=\"p\">[</span><span class=\"s1\">&#39;schema&#39;</span><span class=\"p\">][</span><span class=\"s1\">&#39;intent&#39;</span><span class=\"p\">]</span> <span class=\"o\">==</span> <span class=\"n\">intent</span><span class=\"p\">:</span>\n                <span class=\"k\">return</span> <span class=\"n\">response</span><span class=\"p\">[</span><span class=\"s1\">&#39;schema&#39;</span><span class=\"p\">][</span><span class=\"s1\">&#39;slots&#39;</span><span class=\"p\">]</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"p\">[]</span></div>\n\n<div class=\"viewcode-block\" id=\"getSlotWords\"><a class=\"viewcode-back\" href=\"../../../robot.sdk.html#robot.sdk.unit.getSlotWords\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">getSlotWords</span><span class=\"p\">(</span><span class=\"n\">parsed</span><span class=\"p\">,</span> <span class=\"n\">intent</span><span class=\"p\">,</span> <span class=\"n\">name</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot; </span>\n<span class=\"sd\">    找出命中某个词槽的内容</span>\n<span class=\"sd\">    </span>\n<span class=\"sd\">    :param parsed: UNIT 解析结果</span>\n<span class=\"sd\">    :param intent: 意图的名称</span>\n<span class=\"sd\">    :param name: 词槽名</span>\n<span class=\"sd\">    :returns: 命中该词槽的值的列表。</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"n\">slots</span> <span class=\"o\">=</span> <span class=\"n\">getSlots</span><span class=\"p\">(</span><span class=\"n\">parsed</span><span class=\"p\">,</span> <span class=\"n\">intent</span><span class=\"p\">)</span>\n    <span class=\"n\">words</span> <span class=\"o\">=</span> <span class=\"p\">[]</span>\n    <span class=\"k\">for</span> <span class=\"n\">slot</span> <span class=\"ow\">in</span> <span class=\"n\">slots</span><span class=\"p\">:</span>\n        <span class=\"k\">if</span> <span class=\"n\">slot</span><span class=\"p\">[</span><span class=\"s1\">&#39;name&#39;</span><span class=\"p\">]</span> <span class=\"o\">==</span> <span class=\"n\">name</span><span class=\"p\">:</span>\n            <span class=\"n\">words</span><span class=\"o\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">slot</span><span class=\"p\">[</span><span class=\"s1\">&#39;normalized_word&#39;</span><span class=\"p\">])</span>\n    <span class=\"k\">return</span> <span class=\"n\">words</span></div>\n\n<div class=\"viewcode-block\" id=\"getSay\"><a class=\"viewcode-back\" href=\"../../../robot.sdk.html#robot.sdk.unit.getSay\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">getSay</span><span class=\"p\">(</span><span class=\"n\">parsed</span><span class=\"p\">,</span> <span class=\"n\">intent</span><span class=\"o\">=</span><span class=\"s1\">&#39;&#39;</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    提取 UNIT 的回复文本</span>\n\n<span class=\"sd\">    :param parsed: UNIT 解析结果</span>\n<span class=\"sd\">    :param intent: 意图的名称</span>\n<span class=\"sd\">    :returns: UNIT 的回复文本</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"k\">if</span> <span class=\"n\">parsed</span> <span class=\"ow\">is</span> <span class=\"ow\">not</span> <span class=\"kc\">None</span> <span class=\"ow\">and</span> <span class=\"s1\">&#39;result&#39;</span> <span class=\"ow\">in</span> <span class=\"n\">parsed</span> <span class=\"ow\">and</span> \\\n       <span class=\"s1\">&#39;response_list&#39;</span> <span class=\"ow\">in</span> <span class=\"n\">parsed</span><span class=\"p\">[</span><span class=\"s1\">&#39;result&#39;</span><span class=\"p\">]:</span>\n        <span class=\"n\">response_list</span> <span class=\"o\">=</span> <span class=\"n\">parsed</span><span class=\"p\">[</span><span class=\"s1\">&#39;result&#39;</span><span class=\"p\">][</span><span class=\"s1\">&#39;response_list&#39;</span><span class=\"p\">]</span>\n        <span class=\"k\">if</span> <span class=\"n\">intent</span> <span class=\"o\">==</span> <span class=\"s1\">&#39;&#39;</span><span class=\"p\">:</span>\n            <span class=\"k\">return</span> <span class=\"n\">response_list</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">][</span><span class=\"s1\">&#39;action_list&#39;</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">][</span><span class=\"s1\">&#39;say&#39;</span><span class=\"p\">]</span>\n        <span class=\"k\">for</span> <span class=\"n\">response</span> <span class=\"ow\">in</span> <span class=\"n\">response_list</span><span class=\"p\">:</span>\n            <span class=\"k\">if</span> <span class=\"n\">response</span><span class=\"p\">[</span><span class=\"s1\">&#39;schema&#39;</span><span class=\"p\">][</span><span class=\"s1\">&#39;intent&#39;</span><span class=\"p\">]</span> <span class=\"o\">==</span> <span class=\"n\">intent</span><span class=\"p\">:</span>\n                <span class=\"k\">return</span> <span class=\"n\">response</span><span class=\"p\">[</span><span class=\"s1\">&#39;action_list&#39;</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">][</span><span class=\"s1\">&#39;say&#39;</span><span class=\"p\">]</span>\n        <span class=\"k\">return</span> <span class=\"s1\">&#39;&#39;</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"s1\">&#39;&#39;</span></div>\n\n\n<span class=\"k\">if</span> <span class=\"vm\">__name__</span> <span class=\"o\">==</span> <span class=\"s1\">&#39;__main__&#39;</span><span class=\"p\">:</span>\n    <span class=\"n\">parsed</span> <span class=\"o\">=</span> <span class=\"n\">getUnit</span><span class=\"p\">(</span><span class=\"s1\">&#39;今天的天气&#39;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;S13442&quot;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;w5v7gUV3iPGsGntcM84PtOOM&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;KffXwW6E1alcGplcabcNs63Li6GvvnfL&#39;</span><span class=\"p\">)</span>\n    <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"n\">parsed</span><span class=\"p\">)</span>\n</pre></div>\n\n           </div>\n           \n          </div>\n          <footer>\n  \n\n  <hr/>\n\n  <div role=\"contentinfo\">\n    <p>\n        &copy; Copyright 2019, wzpan\n\n    </p>\n  </div>\n  Built with <a href=\"http://sphinx-doc.org/\">Sphinx</a> using a <a href=\"https://github.com/rtfd/sphinx_rtd_theme\">theme</a> provided by <a href=\"https://readthedocs.org\">Read the Docs</a>. \n\n</footer>\n\n        </div>\n      </div>\n\n    </section>\n\n  </div>\n  \n\n\n  <script type=\"text/javascript\">\n      jQuery(function () {\n          SphinxRtdTheme.Navigation.enable(true);\n      });\n  </script>\n\n  \n  \n    \n   \n\n</body>\n</html>"
  },
  {
    "path": "docs/_modules/robot/statistic.html",
    "content": "\n\n<!DOCTYPE html>\n<!--[if IE 8]><html class=\"no-js lt-ie9\" lang=\"zh-CN\" > <![endif]-->\n<!--[if gt IE 8]><!--> <html class=\"no-js\" lang=\"zh-CN\" > <!--<![endif]-->\n<head>\n  <meta charset=\"utf-8\">\n  \n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  \n  <title>robot.statistic &mdash; wukong-robot 1.2.0 文档</title>\n  \n\n  \n  \n  \n  \n\n  \n  <script type=\"text/javascript\" src=\"../../_static/js/modernizr.min.js\"></script>\n  \n    \n      <script type=\"text/javascript\" id=\"documentation_options\" data-url_root=\"../../\" src=\"../../_static/documentation_options.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/jquery.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/underscore.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/doctools.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/language_data.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/translations.js\"></script>\n    \n    <script type=\"text/javascript\" src=\"../../_static/js/theme.js\"></script>\n\n    \n\n  \n  <link rel=\"stylesheet\" href=\"../../_static/css/theme.css\" type=\"text/css\" />\n  <link rel=\"stylesheet\" href=\"../../_static/pygments.css\" type=\"text/css\" />\n    <link rel=\"index\" title=\"索引\" href=\"../../genindex.html\" />\n    <link rel=\"search\" title=\"搜索\" href=\"../../search.html\" /> \n</head>\n\n<body class=\"wy-body-for-nav\">\n\n   \n  <div class=\"wy-grid-for-nav\">\n    \n    <nav data-toggle=\"wy-nav-shift\" class=\"wy-nav-side\">\n      <div class=\"wy-side-scroll\">\n        <div class=\"wy-side-nav-search\" >\n          \n\n          \n            <a href=\"../../index.html\" class=\"icon icon-home\"> wukong-robot\n          \n\n          \n          </a>\n\n          \n            \n            \n          \n\n          \n<div role=\"search\">\n  <form id=\"rtd-search-form\" class=\"wy-form\" action=\"../../search.html\" method=\"get\">\n    <input type=\"text\" name=\"q\" placeholder=\"Search docs\" />\n    <input type=\"hidden\" name=\"check_keywords\" value=\"yes\" />\n    <input type=\"hidden\" name=\"area\" value=\"default\" />\n  </form>\n</div>\n\n          \n        </div>\n\n        <div class=\"wy-menu wy-menu-vertical\" data-spy=\"affix\" role=\"navigation\" aria-label=\"main navigation\">\n          \n            \n            \n              \n            \n            \n              <!-- Local TOC -->\n              <div class=\"local-toc\"></div>\n            \n          \n        </div>\n      </div>\n    </nav>\n\n    <section data-toggle=\"wy-nav-shift\" class=\"wy-nav-content-wrap\">\n\n      \n      <nav class=\"wy-nav-top\" aria-label=\"top navigation\">\n        \n          <i data-toggle=\"wy-nav-top\" class=\"fa fa-bars\"></i>\n          <a href=\"../../index.html\">wukong-robot</a>\n        \n      </nav>\n\n\n      <div class=\"wy-nav-content\">\n        \n        <div class=\"rst-content\">\n        \n          \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<div role=\"navigation\" aria-label=\"breadcrumbs navigation\">\n\n  <ul class=\"wy-breadcrumbs\">\n    \n      <li><a href=\"../../index.html\">Docs</a> &raquo;</li>\n        \n          <li><a href=\"../index.html\">模块代码</a> &raquo;</li>\n        \n      <li>robot.statistic</li>\n    \n    \n      <li class=\"wy-breadcrumbs-aside\">\n        \n      </li>\n    \n  </ul>\n\n  \n  <hr/>\n</div>\n          <div role=\"main\" class=\"document\" itemscope=\"itemscope\" itemtype=\"http://schema.org/Article\">\n           <div itemprop=\"articleBody\">\n            \n  <h1>robot.statistic 源代码</h1><div class=\"highlight\"><pre>\n<span></span><span class=\"c1\"># -*- coding: utf-8-*-</span>\n\n<span class=\"kn\">from</span> <span class=\"nn\">.</span> <span class=\"k\">import</span> <span class=\"n\">config</span>\n<span class=\"kn\">import</span> <span class=\"nn\">uuid</span>\n<span class=\"kn\">import</span> <span class=\"nn\">requests</span>\n<span class=\"kn\">import</span> <span class=\"nn\">threading</span>\n\n<div class=\"viewcode-block\" id=\"getUUID\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.statistic.getUUID\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">getUUID</span><span class=\"p\">():</span>\n    <span class=\"n\">mac</span> <span class=\"o\">=</span> <span class=\"n\">uuid</span><span class=\"o\">.</span><span class=\"n\">UUID</span><span class=\"p\">(</span><span class=\"nb\">int</span><span class=\"o\">=</span><span class=\"n\">uuid</span><span class=\"o\">.</span><span class=\"n\">getnode</span><span class=\"p\">())</span><span class=\"o\">.</span><span class=\"n\">hex</span><span class=\"p\">[</span><span class=\"o\">-</span><span class=\"mi\">12</span><span class=\"p\">:]</span>\n    <span class=\"k\">return</span> <span class=\"s2\">&quot;:&quot;</span><span class=\"o\">.</span><span class=\"n\">join</span><span class=\"p\">([</span><span class=\"n\">mac</span><span class=\"p\">[</span><span class=\"n\">e</span><span class=\"p\">:</span><span class=\"n\">e</span><span class=\"o\">+</span><span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"k\">for</span> <span class=\"n\">e</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">11</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">)])</span></div>\n\n<div class=\"viewcode-block\" id=\"report\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.statistic.report\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">report</span><span class=\"p\">(</span><span class=\"n\">t</span><span class=\"p\">):</span>\n    <span class=\"n\">ReportThread</span><span class=\"p\">(</span><span class=\"n\">t</span><span class=\"p\">)</span><span class=\"o\">.</span><span class=\"n\">start</span><span class=\"p\">()</span></div>\n\n<div class=\"viewcode-block\" id=\"ReportThread\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.statistic.ReportThread\">[文档]</a><span class=\"k\">class</span> <span class=\"nc\">ReportThread</span> <span class=\"p\">(</span><span class=\"n\">threading</span><span class=\"o\">.</span><span class=\"n\">Thread</span><span class=\"p\">):</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">t</span><span class=\"p\">):</span>\n        <span class=\"c1\"># 需要执行父类的初始化方法</span>\n        <span class=\"n\">threading</span><span class=\"o\">.</span><span class=\"n\">Thread</span><span class=\"o\">.</span><span class=\"fm\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">t</span> <span class=\"o\">=</span> <span class=\"n\">t</span>\n\n<div class=\"viewcode-block\" id=\"ReportThread.run\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.statistic.ReportThread.run\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">run</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"n\">to_report</span> <span class=\"o\">=</span> <span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;statistic&#39;</span><span class=\"p\">,</span> <span class=\"kc\">True</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">to_report</span><span class=\"p\">:</span>\n            <span class=\"k\">try</span><span class=\"p\">:</span>\n                <span class=\"n\">persona</span> <span class=\"o\">=</span> <span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s2\">&quot;robot_name_cn&quot;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;孙悟空&#39;</span><span class=\"p\">)</span>\n                <span class=\"n\">url</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;http://livecv.hahack.com:8022/statistic&#39;</span>\n                <span class=\"n\">payload</span> <span class=\"o\">=</span> <span class=\"p\">{</span><span class=\"s1\">&#39;type&#39;</span><span class=\"p\">:</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">t</span><span class=\"p\">),</span> <span class=\"s1\">&#39;uuid&#39;</span><span class=\"p\">:</span> <span class=\"n\">getUUID</span><span class=\"p\">(),</span> <span class=\"s1\">&#39;name&#39;</span><span class=\"p\">:</span> <span class=\"n\">persona</span><span class=\"p\">,</span> <span class=\"s1\">&#39;project&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;wukong&#39;</span><span class=\"p\">}</span>\n                <span class=\"n\">requests</span><span class=\"o\">.</span><span class=\"n\">post</span><span class=\"p\">(</span><span class=\"n\">url</span><span class=\"p\">,</span> <span class=\"n\">data</span><span class=\"o\">=</span><span class=\"n\">payload</span><span class=\"p\">,</span> <span class=\"n\">timeout</span><span class=\"o\">=</span><span class=\"mi\">3</span><span class=\"p\">)</span>\n            <span class=\"k\">except</span> <span class=\"ne\">Exception</span><span class=\"p\">:</span>\n                <span class=\"k\">return</span></div></div>\n\n    \n</pre></div>\n\n           </div>\n           \n          </div>\n          <footer>\n  \n\n  <hr/>\n\n  <div role=\"contentinfo\">\n    <p>\n        &copy; Copyright 2019, wzpan\n\n    </p>\n  </div>\n  Built with <a href=\"http://sphinx-doc.org/\">Sphinx</a> using a <a href=\"https://github.com/rtfd/sphinx_rtd_theme\">theme</a> provided by <a href=\"https://readthedocs.org\">Read the Docs</a>. \n\n</footer>\n\n        </div>\n      </div>\n\n    </section>\n\n  </div>\n  \n\n\n  <script type=\"text/javascript\">\n      jQuery(function () {\n          SphinxRtdTheme.Navigation.enable(true);\n      });\n  </script>\n\n  \n  \n    \n   \n\n</body>\n</html>"
  },
  {
    "path": "docs/_modules/robot/utils.html",
    "content": "\n\n<!DOCTYPE html>\n<!--[if IE 8]><html class=\"no-js lt-ie9\" lang=\"zh-CN\" > <![endif]-->\n<!--[if gt IE 8]><!--> <html class=\"no-js\" lang=\"zh-CN\" > <!--<![endif]-->\n<head>\n  <meta charset=\"utf-8\">\n  \n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  \n  <title>robot.utils &mdash; wukong-robot 1.2.0 文档</title>\n  \n\n  \n  \n  \n  \n\n  \n  <script type=\"text/javascript\" src=\"../../_static/js/modernizr.min.js\"></script>\n  \n    \n      <script type=\"text/javascript\" id=\"documentation_options\" data-url_root=\"../../\" src=\"../../_static/documentation_options.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/jquery.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/underscore.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/doctools.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/language_data.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/translations.js\"></script>\n    \n    <script type=\"text/javascript\" src=\"../../_static/js/theme.js\"></script>\n\n    \n\n  \n  <link rel=\"stylesheet\" href=\"../../_static/css/theme.css\" type=\"text/css\" />\n  <link rel=\"stylesheet\" href=\"../../_static/pygments.css\" type=\"text/css\" />\n    <link rel=\"index\" title=\"索引\" href=\"../../genindex.html\" />\n    <link rel=\"search\" title=\"搜索\" href=\"../../search.html\" /> \n</head>\n\n<body class=\"wy-body-for-nav\">\n\n   \n  <div class=\"wy-grid-for-nav\">\n    \n    <nav data-toggle=\"wy-nav-shift\" class=\"wy-nav-side\">\n      <div class=\"wy-side-scroll\">\n        <div class=\"wy-side-nav-search\" >\n          \n\n          \n            <a href=\"../../index.html\" class=\"icon icon-home\"> wukong-robot\n          \n\n          \n          </a>\n\n          \n            \n            \n          \n\n          \n<div role=\"search\">\n  <form id=\"rtd-search-form\" class=\"wy-form\" action=\"../../search.html\" method=\"get\">\n    <input type=\"text\" name=\"q\" placeholder=\"Search docs\" />\n    <input type=\"hidden\" name=\"check_keywords\" value=\"yes\" />\n    <input type=\"hidden\" name=\"area\" value=\"default\" />\n  </form>\n</div>\n\n          \n        </div>\n\n        <div class=\"wy-menu wy-menu-vertical\" data-spy=\"affix\" role=\"navigation\" aria-label=\"main navigation\">\n          \n            \n            \n              \n            \n            \n              <!-- Local TOC -->\n              <div class=\"local-toc\"></div>\n            \n          \n        </div>\n      </div>\n    </nav>\n\n    <section data-toggle=\"wy-nav-shift\" class=\"wy-nav-content-wrap\">\n\n      \n      <nav class=\"wy-nav-top\" aria-label=\"top navigation\">\n        \n          <i data-toggle=\"wy-nav-top\" class=\"fa fa-bars\"></i>\n          <a href=\"../../index.html\">wukong-robot</a>\n        \n      </nav>\n\n\n      <div class=\"wy-nav-content\">\n        \n        <div class=\"rst-content\">\n        \n          \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<div role=\"navigation\" aria-label=\"breadcrumbs navigation\">\n\n  <ul class=\"wy-breadcrumbs\">\n    \n      <li><a href=\"../../index.html\">Docs</a> &raquo;</li>\n        \n          <li><a href=\"../index.html\">模块代码</a> &raquo;</li>\n        \n      <li>robot.utils</li>\n    \n    \n      <li class=\"wy-breadcrumbs-aside\">\n        \n      </li>\n    \n  </ul>\n\n  \n  <hr/>\n</div>\n          <div role=\"main\" class=\"document\" itemscope=\"itemscope\" itemtype=\"http://schema.org/Article\">\n           <div itemprop=\"articleBody\">\n            \n  <h1>robot.utils 源代码</h1><div class=\"highlight\"><pre>\n<span></span><span class=\"c1\"># -*- coding: utf-8-*-</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">import</span> <span class=\"nn\">tempfile</span>\n<span class=\"kn\">import</span> <span class=\"nn\">wave</span>\n<span class=\"kn\">import</span> <span class=\"nn\">shutil</span>\n<span class=\"kn\">import</span> <span class=\"nn\">re</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">hashlib</span>\n<span class=\"kn\">import</span> <span class=\"nn\">subprocess</span>\n<span class=\"kn\">from</span> <span class=\"nn\">.</span> <span class=\"k\">import</span> <span class=\"n\">constants</span><span class=\"p\">,</span> <span class=\"n\">config</span>\n<span class=\"kn\">from</span> <span class=\"nn\">robot</span> <span class=\"k\">import</span> <span class=\"n\">logging</span>\n<span class=\"kn\">from</span> <span class=\"nn\">pydub</span> <span class=\"k\">import</span> <span class=\"n\">AudioSegment</span>\n<span class=\"kn\">from</span> <span class=\"nn\">pytz</span> <span class=\"k\">import</span> <span class=\"n\">timezone</span>\n<span class=\"kn\">import</span> <span class=\"nn\">_thread</span> <span class=\"k\">as</span> <span class=\"nn\">thread</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">smtplib</span>\n<span class=\"kn\">from</span> <span class=\"nn\">email.mime.text</span> <span class=\"k\">import</span> <span class=\"n\">MIMEText</span>\n<span class=\"kn\">from</span> <span class=\"nn\">email.mime.multipart</span> <span class=\"k\">import</span> <span class=\"n\">MIMEMultipart</span>\n\n<span class=\"n\">logger</span> <span class=\"o\">=</span> <span class=\"n\">logging</span><span class=\"o\">.</span><span class=\"n\">getLogger</span><span class=\"p\">(</span><span class=\"vm\">__name__</span><span class=\"p\">)</span>\n\n<span class=\"n\">do_not_bother</span> <span class=\"o\">=</span> <span class=\"kc\">False</span>\n\n<div class=\"viewcode-block\" id=\"sendEmail\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.utils.sendEmail\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">sendEmail</span><span class=\"p\">(</span><span class=\"n\">SUBJECT</span><span class=\"p\">,</span> <span class=\"n\">BODY</span><span class=\"p\">,</span> <span class=\"n\">ATTACH_LIST</span><span class=\"p\">,</span> <span class=\"n\">TO</span><span class=\"p\">,</span> <span class=\"n\">FROM</span><span class=\"p\">,</span> <span class=\"n\">SENDER</span><span class=\"p\">,</span>\n              <span class=\"n\">PASSWORD</span><span class=\"p\">,</span> <span class=\"n\">SMTP_SERVER</span><span class=\"p\">,</span> <span class=\"n\">SMTP_PORT</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    发送邮件</span>\n\n<span class=\"sd\">    :param SUBJECT: 邮件标题</span>\n<span class=\"sd\">    :param BODY: 邮件正文</span>\n<span class=\"sd\">    :param ATTACH_LIST: 附件</span>\n<span class=\"sd\">    :param TO: 收件人</span>\n<span class=\"sd\">    :param FROM: 发件人</span>\n<span class=\"sd\">    :param SENDER: 发件人信息</span>\n<span class=\"sd\">    :param PASSWORD: 密码</span>\n<span class=\"sd\">    :param SMTP_SERVER: smtp 服务器</span>\n<span class=\"sd\">    :param SMTP_PORT: smtp 端口号</span>\n<span class=\"sd\">    :returns: True: 发送成功; False: 发送失败</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"n\">txt</span> <span class=\"o\">=</span> <span class=\"n\">MIMEText</span><span class=\"p\">(</span><span class=\"n\">BODY</span><span class=\"o\">.</span><span class=\"n\">encode</span><span class=\"p\">(</span><span class=\"s1\">&#39;utf-8&#39;</span><span class=\"p\">),</span> <span class=\"s1\">&#39;html&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;utf-8&#39;</span><span class=\"p\">)</span>\n    <span class=\"n\">msg</span> <span class=\"o\">=</span> <span class=\"n\">MIMEMultipart</span><span class=\"p\">()</span>\n    <span class=\"n\">msg</span><span class=\"o\">.</span><span class=\"n\">attach</span><span class=\"p\">(</span><span class=\"n\">txt</span><span class=\"p\">)</span>    \n\n    <span class=\"k\">for</span> <span class=\"n\">attach</span> <span class=\"ow\">in</span> <span class=\"n\">ATTACH_LIST</span><span class=\"p\">:</span>\n        <span class=\"k\">try</span><span class=\"p\">:</span>\n            <span class=\"n\">att</span> <span class=\"o\">=</span> <span class=\"n\">MIMEText</span><span class=\"p\">(</span><span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">attach</span><span class=\"p\">,</span> <span class=\"s1\">&#39;rb&#39;</span><span class=\"p\">)</span><span class=\"o\">.</span><span class=\"n\">read</span><span class=\"p\">(),</span> <span class=\"s1\">&#39;base64&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;utf-8&#39;</span><span class=\"p\">)</span>\n            <span class=\"n\">filename</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">basename</span><span class=\"p\">(</span><span class=\"n\">attach</span><span class=\"p\">)</span>\n            <span class=\"n\">att</span><span class=\"p\">[</span><span class=\"s2\">&quot;Content-Type&quot;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;application/octet-stream&#39;</span>\n            <span class=\"n\">att</span><span class=\"p\">[</span><span class=\"s2\">&quot;Content-Disposition&quot;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;attachment; filename=&quot;</span><span class=\"si\">%s</span><span class=\"s1\">&quot;&#39;</span> <span class=\"o\">%</span> <span class=\"n\">filename</span>\n            <span class=\"n\">msg</span><span class=\"o\">.</span><span class=\"n\">attach</span><span class=\"p\">(</span><span class=\"n\">att</span><span class=\"p\">)</span>\n        <span class=\"k\">except</span> <span class=\"ne\">Exception</span><span class=\"p\">:</span>\n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">error</span><span class=\"p\">(</span><span class=\"sa\">u</span><span class=\"s1\">&#39;附件 </span><span class=\"si\">%s</span><span class=\"s1\"> 发送失败！&#39;</span> <span class=\"o\">%</span> <span class=\"n\">attach</span><span class=\"p\">)</span>\n            <span class=\"k\">continue</span>\n\n    <span class=\"n\">msg</span><span class=\"p\">[</span><span class=\"s1\">&#39;From&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">SENDER</span>\n    <span class=\"n\">msg</span><span class=\"p\">[</span><span class=\"s1\">&#39;To&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">TO</span>\n    <span class=\"n\">msg</span><span class=\"p\">[</span><span class=\"s1\">&#39;Subject&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">SUBJECT</span>\n\n    <span class=\"k\">try</span><span class=\"p\">:</span>\n        <span class=\"n\">session</span> <span class=\"o\">=</span> <span class=\"n\">smtplib</span><span class=\"o\">.</span><span class=\"n\">SMTP</span><span class=\"p\">()</span>\n        <span class=\"n\">session</span><span class=\"o\">.</span><span class=\"n\">connect</span><span class=\"p\">(</span><span class=\"n\">SMTP_SERVER</span><span class=\"p\">,</span> <span class=\"n\">SMTP_PORT</span><span class=\"p\">)</span>\n        <span class=\"n\">session</span><span class=\"o\">.</span><span class=\"n\">starttls</span><span class=\"p\">()</span>\n        <span class=\"n\">session</span><span class=\"o\">.</span><span class=\"n\">login</span><span class=\"p\">(</span><span class=\"n\">FROM</span><span class=\"p\">,</span> <span class=\"n\">PASSWORD</span><span class=\"p\">)</span>\n        <span class=\"n\">session</span><span class=\"o\">.</span><span class=\"n\">sendmail</span><span class=\"p\">(</span><span class=\"n\">SENDER</span><span class=\"p\">,</span> <span class=\"n\">TO</span><span class=\"p\">,</span> <span class=\"n\">msg</span><span class=\"o\">.</span><span class=\"n\">as_string</span><span class=\"p\">())</span>\n        <span class=\"n\">session</span><span class=\"o\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n        <span class=\"k\">return</span> <span class=\"kc\">True</span>\n    <span class=\"k\">except</span> <span class=\"ne\">Exception</span> <span class=\"k\">as</span> <span class=\"n\">e</span><span class=\"p\">:</span>\n        <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">error</span><span class=\"p\">(</span><span class=\"n\">e</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span> <span class=\"kc\">False</span></div>\n\n\n<div class=\"viewcode-block\" id=\"emailUser\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.utils.emailUser\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">emailUser</span><span class=\"p\">(</span><span class=\"n\">SUBJECT</span><span class=\"o\">=</span><span class=\"s2\">&quot;&quot;</span><span class=\"p\">,</span> <span class=\"n\">BODY</span><span class=\"o\">=</span><span class=\"s2\">&quot;&quot;</span><span class=\"p\">,</span> <span class=\"n\">ATTACH_LIST</span><span class=\"o\">=</span><span class=\"p\">[]):</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    给用户发送邮件</span>\n\n<span class=\"sd\">    :param SUBJECT: subject line of the email</span>\n<span class=\"sd\">    :param BODY: body text of the email</span>\n<span class=\"sd\">    :returns: True: 发送成功; False: 发送失败</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"c1\"># add footer</span>\n    <span class=\"k\">if</span> <span class=\"n\">BODY</span><span class=\"p\">:</span>\n        <span class=\"n\">BODY</span> <span class=\"o\">=</span> <span class=\"sa\">u</span><span class=\"s2\">&quot;</span><span class=\"si\">%s</span><span class=\"s2\">，&lt;br&gt;&lt;br&gt;这是您要的内容：&lt;br&gt;</span><span class=\"si\">%s</span><span class=\"s2\">&lt;br&gt;&quot;</span> <span class=\"o\">%</span> <span class=\"p\">(</span><span class=\"n\">config</span><span class=\"p\">[</span><span class=\"s1\">&#39;first_name&#39;</span><span class=\"p\">],</span> <span class=\"n\">BODY</span><span class=\"p\">)</span>\n\n    <span class=\"n\">recipient</span> <span class=\"o\">=</span> <span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;/email/address&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;&#39;</span><span class=\"p\">)</span>\n    <span class=\"n\">robot_name</span> <span class=\"o\">=</span> <span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;robot_name_cn&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;wukong-robot&#39;</span><span class=\"p\">)</span>\n    <span class=\"n\">recipient</span> <span class=\"o\">=</span> <span class=\"n\">robot_name</span> <span class=\"o\">+</span> <span class=\"s2\">&quot; &lt;</span><span class=\"si\">%s</span><span class=\"s2\">&gt;&quot;</span> <span class=\"o\">%</span> <span class=\"n\">recipient</span>\n    <span class=\"n\">user</span> <span class=\"o\">=</span> <span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;/email/address&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;&#39;</span><span class=\"p\">)</span>\n    <span class=\"n\">password</span> <span class=\"o\">=</span> <span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;/email/password&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;&#39;</span><span class=\"p\">)</span>\n    <span class=\"n\">server</span> <span class=\"o\">=</span> <span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;/email/smtp_server&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;&#39;</span><span class=\"p\">)</span>\n    <span class=\"n\">port</span> <span class=\"o\">=</span> <span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;/email/smtp_port&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;&#39;</span><span class=\"p\">)</span>\n\n    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">recipient</span> <span class=\"ow\">or</span> <span class=\"ow\">not</span> <span class=\"n\">user</span> <span class=\"ow\">or</span> <span class=\"ow\">not</span> <span class=\"n\">password</span> <span class=\"ow\">or</span> <span class=\"ow\">not</span> <span class=\"n\">server</span> <span class=\"ow\">or</span> <span class=\"ow\">not</span> <span class=\"n\">port</span><span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"kc\">False</span>\n    <span class=\"k\">try</span><span class=\"p\">:</span>\n        <span class=\"n\">sendEmail</span><span class=\"p\">(</span><span class=\"n\">SUBJECT</span><span class=\"p\">,</span> <span class=\"n\">BODY</span><span class=\"p\">,</span> <span class=\"n\">ATTACH_LIST</span><span class=\"p\">,</span> <span class=\"n\">user</span><span class=\"p\">,</span> <span class=\"n\">user</span><span class=\"p\">,</span>\n                  <span class=\"n\">recipient</span><span class=\"p\">,</span> <span class=\"n\">password</span><span class=\"p\">,</span> <span class=\"n\">server</span><span class=\"p\">,</span> <span class=\"n\">port</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span> <span class=\"kc\">True</span>\n    <span class=\"k\">except</span> <span class=\"ne\">Exception</span> <span class=\"k\">as</span> <span class=\"n\">e</span><span class=\"p\">:</span>\n        <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">error</span><span class=\"p\">(</span><span class=\"n\">e</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span> <span class=\"kc\">False</span></div>\n\n\n<div class=\"viewcode-block\" id=\"get_file_content\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.utils.get_file_content\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">get_file_content</span><span class=\"p\">(</span><span class=\"n\">filePath</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    读取文件内容并返回</span>\n\n<span class=\"sd\">    :param filePath: 文件路径</span>\n<span class=\"sd\">    :returns: 文件内容</span>\n<span class=\"sd\">    :raises IOError: 读取失败则抛出 IOError</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"n\">filePath</span><span class=\"p\">,</span> <span class=\"s1\">&#39;rb&#39;</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">fp</span><span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"n\">fp</span><span class=\"o\">.</span><span class=\"n\">read</span><span class=\"p\">()</span></div>\n\n<div class=\"viewcode-block\" id=\"check_and_delete\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.utils.check_and_delete\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">check_and_delete</span><span class=\"p\">(</span><span class=\"n\">fp</span><span class=\"p\">,</span> <span class=\"n\">wait</span><span class=\"o\">=</span><span class=\"mi\">0</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot; </span>\n<span class=\"sd\">    检查并删除文件/文件夹</span>\n\n<span class=\"sd\">    :param fp: 文件路径</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"k\">def</span> <span class=\"nf\">run</span><span class=\"p\">():</span>\n        <span class=\"k\">if</span> <span class=\"n\">wait</span> <span class=\"o\">&gt;</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"n\">time</span><span class=\"o\">.</span><span class=\"n\">sleep</span><span class=\"p\">(</span><span class=\"n\">wait</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"nb\">isinstance</span><span class=\"p\">(</span><span class=\"n\">fp</span><span class=\"p\">,</span> <span class=\"nb\">str</span><span class=\"p\">)</span> <span class=\"ow\">and</span> <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">exists</span><span class=\"p\">(</span><span class=\"n\">fp</span><span class=\"p\">):</span>\n            <span class=\"k\">if</span> <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">fp</span><span class=\"p\">):</span>\n                <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">remove</span><span class=\"p\">(</span><span class=\"n\">fp</span><span class=\"p\">)</span>\n            <span class=\"k\">else</span><span class=\"p\">:</span>\n                <span class=\"n\">shutil</span><span class=\"o\">.</span><span class=\"n\">rmtree</span><span class=\"p\">(</span><span class=\"n\">fp</span><span class=\"p\">)</span>\n    \n    <span class=\"n\">thread</span><span class=\"o\">.</span><span class=\"n\">start_new_thread</span><span class=\"p\">(</span><span class=\"n\">run</span><span class=\"p\">,</span> <span class=\"p\">())</span></div>\n\n\n<div class=\"viewcode-block\" id=\"write_temp_file\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.utils.write_temp_file\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">write_temp_file</span><span class=\"p\">(</span><span class=\"n\">data</span><span class=\"p\">,</span> <span class=\"n\">suffix</span><span class=\"p\">,</span> <span class=\"n\">mode</span><span class=\"o\">=</span><span class=\"s1\">&#39;w+b&#39;</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot; </span>\n<span class=\"sd\">    写入临时文件</span>\n\n<span class=\"sd\">    :param data: 数据</span>\n<span class=\"sd\">    :param suffix: 后缀名</span>\n<span class=\"sd\">    :param mode: 写入模式，默认为 w+b</span>\n<span class=\"sd\">    :returns: 文件保存后的路径</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"k\">with</span> <span class=\"n\">tempfile</span><span class=\"o\">.</span><span class=\"n\">NamedTemporaryFile</span><span class=\"p\">(</span><span class=\"n\">mode</span><span class=\"o\">=</span><span class=\"n\">mode</span><span class=\"p\">,</span> <span class=\"n\">suffix</span><span class=\"o\">=</span><span class=\"n\">suffix</span><span class=\"p\">,</span> <span class=\"n\">delete</span><span class=\"o\">=</span><span class=\"kc\">False</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n        <span class=\"n\">f</span><span class=\"o\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"n\">data</span><span class=\"p\">)</span>\n        <span class=\"n\">tmpfile</span> <span class=\"o\">=</span> <span class=\"n\">f</span><span class=\"o\">.</span><span class=\"n\">name</span>\n    <span class=\"k\">return</span> <span class=\"n\">tmpfile</span></div>\n\n<div class=\"viewcode-block\" id=\"get_pcm_from_wav\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.utils.get_pcm_from_wav\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">get_pcm_from_wav</span><span class=\"p\">(</span><span class=\"n\">wav_path</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot; </span>\n<span class=\"sd\">    从 wav 文件中读取 pcm</span>\n<span class=\"sd\">    </span>\n<span class=\"sd\">    :param wav_path: wav 文件路径</span>\n<span class=\"sd\">    :returns: pcm 数据</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"n\">wav</span> <span class=\"o\">=</span> <span class=\"n\">wave</span><span class=\"o\">.</span><span class=\"n\">open</span><span class=\"p\">(</span><span class=\"n\">wav_path</span><span class=\"p\">,</span> <span class=\"s1\">&#39;rb&#39;</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">wav</span><span class=\"o\">.</span><span class=\"n\">readframes</span><span class=\"p\">(</span><span class=\"n\">wav</span><span class=\"o\">.</span><span class=\"n\">getnframes</span><span class=\"p\">())</span></div>\n\n<div class=\"viewcode-block\" id=\"convert_wav_to_mp3\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.utils.convert_wav_to_mp3\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">convert_wav_to_mp3</span><span class=\"p\">(</span><span class=\"n\">wav_path</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot; </span>\n<span class=\"sd\">    将 wav 文件转成 mp3</span>\n\n<span class=\"sd\">    :param wav_path: wav 文件路径</span>\n<span class=\"sd\">    :returns: mp3 文件路径</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">exists</span><span class=\"p\">(</span><span class=\"n\">wav_path</span><span class=\"p\">):</span>\n        <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">critical</span><span class=\"p\">(</span><span class=\"s2\">&quot;文件错误 </span><span class=\"si\">{}</span><span class=\"s2\">&quot;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">wav_path</span><span class=\"p\">))</span>\n        <span class=\"k\">return</span> <span class=\"kc\">None</span>\n    <span class=\"n\">mp3_path</span> <span class=\"o\">=</span> <span class=\"n\">wav_path</span><span class=\"o\">.</span><span class=\"n\">replace</span><span class=\"p\">(</span><span class=\"s1\">&#39;.wav&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;.mp3&#39;</span><span class=\"p\">)</span>\n    <span class=\"n\">AudioSegment</span><span class=\"o\">.</span><span class=\"n\">from_wav</span><span class=\"p\">(</span><span class=\"n\">wav_path</span><span class=\"p\">)</span><span class=\"o\">.</span><span class=\"n\">export</span><span class=\"p\">(</span><span class=\"n\">mp3_path</span><span class=\"p\">,</span> <span class=\"nb\">format</span><span class=\"o\">=</span><span class=\"s2\">&quot;mp3&quot;</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">mp3_path</span></div>\n\n<div class=\"viewcode-block\" id=\"convert_mp3_to_wav\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.utils.convert_mp3_to_wav\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">convert_mp3_to_wav</span><span class=\"p\">(</span><span class=\"n\">mp3_path</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot; </span>\n<span class=\"sd\">    将 mp3 文件转成 wav</span>\n\n<span class=\"sd\">    :param mp3_path: mp3 文件路径</span>\n<span class=\"sd\">    :returns: wav 文件路径</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"n\">target</span> <span class=\"o\">=</span> <span class=\"n\">mp3_path</span><span class=\"o\">.</span><span class=\"n\">replace</span><span class=\"p\">(</span><span class=\"s2\">&quot;.mp3&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;.wav&quot;</span><span class=\"p\">)</span>\n    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">exists</span><span class=\"p\">(</span><span class=\"n\">mp3_path</span><span class=\"p\">):</span>\n        <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">critical</span><span class=\"p\">(</span><span class=\"s2\">&quot;文件错误 </span><span class=\"si\">{}</span><span class=\"s2\">&quot;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">mp3_path</span><span class=\"p\">))</span>\n        <span class=\"k\">return</span> <span class=\"kc\">None</span>\n    <span class=\"n\">AudioSegment</span><span class=\"o\">.</span><span class=\"n\">from_mp3</span><span class=\"p\">(</span><span class=\"n\">mp3_path</span><span class=\"p\">)</span><span class=\"o\">.</span><span class=\"n\">export</span><span class=\"p\">(</span><span class=\"n\">target</span><span class=\"p\">,</span> <span class=\"nb\">format</span><span class=\"o\">=</span><span class=\"s2\">&quot;wav&quot;</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">target</span>        </div>\n\n<div class=\"viewcode-block\" id=\"clean\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.utils.clean\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">clean</span><span class=\"p\">():</span>\n    <span class=\"sd\">&quot;&quot;&quot; 清理垃圾数据 &quot;&quot;&quot;</span>\n    <span class=\"n\">temp</span> <span class=\"o\">=</span> <span class=\"n\">constants</span><span class=\"o\">.</span><span class=\"n\">TEMP_PATH</span>\n    <span class=\"n\">temp_files</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">listdir</span><span class=\"p\">(</span><span class=\"n\">temp</span><span class=\"p\">)</span>\n    <span class=\"k\">for</span> <span class=\"n\">f</span> <span class=\"ow\">in</span> <span class=\"n\">temp_files</span><span class=\"p\">:</span>\n        <span class=\"k\">if</span> <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">isfile</span><span class=\"p\">(</span><span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">temp</span><span class=\"p\">,</span> <span class=\"n\">f</span><span class=\"p\">))</span> <span class=\"ow\">and</span> <span class=\"n\">re</span><span class=\"o\">.</span><span class=\"n\">match</span><span class=\"p\">(</span><span class=\"sa\">r</span><span class=\"s1\">&#39;output[\\d]*\\.wav&#39;</span><span class=\"p\">,</span> <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">basename</span><span class=\"p\">(</span><span class=\"n\">f</span><span class=\"p\">)):</span>\n            <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">remove</span><span class=\"p\">(</span><span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">temp</span><span class=\"p\">,</span> <span class=\"n\">f</span><span class=\"p\">))</span></div>\n\n<div class=\"viewcode-block\" id=\"is_proper_time\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.utils.is_proper_time\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">is_proper_time</span><span class=\"p\">():</span>\n    <span class=\"sd\">&quot;&quot;&quot; 是否合适时间 &quot;&quot;&quot;</span>\n    <span class=\"k\">if</span> <span class=\"n\">do_not_bother</span> <span class=\"o\">==</span> <span class=\"kc\">True</span><span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"kc\">False</span>\n    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">has</span><span class=\"p\">(</span><span class=\"s1\">&#39;do_not_bother&#39;</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"kc\">True</span>\n    <span class=\"n\">bother_profile</span> <span class=\"o\">=</span> <span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;do_not_bother&#39;</span><span class=\"p\">)</span>\n    <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">bother_profile</span><span class=\"p\">[</span><span class=\"s1\">&#39;enable&#39;</span><span class=\"p\">]:</span>\n        <span class=\"k\">return</span> <span class=\"kc\">True</span>\n    <span class=\"k\">if</span> <span class=\"s1\">&#39;since&#39;</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"n\">bother_profile</span> <span class=\"ow\">or</span> <span class=\"s1\">&#39;till&#39;</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"n\">bother_profile</span><span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"kc\">True</span>\n    <span class=\"n\">since</span> <span class=\"o\">=</span> <span class=\"n\">bother_profile</span><span class=\"p\">[</span><span class=\"s1\">&#39;since&#39;</span><span class=\"p\">]</span>\n    <span class=\"n\">till</span> <span class=\"o\">=</span> <span class=\"n\">bother_profile</span><span class=\"p\">[</span><span class=\"s1\">&#39;till&#39;</span><span class=\"p\">]</span>\n    <span class=\"n\">current</span> <span class=\"o\">=</span> <span class=\"n\">time</span><span class=\"o\">.</span><span class=\"n\">localtime</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"o\">.</span><span class=\"n\">time</span><span class=\"p\">())</span><span class=\"o\">.</span><span class=\"n\">tm_hour</span>\n    <span class=\"k\">if</span> <span class=\"n\">till</span> <span class=\"o\">&gt;</span> <span class=\"n\">since</span><span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"n\">current</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">since</span><span class=\"p\">,</span> <span class=\"n\">till</span><span class=\"p\">)</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"ow\">not</span> <span class=\"p\">(</span><span class=\"n\">current</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">since</span><span class=\"p\">,</span> <span class=\"mi\">25</span><span class=\"p\">)</span> <span class=\"ow\">or</span>\n                    <span class=\"n\">current</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"n\">till</span><span class=\"p\">))</span></div>\n\n<div class=\"viewcode-block\" id=\"get_do_not_bother_on_hotword\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.utils.get_do_not_bother_on_hotword\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">get_do_not_bother_on_hotword</span><span class=\"p\">():</span>\n    <span class=\"sd\">&quot;&quot;&quot; 打开勿扰模式唤醒词 &quot;&quot;&quot;</span>\n    <span class=\"k\">return</span> <span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;/do_not_bother/on_hotword&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;悟空别吵.pmdl&#39;</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"get_do_not_bother_off_hotword\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.utils.get_do_not_bother_off_hotword\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">get_do_not_bother_off_hotword</span><span class=\"p\">():</span>\n    <span class=\"sd\">&quot;&quot;&quot; 关闭勿扰模式唤醒词 &quot;&quot;&quot;</span>\n    <span class=\"k\">return</span> <span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;/do_not_bother/off_hotword&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;悟空醒醒.pmdl&#39;</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"getTimezone\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.utils.getTimezone\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">getTimezone</span><span class=\"p\">():</span>\n    <span class=\"sd\">&quot;&quot;&quot; 获取时区 &quot;&quot;&quot;</span>\n    <span class=\"k\">return</span> <span class=\"n\">timezone</span><span class=\"p\">(</span><span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;timezone&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;HKT&#39;</span><span class=\"p\">))</span></div>\n\n<div class=\"viewcode-block\" id=\"getCache\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.utils.getCache\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">getCache</span><span class=\"p\">(</span><span class=\"n\">msg</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot; 获取缓存的语音 &quot;&quot;&quot;</span>\n    <span class=\"n\">md5</span> <span class=\"o\">=</span> <span class=\"n\">hashlib</span><span class=\"o\">.</span><span class=\"n\">md5</span><span class=\"p\">(</span><span class=\"n\">msg</span><span class=\"o\">.</span><span class=\"n\">encode</span><span class=\"p\">(</span><span class=\"s1\">&#39;utf-8&#39;</span><span class=\"p\">))</span><span class=\"o\">.</span><span class=\"n\">hexdigest</span><span class=\"p\">()</span>\n    <span class=\"n\">mp3_cache</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">constants</span><span class=\"o\">.</span><span class=\"n\">TEMP_PATH</span><span class=\"p\">,</span> <span class=\"n\">md5</span> <span class=\"o\">+</span> <span class=\"s1\">&#39;.mp3&#39;</span><span class=\"p\">)</span>\n    <span class=\"n\">wav_cache</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">constants</span><span class=\"o\">.</span><span class=\"n\">TEMP_PATH</span><span class=\"p\">,</span> <span class=\"n\">md5</span> <span class=\"o\">+</span> <span class=\"s1\">&#39;.wav&#39;</span><span class=\"p\">)</span>\n    <span class=\"k\">if</span> <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">exists</span><span class=\"p\">(</span><span class=\"n\">mp3_cache</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"n\">mp3_cache</span>\n    <span class=\"k\">elif</span> <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">exists</span><span class=\"p\">(</span><span class=\"n\">wav_cache</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"n\">wav_cache</span>\n    <span class=\"k\">return</span> <span class=\"kc\">None</span></div>\n\n<div class=\"viewcode-block\" id=\"saveCache\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.utils.saveCache\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">saveCache</span><span class=\"p\">(</span><span class=\"n\">voice</span><span class=\"p\">,</span> <span class=\"n\">msg</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot; 获取缓存的语音 &quot;&quot;&quot;</span>\n    <span class=\"n\">foo</span><span class=\"p\">,</span> <span class=\"n\">ext</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">splitext</span><span class=\"p\">(</span><span class=\"n\">voice</span><span class=\"p\">)</span>\n    <span class=\"n\">md5</span> <span class=\"o\">=</span> <span class=\"n\">hashlib</span><span class=\"o\">.</span><span class=\"n\">md5</span><span class=\"p\">(</span><span class=\"n\">msg</span><span class=\"o\">.</span><span class=\"n\">encode</span><span class=\"p\">(</span><span class=\"s1\">&#39;utf-8&#39;</span><span class=\"p\">))</span><span class=\"o\">.</span><span class=\"n\">hexdigest</span><span class=\"p\">()</span>\n    <span class=\"n\">target</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">constants</span><span class=\"o\">.</span><span class=\"n\">TEMP_PATH</span><span class=\"p\">,</span> <span class=\"n\">md5</span><span class=\"o\">+</span><span class=\"n\">ext</span><span class=\"p\">)</span>\n    <span class=\"n\">shutil</span><span class=\"o\">.</span><span class=\"n\">copyfile</span><span class=\"p\">(</span><span class=\"n\">voice</span><span class=\"p\">,</span> <span class=\"n\">target</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">target</span></div>\n    \n\n<div class=\"viewcode-block\" id=\"lruCache\"><a class=\"viewcode-back\" href=\"../../robot.html#robot.utils.lruCache\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">lruCache</span><span class=\"p\">():</span>\n    <span class=\"sd\">&quot;&quot;&quot; 清理最近未使用的缓存 &quot;&quot;&quot;</span>\n    <span class=\"k\">def</span> <span class=\"nf\">run</span><span class=\"p\">(</span><span class=\"o\">*</span><span class=\"n\">args</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;/lru_cache/enable&#39;</span><span class=\"p\">,</span> <span class=\"kc\">True</span><span class=\"p\">):</span>            \n            <span class=\"n\">days</span> <span class=\"o\">=</span> <span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;/lru_cache/days&#39;</span><span class=\"p\">,</span> <span class=\"mi\">7</span><span class=\"p\">)</span>\n            <span class=\"n\">subprocess</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"s1\">&#39;find . -name &quot;*.mp3&quot; -atime +</span><span class=\"si\">%d</span><span class=\"s1\"> -exec rm </span><span class=\"si\">{}</span><span class=\"s1\"> \\;&#39;</span> <span class=\"o\">%</span> <span class=\"n\">days</span><span class=\"p\">,</span> <span class=\"n\">cwd</span><span class=\"o\">=</span><span class=\"n\">constants</span><span class=\"o\">.</span><span class=\"n\">TEMP_PATH</span><span class=\"p\">,</span> <span class=\"n\">shell</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">)</span>\n\n    <span class=\"n\">thread</span><span class=\"o\">.</span><span class=\"n\">start_new_thread</span><span class=\"p\">(</span><span class=\"n\">run</span><span class=\"p\">,</span> <span class=\"p\">())</span></div>\n\n</pre></div>\n\n           </div>\n           \n          </div>\n          <footer>\n  \n\n  <hr/>\n\n  <div role=\"contentinfo\">\n    <p>\n        &copy; Copyright 2019, wzpan\n\n    </p>\n  </div>\n  Built with <a href=\"http://sphinx-doc.org/\">Sphinx</a> using a <a href=\"https://github.com/rtfd/sphinx_rtd_theme\">theme</a> provided by <a href=\"https://readthedocs.org\">Read the Docs</a>. \n\n</footer>\n\n        </div>\n      </div>\n\n    </section>\n\n  </div>\n  \n\n\n  <script type=\"text/javascript\">\n      jQuery(function () {\n          SphinxRtdTheme.Navigation.enable(true);\n      });\n  </script>\n\n  \n  \n    \n   \n\n</body>\n</html>"
  },
  {
    "path": "docs/_modules/snowboy/snowboydecoder.html",
    "content": "\n\n<!DOCTYPE html>\n<!--[if IE 8]><html class=\"no-js lt-ie9\" lang=\"zh-CN\" > <![endif]-->\n<!--[if gt IE 8]><!--> <html class=\"no-js\" lang=\"zh-CN\" > <!--<![endif]-->\n<head>\n  <meta charset=\"utf-8\">\n  \n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  \n  <title>snowboy.snowboydecoder &mdash; wukong-robot 1.2.0 文档</title>\n  \n\n  \n  \n  \n  \n\n  \n  <script type=\"text/javascript\" src=\"../../_static/js/modernizr.min.js\"></script>\n  \n    \n      <script type=\"text/javascript\" id=\"documentation_options\" data-url_root=\"../../\" src=\"../../_static/documentation_options.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/jquery.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/underscore.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/doctools.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/language_data.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/translations.js\"></script>\n    \n    <script type=\"text/javascript\" src=\"../../_static/js/theme.js\"></script>\n\n    \n\n  \n  <link rel=\"stylesheet\" href=\"../../_static/css/theme.css\" type=\"text/css\" />\n  <link rel=\"stylesheet\" href=\"../../_static/pygments.css\" type=\"text/css\" />\n    <link rel=\"index\" title=\"索引\" href=\"../../genindex.html\" />\n    <link rel=\"search\" title=\"搜索\" href=\"../../search.html\" /> \n</head>\n\n<body class=\"wy-body-for-nav\">\n\n   \n  <div class=\"wy-grid-for-nav\">\n    \n    <nav data-toggle=\"wy-nav-shift\" class=\"wy-nav-side\">\n      <div class=\"wy-side-scroll\">\n        <div class=\"wy-side-nav-search\" >\n          \n\n          \n            <a href=\"../../index.html\" class=\"icon icon-home\"> wukong-robot\n          \n\n          \n          </a>\n\n          \n            \n            \n          \n\n          \n<div role=\"search\">\n  <form id=\"rtd-search-form\" class=\"wy-form\" action=\"../../search.html\" method=\"get\">\n    <input type=\"text\" name=\"q\" placeholder=\"Search docs\" />\n    <input type=\"hidden\" name=\"check_keywords\" value=\"yes\" />\n    <input type=\"hidden\" name=\"area\" value=\"default\" />\n  </form>\n</div>\n\n          \n        </div>\n\n        <div class=\"wy-menu wy-menu-vertical\" data-spy=\"affix\" role=\"navigation\" aria-label=\"main navigation\">\n          \n            \n            \n              \n            \n            \n              <!-- Local TOC -->\n              <div class=\"local-toc\"></div>\n            \n          \n        </div>\n      </div>\n    </nav>\n\n    <section data-toggle=\"wy-nav-shift\" class=\"wy-nav-content-wrap\">\n\n      \n      <nav class=\"wy-nav-top\" aria-label=\"top navigation\">\n        \n          <i data-toggle=\"wy-nav-top\" class=\"fa fa-bars\"></i>\n          <a href=\"../../index.html\">wukong-robot</a>\n        \n      </nav>\n\n\n      <div class=\"wy-nav-content\">\n        \n        <div class=\"rst-content\">\n        \n          \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<div role=\"navigation\" aria-label=\"breadcrumbs navigation\">\n\n  <ul class=\"wy-breadcrumbs\">\n    \n      <li><a href=\"../../index.html\">Docs</a> &raquo;</li>\n        \n          <li><a href=\"../index.html\">模块代码</a> &raquo;</li>\n        \n      <li>snowboy.snowboydecoder</li>\n    \n    \n      <li class=\"wy-breadcrumbs-aside\">\n        \n      </li>\n    \n  </ul>\n\n  \n  <hr/>\n</div>\n          <div role=\"main\" class=\"document\" itemscope=\"itemscope\" itemtype=\"http://schema.org/Article\">\n           <div itemprop=\"articleBody\">\n            \n  <h1>snowboy.snowboydecoder 源代码</h1><div class=\"highlight\"><pre>\n<span></span><span class=\"ch\">#!/usr/bin/env python</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">collections</span>\n<span class=\"kn\">import</span> <span class=\"nn\">pyaudio</span>\n<span class=\"kn\">from</span> <span class=\"nn\">.</span> <span class=\"k\">import</span> <span class=\"n\">snowboydetect</span>\n<span class=\"kn\">from</span> <span class=\"nn\">robot</span> <span class=\"k\">import</span> <span class=\"n\">utils</span><span class=\"p\">,</span> <span class=\"n\">logging</span>\n<span class=\"kn\">import</span> <span class=\"nn\">time</span>\n<span class=\"kn\">import</span> <span class=\"nn\">wave</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">from</span> <span class=\"nn\">ctypes</span> <span class=\"k\">import</span> <span class=\"n\">CFUNCTYPE</span><span class=\"p\">,</span> <span class=\"n\">c_char_p</span><span class=\"p\">,</span> <span class=\"n\">c_int</span><span class=\"p\">,</span> <span class=\"n\">cdll</span>\n<span class=\"kn\">from</span> <span class=\"nn\">contextlib</span> <span class=\"k\">import</span> <span class=\"n\">contextmanager</span>\n<span class=\"kn\">from</span> <span class=\"nn\">robot</span> <span class=\"k\">import</span> <span class=\"n\">constants</span>\n\n\n<span class=\"n\">logger</span> <span class=\"o\">=</span> <span class=\"n\">logging</span><span class=\"o\">.</span><span class=\"n\">getLogger</span><span class=\"p\">(</span><span class=\"s2\">&quot;snowboy&quot;</span><span class=\"p\">)</span>\n<span class=\"n\">TOP_DIR</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">dirname</span><span class=\"p\">(</span><span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">abspath</span><span class=\"p\">(</span><span class=\"vm\">__file__</span><span class=\"p\">))</span>\n\n<span class=\"n\">RESOURCE_FILE</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">TOP_DIR</span><span class=\"p\">,</span> <span class=\"s2\">&quot;resources/common.res&quot;</span><span class=\"p\">)</span>\n<span class=\"n\">DETECT_DING</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">TOP_DIR</span><span class=\"p\">,</span> <span class=\"s2\">&quot;resources/ding.wav&quot;</span><span class=\"p\">)</span>\n<span class=\"n\">DETECT_DONG</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">TOP_DIR</span><span class=\"p\">,</span> <span class=\"s2\">&quot;resources/dong.wav&quot;</span><span class=\"p\">)</span>\n\n<div class=\"viewcode-block\" id=\"py_error_handler\"><a class=\"viewcode-back\" href=\"../../snowboy.html#snowboy.snowboydecoder.py_error_handler\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">py_error_handler</span><span class=\"p\">(</span><span class=\"n\">filename</span><span class=\"p\">,</span> <span class=\"n\">line</span><span class=\"p\">,</span> <span class=\"n\">function</span><span class=\"p\">,</span> <span class=\"n\">err</span><span class=\"p\">,</span> <span class=\"n\">fmt</span><span class=\"p\">):</span>\n    <span class=\"k\">pass</span></div>\n\n<span class=\"n\">ERROR_HANDLER_FUNC</span> <span class=\"o\">=</span> <span class=\"n\">CFUNCTYPE</span><span class=\"p\">(</span><span class=\"kc\">None</span><span class=\"p\">,</span> <span class=\"n\">c_char_p</span><span class=\"p\">,</span> <span class=\"n\">c_int</span><span class=\"p\">,</span> <span class=\"n\">c_char_p</span><span class=\"p\">,</span> <span class=\"n\">c_int</span><span class=\"p\">,</span> <span class=\"n\">c_char_p</span><span class=\"p\">)</span>\n\n<span class=\"n\">c_error_handler</span> <span class=\"o\">=</span> <span class=\"n\">ERROR_HANDLER_FUNC</span><span class=\"p\">(</span><span class=\"n\">py_error_handler</span><span class=\"p\">)</span>\n\n<div class=\"viewcode-block\" id=\"no_alsa_error\"><a class=\"viewcode-back\" href=\"../../snowboy.html#snowboy.snowboydecoder.no_alsa_error\">[文档]</a><span class=\"nd\">@contextmanager</span>\n<span class=\"k\">def</span> <span class=\"nf\">no_alsa_error</span><span class=\"p\">():</span>\n    <span class=\"k\">try</span><span class=\"p\">:</span>\n        <span class=\"n\">asound</span> <span class=\"o\">=</span> <span class=\"n\">cdll</span><span class=\"o\">.</span><span class=\"n\">LoadLibrary</span><span class=\"p\">(</span><span class=\"s1\">&#39;libasound.so&#39;</span><span class=\"p\">)</span>\n        <span class=\"n\">asound</span><span class=\"o\">.</span><span class=\"n\">snd_lib_error_set_handler</span><span class=\"p\">(</span><span class=\"n\">c_error_handler</span><span class=\"p\">)</span>\n        <span class=\"k\">yield</span>\n        <span class=\"n\">asound</span><span class=\"o\">.</span><span class=\"n\">snd_lib_error_set_handler</span><span class=\"p\">(</span><span class=\"kc\">None</span><span class=\"p\">)</span>\n    <span class=\"k\">except</span><span class=\"p\">:</span>\n        <span class=\"k\">yield</span>\n        <span class=\"k\">pass</span></div>\n\n<div class=\"viewcode-block\" id=\"RingBuffer\"><a class=\"viewcode-back\" href=\"../../snowboy.html#snowboy.snowboydecoder.RingBuffer\">[文档]</a><span class=\"k\">class</span> <span class=\"nc\">RingBuffer</span><span class=\"p\">(</span><span class=\"nb\">object</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;Ring buffer to hold audio from PortAudio&quot;&quot;&quot;</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">size</span><span class=\"o\">=</span><span class=\"mi\">4096</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_buf</span> <span class=\"o\">=</span> <span class=\"n\">collections</span><span class=\"o\">.</span><span class=\"n\">deque</span><span class=\"p\">(</span><span class=\"n\">maxlen</span><span class=\"o\">=</span><span class=\"n\">size</span><span class=\"p\">)</span>\n\n<div class=\"viewcode-block\" id=\"RingBuffer.extend\"><a class=\"viewcode-back\" href=\"../../snowboy.html#snowboy.snowboydecoder.RingBuffer.extend\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">extend</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">data</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;Adds data to the end of buffer&quot;&quot;&quot;</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_buf</span><span class=\"o\">.</span><span class=\"n\">extend</span><span class=\"p\">(</span><span class=\"n\">data</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"RingBuffer.get\"><a class=\"viewcode-back\" href=\"../../snowboy.html#snowboy.snowboydecoder.RingBuffer.get\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">get</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;Retrieves data from the beginning of buffer and clears it&quot;&quot;&quot;</span>\n        <span class=\"n\">tmp</span> <span class=\"o\">=</span> <span class=\"nb\">bytes</span><span class=\"p\">(</span><span class=\"nb\">bytearray</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_buf</span><span class=\"p\">))</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_buf</span><span class=\"o\">.</span><span class=\"n\">clear</span><span class=\"p\">()</span>\n        <span class=\"k\">return</span> <span class=\"n\">tmp</span></div></div>\n\n\n<div class=\"viewcode-block\" id=\"play_audio_file\"><a class=\"viewcode-back\" href=\"../../snowboy.html#snowboy.snowboydecoder.play_audio_file\">[文档]</a><span class=\"k\">def</span> <span class=\"nf\">play_audio_file</span><span class=\"p\">(</span><span class=\"n\">fname</span><span class=\"o\">=</span><span class=\"n\">DETECT_DING</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;Simple callback function to play a wave file. By default it plays</span>\n<span class=\"sd\">    a Ding sound.</span>\n\n<span class=\"sd\">    :param str fname: wave file name</span>\n<span class=\"sd\">    :return: None</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"n\">ding_wav</span> <span class=\"o\">=</span> <span class=\"n\">wave</span><span class=\"o\">.</span><span class=\"n\">open</span><span class=\"p\">(</span><span class=\"n\">fname</span><span class=\"p\">,</span> <span class=\"s1\">&#39;rb&#39;</span><span class=\"p\">)</span>\n    <span class=\"n\">ding_data</span> <span class=\"o\">=</span> <span class=\"n\">ding_wav</span><span class=\"o\">.</span><span class=\"n\">readframes</span><span class=\"p\">(</span><span class=\"n\">ding_wav</span><span class=\"o\">.</span><span class=\"n\">getnframes</span><span class=\"p\">())</span>\n    <span class=\"k\">with</span> <span class=\"n\">no_alsa_error</span><span class=\"p\">():</span>\n        <span class=\"n\">audio</span> <span class=\"o\">=</span> <span class=\"n\">pyaudio</span><span class=\"o\">.</span><span class=\"n\">PyAudio</span><span class=\"p\">()</span>\n    <span class=\"n\">stream_out</span> <span class=\"o\">=</span> <span class=\"n\">audio</span><span class=\"o\">.</span><span class=\"n\">open</span><span class=\"p\">(</span>\n        <span class=\"nb\">format</span><span class=\"o\">=</span><span class=\"n\">audio</span><span class=\"o\">.</span><span class=\"n\">get_format_from_width</span><span class=\"p\">(</span><span class=\"n\">ding_wav</span><span class=\"o\">.</span><span class=\"n\">getsampwidth</span><span class=\"p\">()),</span>\n        <span class=\"n\">channels</span><span class=\"o\">=</span><span class=\"n\">ding_wav</span><span class=\"o\">.</span><span class=\"n\">getnchannels</span><span class=\"p\">(),</span>\n        <span class=\"n\">rate</span><span class=\"o\">=</span><span class=\"n\">ding_wav</span><span class=\"o\">.</span><span class=\"n\">getframerate</span><span class=\"p\">(),</span> <span class=\"nb\">input</span><span class=\"o\">=</span><span class=\"kc\">False</span><span class=\"p\">,</span> <span class=\"n\">output</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">)</span>\n    <span class=\"n\">stream_out</span><span class=\"o\">.</span><span class=\"n\">start_stream</span><span class=\"p\">()</span>\n    <span class=\"n\">stream_out</span><span class=\"o\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"n\">ding_data</span><span class=\"p\">)</span>\n    <span class=\"n\">time</span><span class=\"o\">.</span><span class=\"n\">sleep</span><span class=\"p\">(</span><span class=\"mf\">0.2</span><span class=\"p\">)</span>\n    <span class=\"n\">stream_out</span><span class=\"o\">.</span><span class=\"n\">stop_stream</span><span class=\"p\">()</span>\n    <span class=\"n\">stream_out</span><span class=\"o\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n    <span class=\"n\">audio</span><span class=\"o\">.</span><span class=\"n\">terminate</span><span class=\"p\">()</span></div>\n\n\n<div class=\"viewcode-block\" id=\"ActiveListener\"><a class=\"viewcode-back\" href=\"../../snowboy.html#snowboy.snowboydecoder.ActiveListener\">[文档]</a><span class=\"k\">class</span> <span class=\"nc\">ActiveListener</span><span class=\"p\">(</span><span class=\"nb\">object</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot; Active Listening with VAD &quot;&quot;&quot;</span>\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">decoder_model</span><span class=\"p\">,</span>\n                 <span class=\"n\">resource</span><span class=\"o\">=</span><span class=\"n\">RESOURCE_FILE</span><span class=\"p\">):</span>\n        <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">debug</span><span class=\"p\">(</span><span class=\"s2\">&quot;activeListen __init__()&quot;</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">recordedData</span> <span class=\"o\">=</span> <span class=\"p\">[]</span>\n        <span class=\"n\">model_str</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;,&quot;</span><span class=\"o\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">decoder_model</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">detector</span> <span class=\"o\">=</span> <span class=\"n\">snowboydetect</span><span class=\"o\">.</span><span class=\"n\">SnowboyDetect</span><span class=\"p\">(</span>\n            <span class=\"n\">resource_filename</span><span class=\"o\">=</span><span class=\"n\">resource</span><span class=\"o\">.</span><span class=\"n\">encode</span><span class=\"p\">(),</span> <span class=\"n\">model_str</span><span class=\"o\">=</span><span class=\"n\">model_str</span><span class=\"o\">.</span><span class=\"n\">encode</span><span class=\"p\">())</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">ring_buffer</span> <span class=\"o\">=</span> <span class=\"n\">RingBuffer</span><span class=\"p\">(</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">detector</span><span class=\"o\">.</span><span class=\"n\">NumChannels</span><span class=\"p\">()</span> <span class=\"o\">*</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">detector</span><span class=\"o\">.</span><span class=\"n\">SampleRate</span><span class=\"p\">()</span> <span class=\"o\">*</span> <span class=\"mi\">5</span><span class=\"p\">)</span>\n\n<div class=\"viewcode-block\" id=\"ActiveListener.listen\"><a class=\"viewcode-back\" href=\"../../snowboy.html#snowboy.snowboydecoder.ActiveListener.listen\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">listen</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">interrupt_check</span><span class=\"o\">=</span><span class=\"k\">lambda</span><span class=\"p\">:</span> <span class=\"kc\">False</span><span class=\"p\">,</span> <span class=\"n\">sleep_time</span><span class=\"o\">=</span><span class=\"mf\">0.03</span><span class=\"p\">,</span> <span class=\"n\">silent_count_threshold</span><span class=\"o\">=</span><span class=\"mi\">15</span><span class=\"p\">,</span> <span class=\"n\">recording_timeout</span><span class=\"o\">=</span><span class=\"mi\">100</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        :param interrupt_check: a function that returns True if the main loop</span>\n<span class=\"sd\">                                needs to stop.</span>\n<span class=\"sd\">        :param silent_count_threshold: indicates how long silence must be heard</span>\n<span class=\"sd\">                                       to mark the end of a phrase that is</span>\n<span class=\"sd\">                                       being recorded.</span>\n<span class=\"sd\">        :param float sleep_time: how much time in second every loop waits.</span>\n<span class=\"sd\">        :param recording_timeout: limits the maximum length of a recording.</span>\n<span class=\"sd\">        :return: recorded file path</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">debug</span><span class=\"p\">(</span><span class=\"s2\">&quot;activeListen listen()&quot;</span><span class=\"p\">)</span>\n\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_running</span> <span class=\"o\">=</span> <span class=\"kc\">True</span>\n\n        <span class=\"k\">def</span> <span class=\"nf\">audio_callback</span><span class=\"p\">(</span><span class=\"n\">in_data</span><span class=\"p\">,</span> <span class=\"n\">frame_count</span><span class=\"p\">,</span> <span class=\"n\">time_info</span><span class=\"p\">,</span> <span class=\"n\">status</span><span class=\"p\">):</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">ring_buffer</span><span class=\"o\">.</span><span class=\"n\">extend</span><span class=\"p\">(</span><span class=\"n\">in_data</span><span class=\"p\">)</span>\n            <span class=\"n\">play_data</span> <span class=\"o\">=</span> <span class=\"nb\">chr</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">in_data</span><span class=\"p\">)</span>\n            <span class=\"k\">return</span> <span class=\"n\">play_data</span><span class=\"p\">,</span> <span class=\"n\">pyaudio</span><span class=\"o\">.</span><span class=\"n\">paContinue</span>\n\n        <span class=\"k\">with</span> <span class=\"n\">no_alsa_error</span><span class=\"p\">():</span>            \n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">audio</span> <span class=\"o\">=</span> <span class=\"n\">pyaudio</span><span class=\"o\">.</span><span class=\"n\">PyAudio</span><span class=\"p\">()</span>\n        \n        <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">debug</span><span class=\"p\">(</span><span class=\"s1\">&#39;opening audio stream&#39;</span><span class=\"p\">)</span>\n\n        <span class=\"k\">try</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">stream_in</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">audio</span><span class=\"o\">.</span><span class=\"n\">open</span><span class=\"p\">(</span>\n                <span class=\"nb\">input</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">,</span> <span class=\"n\">output</span><span class=\"o\">=</span><span class=\"kc\">False</span><span class=\"p\">,</span>\n                <span class=\"nb\">format</span><span class=\"o\">=</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">audio</span><span class=\"o\">.</span><span class=\"n\">get_format_from_width</span><span class=\"p\">(</span>\n                    <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">detector</span><span class=\"o\">.</span><span class=\"n\">BitsPerSample</span><span class=\"p\">()</span> <span class=\"o\">/</span> <span class=\"mi\">8</span><span class=\"p\">),</span>\n                <span class=\"n\">channels</span><span class=\"o\">=</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">detector</span><span class=\"o\">.</span><span class=\"n\">NumChannels</span><span class=\"p\">(),</span>\n                <span class=\"n\">rate</span><span class=\"o\">=</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">detector</span><span class=\"o\">.</span><span class=\"n\">SampleRate</span><span class=\"p\">(),</span>\n                <span class=\"n\">frames_per_buffer</span><span class=\"o\">=</span><span class=\"mi\">2048</span><span class=\"p\">,</span>\n                <span class=\"n\">stream_callback</span><span class=\"o\">=</span><span class=\"n\">audio_callback</span><span class=\"p\">)</span>\n        <span class=\"k\">except</span> <span class=\"ne\">Exception</span> <span class=\"k\">as</span> <span class=\"n\">e</span><span class=\"p\">:</span>\n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">critical</span><span class=\"p\">(</span><span class=\"n\">e</span><span class=\"p\">)</span>\n            <span class=\"k\">return</span> \n\n        <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">debug</span><span class=\"p\">(</span><span class=\"s1\">&#39;audio stream opened&#39;</span><span class=\"p\">)</span>\n\n        <span class=\"k\">if</span> <span class=\"n\">interrupt_check</span><span class=\"p\">():</span>\n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">debug</span><span class=\"p\">(</span><span class=\"s2\">&quot;detect voice return&quot;</span><span class=\"p\">)</span>\n            <span class=\"k\">return</span>\n\n        <span class=\"n\">silentCount</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n        <span class=\"n\">recordingCount</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n\n        <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">debug</span><span class=\"p\">(</span><span class=\"s2\">&quot;begin activeListen loop&quot;</span><span class=\"p\">)</span>\n        \n        <span class=\"k\">while</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_running</span> <span class=\"ow\">is</span> <span class=\"kc\">True</span><span class=\"p\">:</span>\n\n            <span class=\"k\">if</span> <span class=\"n\">interrupt_check</span><span class=\"p\">():</span>\n                <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">debug</span><span class=\"p\">(</span><span class=\"s2\">&quot;detect voice break&quot;</span><span class=\"p\">)</span>\n                <span class=\"k\">break</span>\n            <span class=\"n\">data</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">ring_buffer</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">()</span>\n            <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">data</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n                <span class=\"n\">time</span><span class=\"o\">.</span><span class=\"n\">sleep</span><span class=\"p\">(</span><span class=\"n\">sleep_time</span><span class=\"p\">)</span>\n                <span class=\"k\">continue</span>\n            \n            <span class=\"n\">status</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">detector</span><span class=\"o\">.</span><span class=\"n\">RunDetection</span><span class=\"p\">(</span><span class=\"n\">data</span><span class=\"p\">)</span>\n            <span class=\"k\">if</span> <span class=\"n\">status</span> <span class=\"o\">==</span> <span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">:</span>\n                <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">warning</span><span class=\"p\">(</span><span class=\"s2\">&quot;Error initializing streams or reading audio data&quot;</span><span class=\"p\">)</span>\n                \n            <span class=\"n\">stopRecording</span> <span class=\"o\">=</span> <span class=\"kc\">False</span>\n            <span class=\"k\">if</span> <span class=\"n\">recordingCount</span> <span class=\"o\">&gt;</span> <span class=\"n\">recording_timeout</span><span class=\"p\">:</span>\n                <span class=\"n\">stopRecording</span> <span class=\"o\">=</span> <span class=\"kc\">True</span>\n            <span class=\"k\">elif</span> <span class=\"n\">status</span> <span class=\"o\">==</span> <span class=\"o\">-</span><span class=\"mi\">2</span><span class=\"p\">:</span> <span class=\"c1\">#silence found</span>\n                <span class=\"k\">if</span> <span class=\"n\">silentCount</span> <span class=\"o\">&gt;</span> <span class=\"n\">silent_count_threshold</span><span class=\"p\">:</span>\n                    <span class=\"n\">stopRecording</span> <span class=\"o\">=</span> <span class=\"kc\">True</span>\n                <span class=\"k\">else</span><span class=\"p\">:</span>\n                    <span class=\"n\">silentCount</span> <span class=\"o\">=</span> <span class=\"n\">silentCount</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n            <span class=\"k\">elif</span> <span class=\"n\">status</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span> <span class=\"c1\">#voice found</span>\n                <span class=\"n\">silentCount</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n\n            <span class=\"k\">if</span> <span class=\"n\">stopRecording</span> <span class=\"o\">==</span> <span class=\"kc\">True</span><span class=\"p\">:</span>\n                <span class=\"k\">return</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">saveMessage</span><span class=\"p\">()</span>\n\n            <span class=\"n\">recordingCount</span> <span class=\"o\">=</span> <span class=\"n\">recordingCount</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">recordedData</span><span class=\"o\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">data</span><span class=\"p\">)</span>\n\n        <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">debug</span><span class=\"p\">(</span><span class=\"s2\">&quot;finished.&quot;</span><span class=\"p\">)</span></div>\n\n\n<div class=\"viewcode-block\" id=\"ActiveListener.saveMessage\"><a class=\"viewcode-back\" href=\"../../snowboy.html#snowboy.snowboydecoder.ActiveListener.saveMessage\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">saveMessage</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Save the message stored in self.recordedData to a timestamped file.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"n\">filename</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">constants</span><span class=\"o\">.</span><span class=\"n\">TEMP_PATH</span><span class=\"p\">,</span> <span class=\"s1\">&#39;output&#39;</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"o\">.</span><span class=\"n\">time</span><span class=\"p\">()))</span> <span class=\"o\">+</span> <span class=\"s1\">&#39;.wav&#39;</span><span class=\"p\">)</span>\n        <span class=\"n\">data</span> <span class=\"o\">=</span> <span class=\"sa\">b</span><span class=\"s1\">&#39;&#39;</span><span class=\"o\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">recordedData</span><span class=\"p\">)</span>\n\n        <span class=\"c1\">#use wave to save data</span>\n        <span class=\"n\">wf</span> <span class=\"o\">=</span> <span class=\"n\">wave</span><span class=\"o\">.</span><span class=\"n\">open</span><span class=\"p\">(</span><span class=\"n\">filename</span><span class=\"p\">,</span> <span class=\"s1\">&#39;wb&#39;</span><span class=\"p\">)</span>\n        <span class=\"n\">wf</span><span class=\"o\">.</span><span class=\"n\">setnchannels</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">detector</span><span class=\"o\">.</span><span class=\"n\">NumChannels</span><span class=\"p\">())</span>\n        <span class=\"n\">wf</span><span class=\"o\">.</span><span class=\"n\">setsampwidth</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">audio</span><span class=\"o\">.</span><span class=\"n\">get_sample_size</span><span class=\"p\">(</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">audio</span><span class=\"o\">.</span><span class=\"n\">get_format_from_width</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">detector</span><span class=\"o\">.</span><span class=\"n\">BitsPerSample</span><span class=\"p\">()</span> <span class=\"o\">/</span> <span class=\"mi\">8</span><span class=\"p\">)))</span>\n        <span class=\"n\">wf</span><span class=\"o\">.</span><span class=\"n\">setframerate</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">detector</span><span class=\"o\">.</span><span class=\"n\">SampleRate</span><span class=\"p\">())</span>\n        <span class=\"n\">wf</span><span class=\"o\">.</span><span class=\"n\">writeframes</span><span class=\"p\">(</span><span class=\"n\">data</span><span class=\"p\">)</span>\n        <span class=\"n\">wf</span><span class=\"o\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n        <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">debug</span><span class=\"p\">(</span><span class=\"s2\">&quot;finished saving: &quot;</span> <span class=\"o\">+</span> <span class=\"n\">filename</span><span class=\"p\">)</span>\n\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">stream_in</span><span class=\"o\">.</span><span class=\"n\">stop_stream</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">stream_in</span><span class=\"o\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">audio</span><span class=\"o\">.</span><span class=\"n\">terminate</span><span class=\"p\">()</span>\n        \n        <span class=\"k\">return</span> <span class=\"n\">filename</span></div></div>\n    \n    \n\n\n<div class=\"viewcode-block\" id=\"HotwordDetector\"><a class=\"viewcode-back\" href=\"../../snowboy.html#snowboy.snowboydecoder.HotwordDetector\">[文档]</a><span class=\"k\">class</span> <span class=\"nc\">HotwordDetector</span><span class=\"p\">(</span><span class=\"nb\">object</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    Snowboy decoder to detect whether a keyword specified by `decoder_model`</span>\n<span class=\"sd\">    exists in a microphone input stream.</span>\n\n<span class=\"sd\">    :param decoder_model: decoder model file path, a string or a list of strings</span>\n<span class=\"sd\">    :param resource: resource file path.</span>\n<span class=\"sd\">    :param sensitivity: decoder sensitivity, a float of a list of floats.</span>\n<span class=\"sd\">                              The bigger the value, the more senstive the</span>\n<span class=\"sd\">                              decoder. If an empty list is provided, then the</span>\n<span class=\"sd\">                              default sensitivity in the model will be used.</span>\n<span class=\"sd\">    :param audio_gain: multiply input volume by this factor.</span>\n<span class=\"sd\">    :param apply_frontend: applies the frontend processing algorithm if True.</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">decoder_model</span><span class=\"p\">,</span>\n                 <span class=\"n\">resource</span><span class=\"o\">=</span><span class=\"n\">RESOURCE_FILE</span><span class=\"p\">,</span>\n                 <span class=\"n\">sensitivity</span><span class=\"o\">=</span><span class=\"p\">[],</span>\n                 <span class=\"n\">audio_gain</span><span class=\"o\">=</span><span class=\"mi\">1</span><span class=\"p\">,</span>\n                 <span class=\"n\">apply_frontend</span><span class=\"o\">=</span><span class=\"kc\">False</span><span class=\"p\">):</span>\n\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_running</span> <span class=\"o\">=</span> <span class=\"kc\">False</span>\n\n        <span class=\"n\">tm</span> <span class=\"o\">=</span> <span class=\"nb\">type</span><span class=\"p\">(</span><span class=\"n\">decoder_model</span><span class=\"p\">)</span>\n        <span class=\"n\">ts</span> <span class=\"o\">=</span> <span class=\"nb\">type</span><span class=\"p\">(</span><span class=\"n\">sensitivity</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">tm</span> <span class=\"ow\">is</span> <span class=\"ow\">not</span> <span class=\"nb\">list</span><span class=\"p\">:</span>\n            <span class=\"n\">decoder_model</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">decoder_model</span><span class=\"p\">]</span>\n        <span class=\"k\">if</span> <span class=\"n\">ts</span> <span class=\"ow\">is</span> <span class=\"ow\">not</span> <span class=\"nb\">list</span><span class=\"p\">:</span>\n            <span class=\"n\">sensitivity</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">sensitivity</span><span class=\"p\">]</span>\n        <span class=\"n\">model_str</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;,&quot;</span><span class=\"o\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">decoder_model</span><span class=\"p\">)</span>\n\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">detector</span> <span class=\"o\">=</span> <span class=\"n\">snowboydetect</span><span class=\"o\">.</span><span class=\"n\">SnowboyDetect</span><span class=\"p\">(</span>\n            <span class=\"n\">resource_filename</span><span class=\"o\">=</span><span class=\"n\">resource</span><span class=\"o\">.</span><span class=\"n\">encode</span><span class=\"p\">(),</span> <span class=\"n\">model_str</span><span class=\"o\">=</span><span class=\"n\">model_str</span><span class=\"o\">.</span><span class=\"n\">encode</span><span class=\"p\">())</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">detector</span><span class=\"o\">.</span><span class=\"n\">SetAudioGain</span><span class=\"p\">(</span><span class=\"n\">audio_gain</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">detector</span><span class=\"o\">.</span><span class=\"n\">ApplyFrontend</span><span class=\"p\">(</span><span class=\"n\">apply_frontend</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">num_hotwords</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">detector</span><span class=\"o\">.</span><span class=\"n\">NumHotwords</span><span class=\"p\">()</span>\n\n        <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">decoder_model</span><span class=\"p\">)</span> <span class=\"o\">&gt;</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">sensitivity</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">1</span><span class=\"p\">:</span>\n            <span class=\"n\">sensitivity</span> <span class=\"o\">=</span> <span class=\"n\">sensitivity</span> <span class=\"o\">*</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">num_hotwords</span>\n        <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">sensitivity</span><span class=\"p\">)</span> <span class=\"o\">!=</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"k\">assert</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">num_hotwords</span> <span class=\"o\">==</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">sensitivity</span><span class=\"p\">),</span> \\\n                <span class=\"s2\">&quot;number of hotwords in decoder_model (</span><span class=\"si\">%d</span><span class=\"s2\">) and sensitivity &quot;</span> \\\n                <span class=\"s2\">&quot;(</span><span class=\"si\">%d</span><span class=\"s2\">) does not match&quot;</span> <span class=\"o\">%</span> <span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">num_hotwords</span><span class=\"p\">,</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">sensitivity</span><span class=\"p\">))</span>\n        <span class=\"n\">sensitivity_str</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;,&quot;</span><span class=\"o\">.</span><span class=\"n\">join</span><span class=\"p\">([</span><span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">t</span><span class=\"p\">)</span> <span class=\"k\">for</span> <span class=\"n\">t</span> <span class=\"ow\">in</span> <span class=\"n\">sensitivity</span><span class=\"p\">])</span>\n        <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">sensitivity</span><span class=\"p\">)</span> <span class=\"o\">!=</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">detector</span><span class=\"o\">.</span><span class=\"n\">SetSensitivity</span><span class=\"p\">(</span><span class=\"n\">sensitivity_str</span><span class=\"o\">.</span><span class=\"n\">encode</span><span class=\"p\">())</span>        \n\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">ring_buffer</span> <span class=\"o\">=</span> <span class=\"n\">RingBuffer</span><span class=\"p\">(</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">detector</span><span class=\"o\">.</span><span class=\"n\">NumChannels</span><span class=\"p\">()</span> <span class=\"o\">*</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">detector</span><span class=\"o\">.</span><span class=\"n\">SampleRate</span><span class=\"p\">()</span> <span class=\"o\">*</span> <span class=\"mi\">5</span><span class=\"p\">)</span>\n\n<div class=\"viewcode-block\" id=\"HotwordDetector.start\"><a class=\"viewcode-back\" href=\"../../snowboy.html#snowboy.snowboydecoder.HotwordDetector.start\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">start</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">detected_callback</span><span class=\"o\">=</span><span class=\"n\">play_audio_file</span><span class=\"p\">,</span>\n              <span class=\"n\">interrupt_check</span><span class=\"o\">=</span><span class=\"k\">lambda</span><span class=\"p\">:</span> <span class=\"kc\">False</span><span class=\"p\">,</span>\n              <span class=\"n\">sleep_time</span><span class=\"o\">=</span><span class=\"mf\">0.03</span><span class=\"p\">,</span>\n              <span class=\"n\">audio_recorder_callback</span><span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">,</span>\n              <span class=\"n\">silent_count_threshold</span><span class=\"o\">=</span><span class=\"mi\">15</span><span class=\"p\">,</span>\n              <span class=\"n\">recording_timeout</span><span class=\"o\">=</span><span class=\"mi\">100</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Start the voice detector. For every `sleep_time` second it checks the</span>\n<span class=\"sd\">        audio buffer for triggering keywords. If detected, then call</span>\n<span class=\"sd\">        corresponding function in `detected_callback`, which can be a single</span>\n<span class=\"sd\">        function (single model) or a list of callback functions (multiple</span>\n<span class=\"sd\">        models). Every loop it also calls `interrupt_check` -- if it returns</span>\n<span class=\"sd\">        True, then breaks from the loop and return.</span>\n\n<span class=\"sd\">        :param detected_callback: a function or list of functions. The number of</span>\n<span class=\"sd\">                                  items must match the number of models in</span>\n<span class=\"sd\">                                  `decoder_model`.</span>\n<span class=\"sd\">        :param interrupt_check: a function that returns True if the main loop</span>\n<span class=\"sd\">                                needs to stop.</span>\n<span class=\"sd\">        :param float sleep_time: how much time in second every loop waits.</span>\n<span class=\"sd\">        :param audio_recorder_callback: if specified, this will be called after</span>\n<span class=\"sd\">                                        a keyword has been spoken and after the</span>\n<span class=\"sd\">                                        phrase immediately after the keyword has</span>\n<span class=\"sd\">                                        been recorded. The function will be</span>\n<span class=\"sd\">                                        passed the name of the file where the</span>\n<span class=\"sd\">                                        phrase was recorded.</span>\n<span class=\"sd\">        :param silent_count_threshold: indicates how long silence must be heard</span>\n<span class=\"sd\">                                       to mark the end of a phrase that is</span>\n<span class=\"sd\">                                       being recorded.</span>\n<span class=\"sd\">        :param recording_timeout: limits the maximum length of a recording.</span>\n<span class=\"sd\">        :return: None</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_running</span> <span class=\"o\">=</span> <span class=\"kc\">True</span>\n\n        <span class=\"k\">def</span> <span class=\"nf\">audio_callback</span><span class=\"p\">(</span><span class=\"n\">in_data</span><span class=\"p\">,</span> <span class=\"n\">frame_count</span><span class=\"p\">,</span> <span class=\"n\">time_info</span><span class=\"p\">,</span> <span class=\"n\">status</span><span class=\"p\">):</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">ring_buffer</span><span class=\"o\">.</span><span class=\"n\">extend</span><span class=\"p\">(</span><span class=\"n\">in_data</span><span class=\"p\">)</span>\n            <span class=\"n\">play_data</span> <span class=\"o\">=</span> <span class=\"nb\">chr</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">in_data</span><span class=\"p\">)</span>\n            <span class=\"k\">return</span> <span class=\"n\">play_data</span><span class=\"p\">,</span> <span class=\"n\">pyaudio</span><span class=\"o\">.</span><span class=\"n\">paContinue</span>\n\n        <span class=\"k\">with</span> <span class=\"n\">no_alsa_error</span><span class=\"p\">():</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">audio</span> <span class=\"o\">=</span> <span class=\"n\">pyaudio</span><span class=\"o\">.</span><span class=\"n\">PyAudio</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">stream_in</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">audio</span><span class=\"o\">.</span><span class=\"n\">open</span><span class=\"p\">(</span>\n            <span class=\"nb\">input</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">,</span> <span class=\"n\">output</span><span class=\"o\">=</span><span class=\"kc\">False</span><span class=\"p\">,</span>\n            <span class=\"nb\">format</span><span class=\"o\">=</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">audio</span><span class=\"o\">.</span><span class=\"n\">get_format_from_width</span><span class=\"p\">(</span>\n                <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">detector</span><span class=\"o\">.</span><span class=\"n\">BitsPerSample</span><span class=\"p\">()</span> <span class=\"o\">/</span> <span class=\"mi\">8</span><span class=\"p\">),</span>\n            <span class=\"n\">channels</span><span class=\"o\">=</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">detector</span><span class=\"o\">.</span><span class=\"n\">NumChannels</span><span class=\"p\">(),</span>\n            <span class=\"n\">rate</span><span class=\"o\">=</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">detector</span><span class=\"o\">.</span><span class=\"n\">SampleRate</span><span class=\"p\">(),</span>\n            <span class=\"n\">frames_per_buffer</span><span class=\"o\">=</span><span class=\"mi\">2048</span><span class=\"p\">,</span>\n            <span class=\"n\">stream_callback</span><span class=\"o\">=</span><span class=\"n\">audio_callback</span><span class=\"p\">)</span>\n\n        <span class=\"k\">if</span> <span class=\"n\">interrupt_check</span><span class=\"p\">():</span>\n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">debug</span><span class=\"p\">(</span><span class=\"s2\">&quot;detect voice return&quot;</span><span class=\"p\">)</span>\n            <span class=\"k\">return</span>\n\n        <span class=\"n\">tc</span> <span class=\"o\">=</span> <span class=\"nb\">type</span><span class=\"p\">(</span><span class=\"n\">detected_callback</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">tc</span> <span class=\"ow\">is</span> <span class=\"ow\">not</span> <span class=\"nb\">list</span><span class=\"p\">:</span>\n            <span class=\"n\">detected_callback</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">detected_callback</span><span class=\"p\">]</span>\n        <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">detected_callback</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">num_hotwords</span> <span class=\"o\">&gt;</span> <span class=\"mi\">1</span><span class=\"p\">:</span>\n            <span class=\"n\">detected_callback</span> <span class=\"o\">*=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">num_hotwords</span>\n\n        <span class=\"k\">assert</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">num_hotwords</span> <span class=\"o\">==</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">detected_callback</span><span class=\"p\">),</span> \\\n            <span class=\"s2\">&quot;Error: hotwords in your models (</span><span class=\"si\">%d</span><span class=\"s2\">) do not match the number of &quot;</span> \\\n            <span class=\"s2\">&quot;callbacks (</span><span class=\"si\">%d</span><span class=\"s2\">)&quot;</span> <span class=\"o\">%</span> <span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">num_hotwords</span><span class=\"p\">,</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">detected_callback</span><span class=\"p\">))</span>\n\n        <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">debug</span><span class=\"p\">(</span><span class=\"s2\">&quot;detecting...&quot;</span><span class=\"p\">)</span>\n\n        <span class=\"n\">state</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;PASSIVE&quot;</span>\n        <span class=\"k\">while</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_running</span> <span class=\"ow\">is</span> <span class=\"kc\">True</span><span class=\"p\">:</span>            \n            <span class=\"k\">if</span> <span class=\"n\">interrupt_check</span><span class=\"p\">():</span>\n                <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">debug</span><span class=\"p\">(</span><span class=\"s2\">&quot;detect voice break&quot;</span><span class=\"p\">)</span>\n                <span class=\"k\">break</span>\n            <span class=\"n\">data</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">ring_buffer</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">()</span>\n            <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">data</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n                <span class=\"n\">time</span><span class=\"o\">.</span><span class=\"n\">sleep</span><span class=\"p\">(</span><span class=\"n\">sleep_time</span><span class=\"p\">)</span>\n                <span class=\"k\">continue</span>\n\n            <span class=\"n\">status</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">detector</span><span class=\"o\">.</span><span class=\"n\">RunDetection</span><span class=\"p\">(</span><span class=\"n\">data</span><span class=\"p\">)</span>\n            <span class=\"k\">if</span> <span class=\"n\">status</span> <span class=\"o\">==</span> <span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">:</span>\n                <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">warning</span><span class=\"p\">(</span><span class=\"s2\">&quot;Error initializing streams or reading audio data&quot;</span><span class=\"p\">)</span>\n\n            <span class=\"c1\">#small state machine to handle recording of phrase after keyword</span>\n            <span class=\"k\">if</span> <span class=\"n\">state</span> <span class=\"o\">==</span> <span class=\"s2\">&quot;PASSIVE&quot;</span><span class=\"p\">:</span>\n                <span class=\"k\">if</span> <span class=\"n\">status</span> <span class=\"o\">&gt;</span> <span class=\"mi\">0</span><span class=\"p\">:</span> <span class=\"c1\">#key word found</span>\n\n                    <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">recordedData</span> <span class=\"o\">=</span> <span class=\"p\">[]</span>\n                    <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">recordedData</span><span class=\"o\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">data</span><span class=\"p\">)</span>\n                    <span class=\"n\">silentCount</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n                    <span class=\"n\">recordingCount</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n                    <span class=\"n\">message</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;Keyword &quot;</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">status</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"s2\">&quot; detected at time: &quot;</span>\n                    <span class=\"n\">message</span> <span class=\"o\">+=</span> <span class=\"n\">time</span><span class=\"o\">.</span><span class=\"n\">strftime</span><span class=\"p\">(</span><span class=\"s2\">&quot;%Y-%m-</span><span class=\"si\">%d</span><span class=\"s2\"> %H:%M:%S&quot;</span><span class=\"p\">,</span>\n                                         <span class=\"n\">time</span><span class=\"o\">.</span><span class=\"n\">localtime</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"o\">.</span><span class=\"n\">time</span><span class=\"p\">()))</span>\n                    <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"n\">message</span><span class=\"p\">)</span>\n                    <span class=\"n\">callback</span> <span class=\"o\">=</span> <span class=\"n\">detected_callback</span><span class=\"p\">[</span><span class=\"n\">status</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">]</span>                    \n                    <span class=\"k\">if</span> <span class=\"n\">callback</span> <span class=\"ow\">is</span> <span class=\"ow\">not</span> <span class=\"kc\">None</span><span class=\"p\">:</span>\n                        <span class=\"n\">callback</span><span class=\"p\">()</span>\n\n                    <span class=\"k\">if</span> <span class=\"n\">audio_recorder_callback</span> <span class=\"ow\">is</span> <span class=\"ow\">not</span> <span class=\"kc\">None</span> <span class=\"ow\">and</span> <span class=\"n\">status</span> <span class=\"o\">==</span> <span class=\"mi\">1</span> <span class=\"ow\">and</span> <span class=\"n\">utils</span><span class=\"o\">.</span><span class=\"n\">is_proper_time</span><span class=\"p\">():</span>\n                        <span class=\"n\">state</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;ACTIVE&quot;</span>\n                    <span class=\"k\">continue</span>\n\n            <span class=\"k\">elif</span> <span class=\"n\">state</span> <span class=\"o\">==</span> <span class=\"s2\">&quot;ACTIVE&quot;</span><span class=\"p\">:</span>\n                <span class=\"n\">stopRecording</span> <span class=\"o\">=</span> <span class=\"kc\">False</span>\n                <span class=\"k\">if</span> <span class=\"n\">recordingCount</span> <span class=\"o\">&gt;</span> <span class=\"n\">recording_timeout</span><span class=\"p\">:</span>\n                    <span class=\"n\">stopRecording</span> <span class=\"o\">=</span> <span class=\"kc\">True</span>\n                <span class=\"k\">elif</span> <span class=\"n\">status</span> <span class=\"o\">==</span> <span class=\"o\">-</span><span class=\"mi\">2</span><span class=\"p\">:</span> <span class=\"c1\">#silence found</span>\n                    <span class=\"k\">if</span> <span class=\"n\">silentCount</span> <span class=\"o\">&gt;</span> <span class=\"n\">silent_count_threshold</span><span class=\"p\">:</span>\n                        <span class=\"n\">stopRecording</span> <span class=\"o\">=</span> <span class=\"kc\">True</span>\n                    <span class=\"k\">else</span><span class=\"p\">:</span>\n                        <span class=\"n\">silentCount</span> <span class=\"o\">=</span> <span class=\"n\">silentCount</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n                <span class=\"k\">elif</span> <span class=\"n\">status</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span> <span class=\"c1\">#voice found</span>\n                    <span class=\"n\">silentCount</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n\n                <span class=\"k\">if</span> <span class=\"n\">stopRecording</span> <span class=\"o\">==</span> <span class=\"kc\">True</span><span class=\"p\">:</span>\n                    <span class=\"n\">fname</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">saveMessage</span><span class=\"p\">()</span>\n                    <span class=\"n\">audio_recorder_callback</span><span class=\"p\">(</span><span class=\"n\">fname</span><span class=\"p\">)</span>\n                    <span class=\"n\">state</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;PASSIVE&quot;</span>                    \n                    <span class=\"k\">continue</span>\n\n                <span class=\"n\">recordingCount</span> <span class=\"o\">=</span> <span class=\"n\">recordingCount</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n                <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">recordedData</span><span class=\"o\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">data</span><span class=\"p\">)</span>                \n\n        <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">debug</span><span class=\"p\">(</span><span class=\"s2\">&quot;finished.&quot;</span><span class=\"p\">)</span></div>\n\n\n<div class=\"viewcode-block\" id=\"HotwordDetector.saveMessage\"><a class=\"viewcode-back\" href=\"../../snowboy.html#snowboy.snowboydecoder.HotwordDetector.saveMessage\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">saveMessage</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Save the message stored in self.recordedData to a timestamped file.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"n\">filename</span> <span class=\"o\">=</span> <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"n\">constants</span><span class=\"o\">.</span><span class=\"n\">TEMP_PATH</span><span class=\"p\">,</span> <span class=\"s1\">&#39;output&#39;</span> <span class=\"o\">+</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">time</span><span class=\"o\">.</span><span class=\"n\">time</span><span class=\"p\">()))</span> <span class=\"o\">+</span> <span class=\"s1\">&#39;.wav&#39;</span><span class=\"p\">)</span>\n        <span class=\"n\">data</span> <span class=\"o\">=</span> <span class=\"sa\">b</span><span class=\"s1\">&#39;&#39;</span><span class=\"o\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">recordedData</span><span class=\"p\">)</span>\n\n        <span class=\"c1\">#use wave to save data</span>\n        <span class=\"n\">wf</span> <span class=\"o\">=</span> <span class=\"n\">wave</span><span class=\"o\">.</span><span class=\"n\">open</span><span class=\"p\">(</span><span class=\"n\">filename</span><span class=\"p\">,</span> <span class=\"s1\">&#39;wb&#39;</span><span class=\"p\">)</span>\n        <span class=\"n\">wf</span><span class=\"o\">.</span><span class=\"n\">setnchannels</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">detector</span><span class=\"o\">.</span><span class=\"n\">NumChannels</span><span class=\"p\">())</span>\n        <span class=\"n\">wf</span><span class=\"o\">.</span><span class=\"n\">setsampwidth</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">audio</span><span class=\"o\">.</span><span class=\"n\">get_sample_size</span><span class=\"p\">(</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">audio</span><span class=\"o\">.</span><span class=\"n\">get_format_from_width</span><span class=\"p\">(</span>\n                <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">detector</span><span class=\"o\">.</span><span class=\"n\">BitsPerSample</span><span class=\"p\">()</span> <span class=\"o\">/</span> <span class=\"mi\">8</span><span class=\"p\">)))</span>\n        <span class=\"n\">wf</span><span class=\"o\">.</span><span class=\"n\">setframerate</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">detector</span><span class=\"o\">.</span><span class=\"n\">SampleRate</span><span class=\"p\">())</span>\n        <span class=\"n\">wf</span><span class=\"o\">.</span><span class=\"n\">writeframes</span><span class=\"p\">(</span><span class=\"n\">data</span><span class=\"p\">)</span>\n        <span class=\"n\">wf</span><span class=\"o\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n        <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">debug</span><span class=\"p\">(</span><span class=\"s2\">&quot;finished saving: &quot;</span> <span class=\"o\">+</span> <span class=\"n\">filename</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span> <span class=\"n\">filename</span></div>\n\n<div class=\"viewcode-block\" id=\"HotwordDetector.terminate\"><a class=\"viewcode-back\" href=\"../../snowboy.html#snowboy.snowboydecoder.HotwordDetector.terminate\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">terminate</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Terminate audio stream. Users can call start() again to detect.</span>\n<span class=\"sd\">        :return: None</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_running</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">stream_in</span><span class=\"o\">.</span><span class=\"n\">stop_stream</span><span class=\"p\">()</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">stream_in</span><span class=\"o\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">audio</span><span class=\"o\">.</span><span class=\"n\">terminate</span><span class=\"p\">()</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_running</span> <span class=\"o\">=</span> <span class=\"kc\">False</span></div></div>\n</pre></div>\n\n           </div>\n           \n          </div>\n          <footer>\n  \n\n  <hr/>\n\n  <div role=\"contentinfo\">\n    <p>\n        &copy; Copyright 2019, wzpan\n\n    </p>\n  </div>\n  Built with <a href=\"http://sphinx-doc.org/\">Sphinx</a> using a <a href=\"https://github.com/rtfd/sphinx_rtd_theme\">theme</a> provided by <a href=\"https://readthedocs.org\">Read the Docs</a>. \n\n</footer>\n\n        </div>\n      </div>\n\n    </section>\n\n  </div>\n  \n\n\n  <script type=\"text/javascript\">\n      jQuery(function () {\n          SphinxRtdTheme.Navigation.enable(true);\n      });\n  </script>\n\n  \n  \n    \n   \n\n</body>\n</html>"
  },
  {
    "path": "docs/_modules/snowboy/snowboydetect.html",
    "content": "\n\n<!DOCTYPE html>\n<!--[if IE 8]><html class=\"no-js lt-ie9\" lang=\"zh-CN\" > <![endif]-->\n<!--[if gt IE 8]><!--> <html class=\"no-js\" lang=\"zh-CN\" > <!--<![endif]-->\n<head>\n  <meta charset=\"utf-8\">\n  \n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  \n  <title>snowboy.snowboydetect &mdash; wukong-robot 1.2.0 文档</title>\n  \n\n  \n  \n  \n  \n\n  \n  <script type=\"text/javascript\" src=\"../../_static/js/modernizr.min.js\"></script>\n  \n    \n      <script type=\"text/javascript\" id=\"documentation_options\" data-url_root=\"../../\" src=\"../../_static/documentation_options.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/jquery.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/underscore.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/doctools.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/language_data.js\"></script>\n        <script type=\"text/javascript\" src=\"../../_static/translations.js\"></script>\n    \n    <script type=\"text/javascript\" src=\"../../_static/js/theme.js\"></script>\n\n    \n\n  \n  <link rel=\"stylesheet\" href=\"../../_static/css/theme.css\" type=\"text/css\" />\n  <link rel=\"stylesheet\" href=\"../../_static/pygments.css\" type=\"text/css\" />\n    <link rel=\"index\" title=\"索引\" href=\"../../genindex.html\" />\n    <link rel=\"search\" title=\"搜索\" href=\"../../search.html\" /> \n</head>\n\n<body class=\"wy-body-for-nav\">\n\n   \n  <div class=\"wy-grid-for-nav\">\n    \n    <nav data-toggle=\"wy-nav-shift\" class=\"wy-nav-side\">\n      <div class=\"wy-side-scroll\">\n        <div class=\"wy-side-nav-search\" >\n          \n\n          \n            <a href=\"../../index.html\" class=\"icon icon-home\"> wukong-robot\n          \n\n          \n          </a>\n\n          \n            \n            \n          \n\n          \n<div role=\"search\">\n  <form id=\"rtd-search-form\" class=\"wy-form\" action=\"../../search.html\" method=\"get\">\n    <input type=\"text\" name=\"q\" placeholder=\"Search docs\" />\n    <input type=\"hidden\" name=\"check_keywords\" value=\"yes\" />\n    <input type=\"hidden\" name=\"area\" value=\"default\" />\n  </form>\n</div>\n\n          \n        </div>\n\n        <div class=\"wy-menu wy-menu-vertical\" data-spy=\"affix\" role=\"navigation\" aria-label=\"main navigation\">\n          \n            \n            \n              \n            \n            \n              <!-- Local TOC -->\n              <div class=\"local-toc\"></div>\n            \n          \n        </div>\n      </div>\n    </nav>\n\n    <section data-toggle=\"wy-nav-shift\" class=\"wy-nav-content-wrap\">\n\n      \n      <nav class=\"wy-nav-top\" aria-label=\"top navigation\">\n        \n          <i data-toggle=\"wy-nav-top\" class=\"fa fa-bars\"></i>\n          <a href=\"../../index.html\">wukong-robot</a>\n        \n      </nav>\n\n\n      <div class=\"wy-nav-content\">\n        \n        <div class=\"rst-content\">\n        \n          \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<div role=\"navigation\" aria-label=\"breadcrumbs navigation\">\n\n  <ul class=\"wy-breadcrumbs\">\n    \n      <li><a href=\"../../index.html\">Docs</a> &raquo;</li>\n        \n          <li><a href=\"../index.html\">模块代码</a> &raquo;</li>\n        \n      <li>snowboy.snowboydetect</li>\n    \n    \n      <li class=\"wy-breadcrumbs-aside\">\n        \n      </li>\n    \n  </ul>\n\n  \n  <hr/>\n</div>\n          <div role=\"main\" class=\"document\" itemscope=\"itemscope\" itemtype=\"http://schema.org/Article\">\n           <div itemprop=\"articleBody\">\n            \n  <h1>snowboy.snowboydetect 源代码</h1><div class=\"highlight\"><pre>\n<span></span><span class=\"c1\"># This file was automatically generated by SWIG (http://www.swig.org).</span>\n<span class=\"c1\"># Version 3.0.12</span>\n<span class=\"c1\">#</span>\n<span class=\"c1\"># Do not make changes to this file unless you know what you are doing--modify</span>\n<span class=\"c1\"># the SWIG interface file instead.</span>\n\n<span class=\"kn\">from</span> <span class=\"nn\">sys</span> <span class=\"k\">import</span> <span class=\"n\">version_info</span> <span class=\"k\">as</span> <span class=\"n\">_swig_python_version_info</span>\n<span class=\"k\">if</span> <span class=\"n\">_swig_python_version_info</span> <span class=\"o\">&gt;=</span> <span class=\"p\">(</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">7</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">):</span>\n    <span class=\"k\">def</span> <span class=\"nf\">swig_import_helper</span><span class=\"p\">():</span>\n        <span class=\"kn\">import</span> <span class=\"nn\">importlib</span>\n        <span class=\"n\">pkg</span> <span class=\"o\">=</span> <span class=\"vm\">__name__</span><span class=\"o\">.</span><span class=\"n\">rpartition</span><span class=\"p\">(</span><span class=\"s1\">&#39;.&#39;</span><span class=\"p\">)[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n        <span class=\"n\">mname</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;.&#39;</span><span class=\"o\">.</span><span class=\"n\">join</span><span class=\"p\">((</span><span class=\"n\">pkg</span><span class=\"p\">,</span> <span class=\"s1\">&#39;_snowboydetect&#39;</span><span class=\"p\">))</span><span class=\"o\">.</span><span class=\"n\">lstrip</span><span class=\"p\">(</span><span class=\"s1\">&#39;.&#39;</span><span class=\"p\">)</span>\n        <span class=\"k\">try</span><span class=\"p\">:</span>\n            <span class=\"k\">return</span> <span class=\"n\">importlib</span><span class=\"o\">.</span><span class=\"n\">import_module</span><span class=\"p\">(</span><span class=\"n\">mname</span><span class=\"p\">)</span>\n        <span class=\"k\">except</span> <span class=\"ne\">ImportError</span><span class=\"p\">:</span>\n            <span class=\"k\">return</span> <span class=\"n\">importlib</span><span class=\"o\">.</span><span class=\"n\">import_module</span><span class=\"p\">(</span><span class=\"s1\">&#39;_snowboydetect&#39;</span><span class=\"p\">)</span>\n    <span class=\"n\">_snowboydetect</span> <span class=\"o\">=</span> <span class=\"n\">swig_import_helper</span><span class=\"p\">()</span>\n    <span class=\"k\">del</span> <span class=\"n\">swig_import_helper</span>\n<span class=\"k\">elif</span> <span class=\"n\">_swig_python_version_info</span> <span class=\"o\">&gt;=</span> <span class=\"p\">(</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">6</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">):</span>\n    <span class=\"k\">def</span> <span class=\"nf\">swig_import_helper</span><span class=\"p\">():</span>\n        <span class=\"kn\">from</span> <span class=\"nn\">os.path</span> <span class=\"k\">import</span> <span class=\"n\">dirname</span>\n        <span class=\"kn\">import</span> <span class=\"nn\">imp</span>\n        <span class=\"n\">fp</span> <span class=\"o\">=</span> <span class=\"kc\">None</span>\n        <span class=\"k\">try</span><span class=\"p\">:</span>\n            <span class=\"n\">fp</span><span class=\"p\">,</span> <span class=\"n\">pathname</span><span class=\"p\">,</span> <span class=\"n\">description</span> <span class=\"o\">=</span> <span class=\"n\">imp</span><span class=\"o\">.</span><span class=\"n\">find_module</span><span class=\"p\">(</span><span class=\"s1\">&#39;_snowboydetect&#39;</span><span class=\"p\">,</span> <span class=\"p\">[</span><span class=\"n\">dirname</span><span class=\"p\">(</span><span class=\"vm\">__file__</span><span class=\"p\">)])</span>\n        <span class=\"k\">except</span> <span class=\"ne\">ImportError</span><span class=\"p\">:</span>\n            <span class=\"kn\">import</span> <span class=\"nn\">_snowboydetect</span>\n            <span class=\"k\">return</span> <span class=\"n\">_snowboydetect</span>\n        <span class=\"k\">try</span><span class=\"p\">:</span>\n            <span class=\"n\">_mod</span> <span class=\"o\">=</span> <span class=\"n\">imp</span><span class=\"o\">.</span><span class=\"n\">load_module</span><span class=\"p\">(</span><span class=\"s1\">&#39;_snowboydetect&#39;</span><span class=\"p\">,</span> <span class=\"n\">fp</span><span class=\"p\">,</span> <span class=\"n\">pathname</span><span class=\"p\">,</span> <span class=\"n\">description</span><span class=\"p\">)</span>\n        <span class=\"k\">finally</span><span class=\"p\">:</span>\n            <span class=\"k\">if</span> <span class=\"n\">fp</span> <span class=\"ow\">is</span> <span class=\"ow\">not</span> <span class=\"kc\">None</span><span class=\"p\">:</span>\n                <span class=\"n\">fp</span><span class=\"o\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n        <span class=\"k\">return</span> <span class=\"n\">_mod</span>\n    <span class=\"n\">_snowboydetect</span> <span class=\"o\">=</span> <span class=\"n\">swig_import_helper</span><span class=\"p\">()</span>\n    <span class=\"k\">del</span> <span class=\"n\">swig_import_helper</span>\n<span class=\"k\">else</span><span class=\"p\">:</span>\n    <span class=\"kn\">import</span> <span class=\"nn\">_snowboydetect</span>\n<span class=\"k\">del</span> <span class=\"n\">_swig_python_version_info</span>\n\n<span class=\"k\">try</span><span class=\"p\">:</span>\n    <span class=\"n\">_swig_property</span> <span class=\"o\">=</span> <span class=\"nb\">property</span>\n<span class=\"k\">except</span> <span class=\"ne\">NameError</span><span class=\"p\">:</span>\n    <span class=\"k\">pass</span>  <span class=\"c1\"># Python &lt; 2.2 doesn&#39;t have &#39;property&#39;.</span>\n\n<span class=\"k\">try</span><span class=\"p\">:</span>\n    <span class=\"kn\">import</span> <span class=\"nn\">builtins</span> <span class=\"k\">as</span> <span class=\"nn\">__builtin__</span>\n<span class=\"k\">except</span> <span class=\"ne\">ImportError</span><span class=\"p\">:</span>\n    <span class=\"kn\">import</span> <span class=\"nn\">__builtin__</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">_swig_setattr_nondynamic</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">class_type</span><span class=\"p\">,</span> <span class=\"n\">name</span><span class=\"p\">,</span> <span class=\"n\">value</span><span class=\"p\">,</span> <span class=\"n\">static</span><span class=\"o\">=</span><span class=\"mi\">1</span><span class=\"p\">):</span>\n    <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">name</span> <span class=\"o\">==</span> <span class=\"s2\">&quot;thisown&quot;</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">this</span><span class=\"o\">.</span><span class=\"n\">own</span><span class=\"p\">(</span><span class=\"n\">value</span><span class=\"p\">)</span>\n    <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">name</span> <span class=\"o\">==</span> <span class=\"s2\">&quot;this&quot;</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"nb\">type</span><span class=\"p\">(</span><span class=\"n\">value</span><span class=\"p\">)</span><span class=\"o\">.</span><span class=\"vm\">__name__</span> <span class=\"o\">==</span> <span class=\"s1\">&#39;SwigPyObject&#39;</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"vm\">__dict__</span><span class=\"p\">[</span><span class=\"n\">name</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">value</span>\n            <span class=\"k\">return</span>\n    <span class=\"n\">method</span> <span class=\"o\">=</span> <span class=\"n\">class_type</span><span class=\"o\">.</span><span class=\"n\">__swig_setmethods__</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">name</span><span class=\"p\">,</span> <span class=\"kc\">None</span><span class=\"p\">)</span>\n    <span class=\"k\">if</span> <span class=\"n\">method</span><span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"n\">method</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">value</span><span class=\"p\">)</span>\n    <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"ow\">not</span> <span class=\"n\">static</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"n\">_newclass</span><span class=\"p\">:</span>\n            <span class=\"nb\">object</span><span class=\"o\">.</span><span class=\"fm\">__setattr__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">name</span><span class=\"p\">,</span> <span class=\"n\">value</span><span class=\"p\">)</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"vm\">__dict__</span><span class=\"p\">[</span><span class=\"n\">name</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">value</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"k\">raise</span> <span class=\"ne\">AttributeError</span><span class=\"p\">(</span><span class=\"s2\">&quot;You cannot add attributes to </span><span class=\"si\">%s</span><span class=\"s2\">&quot;</span> <span class=\"o\">%</span> <span class=\"bp\">self</span><span class=\"p\">)</span>\n\n\n<span class=\"k\">def</span> <span class=\"nf\">_swig_setattr</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">class_type</span><span class=\"p\">,</span> <span class=\"n\">name</span><span class=\"p\">,</span> <span class=\"n\">value</span><span class=\"p\">):</span>\n    <span class=\"k\">return</span> <span class=\"n\">_swig_setattr_nondynamic</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">class_type</span><span class=\"p\">,</span> <span class=\"n\">name</span><span class=\"p\">,</span> <span class=\"n\">value</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">)</span>\n\n\n<span class=\"k\">def</span> <span class=\"nf\">_swig_getattr</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">class_type</span><span class=\"p\">,</span> <span class=\"n\">name</span><span class=\"p\">):</span>\n    <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">name</span> <span class=\"o\">==</span> <span class=\"s2\">&quot;thisown&quot;</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">this</span><span class=\"o\">.</span><span class=\"n\">own</span><span class=\"p\">()</span>\n    <span class=\"n\">method</span> <span class=\"o\">=</span> <span class=\"n\">class_type</span><span class=\"o\">.</span><span class=\"n\">__swig_getmethods__</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">name</span><span class=\"p\">,</span> <span class=\"kc\">None</span><span class=\"p\">)</span>\n    <span class=\"k\">if</span> <span class=\"n\">method</span><span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"n\">method</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">)</span>\n    <span class=\"k\">raise</span> <span class=\"ne\">AttributeError</span><span class=\"p\">(</span><span class=\"s2\">&quot;&#39;</span><span class=\"si\">%s</span><span class=\"s2\">&#39; object has no attribute &#39;</span><span class=\"si\">%s</span><span class=\"s2\">&#39;&quot;</span> <span class=\"o\">%</span> <span class=\"p\">(</span><span class=\"n\">class_type</span><span class=\"o\">.</span><span class=\"vm\">__name__</span><span class=\"p\">,</span> <span class=\"n\">name</span><span class=\"p\">))</span>\n\n\n<span class=\"k\">def</span> <span class=\"nf\">_swig_repr</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n    <span class=\"k\">try</span><span class=\"p\">:</span>\n        <span class=\"n\">strthis</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;proxy of &quot;</span> <span class=\"o\">+</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">this</span><span class=\"o\">.</span><span class=\"fm\">__repr__</span><span class=\"p\">()</span>\n    <span class=\"k\">except</span> <span class=\"n\">__builtin__</span><span class=\"o\">.</span><span class=\"n\">Exception</span><span class=\"p\">:</span>\n        <span class=\"n\">strthis</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;&quot;</span>\n    <span class=\"k\">return</span> <span class=\"s2\">&quot;&lt;</span><span class=\"si\">%s</span><span class=\"s2\">.</span><span class=\"si\">%s</span><span class=\"s2\">; </span><span class=\"si\">%s</span><span class=\"s2\"> &gt;&quot;</span> <span class=\"o\">%</span> <span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"vm\">__class__</span><span class=\"o\">.</span><span class=\"vm\">__module__</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"vm\">__class__</span><span class=\"o\">.</span><span class=\"vm\">__name__</span><span class=\"p\">,</span> <span class=\"n\">strthis</span><span class=\"p\">,)</span>\n\n<span class=\"k\">try</span><span class=\"p\">:</span>\n    <span class=\"n\">_object</span> <span class=\"o\">=</span> <span class=\"nb\">object</span>\n    <span class=\"n\">_newclass</span> <span class=\"o\">=</span> <span class=\"mi\">1</span>\n<span class=\"k\">except</span> <span class=\"n\">__builtin__</span><span class=\"o\">.</span><span class=\"n\">Exception</span><span class=\"p\">:</span>\n    <span class=\"k\">class</span> <span class=\"nc\">_object</span><span class=\"p\">:</span>\n        <span class=\"k\">pass</span>\n    <span class=\"n\">_newclass</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n\n<div class=\"viewcode-block\" id=\"SnowboyDetect\"><a class=\"viewcode-back\" href=\"../../snowboy.html#snowboy.snowboydetect.SnowboyDetect\">[文档]</a><span class=\"k\">class</span> <span class=\"nc\">SnowboyDetect</span><span class=\"p\">(</span><span class=\"n\">_object</span><span class=\"p\">):</span>\n    <span class=\"n\">__swig_setmethods__</span> <span class=\"o\">=</span> <span class=\"p\">{}</span>\n    <span class=\"fm\">__setattr__</span> <span class=\"o\">=</span> <span class=\"k\">lambda</span> <span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">name</span><span class=\"p\">,</span> <span class=\"n\">value</span><span class=\"p\">:</span> <span class=\"n\">_swig_setattr</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">SnowboyDetect</span><span class=\"p\">,</span> <span class=\"n\">name</span><span class=\"p\">,</span> <span class=\"n\">value</span><span class=\"p\">)</span>\n    <span class=\"n\">__swig_getmethods__</span> <span class=\"o\">=</span> <span class=\"p\">{}</span>\n    <span class=\"fm\">__getattr__</span> <span class=\"o\">=</span> <span class=\"k\">lambda</span> <span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">name</span><span class=\"p\">:</span> <span class=\"n\">_swig_getattr</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">SnowboyDetect</span><span class=\"p\">,</span> <span class=\"n\">name</span><span class=\"p\">)</span>\n    <span class=\"fm\">__repr__</span> <span class=\"o\">=</span> <span class=\"n\">_swig_repr</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">resource_filename</span><span class=\"p\">,</span> <span class=\"n\">model_str</span><span class=\"p\">):</span>\n        <span class=\"n\">this</span> <span class=\"o\">=</span> <span class=\"n\">_snowboydetect</span><span class=\"o\">.</span><span class=\"n\">new_SnowboyDetect</span><span class=\"p\">(</span><span class=\"n\">resource_filename</span><span class=\"p\">,</span> <span class=\"n\">model_str</span><span class=\"p\">)</span>\n        <span class=\"k\">try</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">this</span><span class=\"o\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">this</span><span class=\"p\">)</span>\n        <span class=\"k\">except</span> <span class=\"n\">__builtin__</span><span class=\"o\">.</span><span class=\"n\">Exception</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">this</span> <span class=\"o\">=</span> <span class=\"n\">this</span>\n\n<div class=\"viewcode-block\" id=\"SnowboyDetect.Reset\"><a class=\"viewcode-back\" href=\"../../snowboy.html#snowboy.snowboydetect.SnowboyDetect.Reset\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">Reset</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"n\">_snowboydetect</span><span class=\"o\">.</span><span class=\"n\">SnowboyDetect_Reset</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"SnowboyDetect.RunDetection\"><a class=\"viewcode-back\" href=\"../../snowboy.html#snowboy.snowboydetect.SnowboyDetect.RunDetection\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">RunDetection</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">args</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"n\">_snowboydetect</span><span class=\"o\">.</span><span class=\"n\">SnowboyDetect_RunDetection</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">args</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"SnowboyDetect.SetSensitivity\"><a class=\"viewcode-back\" href=\"../../snowboy.html#snowboy.snowboydetect.SnowboyDetect.SetSensitivity\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">SetSensitivity</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">sensitivity_str</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"n\">_snowboydetect</span><span class=\"o\">.</span><span class=\"n\">SnowboyDetect_SetSensitivity</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">sensitivity_str</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"SnowboyDetect.SetHighSensitivity\"><a class=\"viewcode-back\" href=\"../../snowboy.html#snowboy.snowboydetect.SnowboyDetect.SetHighSensitivity\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">SetHighSensitivity</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">high_sensitivity_str</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"n\">_snowboydetect</span><span class=\"o\">.</span><span class=\"n\">SnowboyDetect_SetHighSensitivity</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">high_sensitivity_str</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"SnowboyDetect.GetSensitivity\"><a class=\"viewcode-back\" href=\"../../snowboy.html#snowboy.snowboydetect.SnowboyDetect.GetSensitivity\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">GetSensitivity</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"n\">_snowboydetect</span><span class=\"o\">.</span><span class=\"n\">SnowboyDetect_GetSensitivity</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"SnowboyDetect.SetAudioGain\"><a class=\"viewcode-back\" href=\"../../snowboy.html#snowboy.snowboydetect.SnowboyDetect.SetAudioGain\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">SetAudioGain</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">audio_gain</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"n\">_snowboydetect</span><span class=\"o\">.</span><span class=\"n\">SnowboyDetect_SetAudioGain</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">audio_gain</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"SnowboyDetect.UpdateModel\"><a class=\"viewcode-back\" href=\"../../snowboy.html#snowboy.snowboydetect.SnowboyDetect.UpdateModel\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">UpdateModel</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"n\">_snowboydetect</span><span class=\"o\">.</span><span class=\"n\">SnowboyDetect_UpdateModel</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"SnowboyDetect.NumHotwords\"><a class=\"viewcode-back\" href=\"../../snowboy.html#snowboy.snowboydetect.SnowboyDetect.NumHotwords\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">NumHotwords</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"n\">_snowboydetect</span><span class=\"o\">.</span><span class=\"n\">SnowboyDetect_NumHotwords</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"SnowboyDetect.ApplyFrontend\"><a class=\"viewcode-back\" href=\"../../snowboy.html#snowboy.snowboydetect.SnowboyDetect.ApplyFrontend\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">ApplyFrontend</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">apply_frontend</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"n\">_snowboydetect</span><span class=\"o\">.</span><span class=\"n\">SnowboyDetect_ApplyFrontend</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">apply_frontend</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"SnowboyDetect.SampleRate\"><a class=\"viewcode-back\" href=\"../../snowboy.html#snowboy.snowboydetect.SnowboyDetect.SampleRate\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">SampleRate</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"n\">_snowboydetect</span><span class=\"o\">.</span><span class=\"n\">SnowboyDetect_SampleRate</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"SnowboyDetect.NumChannels\"><a class=\"viewcode-back\" href=\"../../snowboy.html#snowboy.snowboydetect.SnowboyDetect.NumChannels\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">NumChannels</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"n\">_snowboydetect</span><span class=\"o\">.</span><span class=\"n\">SnowboyDetect_NumChannels</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"SnowboyDetect.BitsPerSample\"><a class=\"viewcode-back\" href=\"../../snowboy.html#snowboy.snowboydetect.SnowboyDetect.BitsPerSample\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">BitsPerSample</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"n\">_snowboydetect</span><span class=\"o\">.</span><span class=\"n\">SnowboyDetect_BitsPerSample</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">)</span></div>\n    <span class=\"n\">__swig_destroy__</span> <span class=\"o\">=</span> <span class=\"n\">_snowboydetect</span><span class=\"o\">.</span><span class=\"n\">delete_SnowboyDetect</span>\n    <span class=\"fm\">__del__</span> <span class=\"o\">=</span> <span class=\"k\">lambda</span> <span class=\"bp\">self</span><span class=\"p\">:</span> <span class=\"kc\">None</span></div>\n<span class=\"n\">SnowboyDetect_swigregister</span> <span class=\"o\">=</span> <span class=\"n\">_snowboydetect</span><span class=\"o\">.</span><span class=\"n\">SnowboyDetect_swigregister</span>\n<span class=\"n\">SnowboyDetect_swigregister</span><span class=\"p\">(</span><span class=\"n\">SnowboyDetect</span><span class=\"p\">)</span>\n\n<div class=\"viewcode-block\" id=\"SnowboyVad\"><a class=\"viewcode-back\" href=\"../../snowboy.html#snowboy.snowboydetect.SnowboyVad\">[文档]</a><span class=\"k\">class</span> <span class=\"nc\">SnowboyVad</span><span class=\"p\">(</span><span class=\"n\">_object</span><span class=\"p\">):</span>\n    <span class=\"n\">__swig_setmethods__</span> <span class=\"o\">=</span> <span class=\"p\">{}</span>\n    <span class=\"fm\">__setattr__</span> <span class=\"o\">=</span> <span class=\"k\">lambda</span> <span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">name</span><span class=\"p\">,</span> <span class=\"n\">value</span><span class=\"p\">:</span> <span class=\"n\">_swig_setattr</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">SnowboyVad</span><span class=\"p\">,</span> <span class=\"n\">name</span><span class=\"p\">,</span> <span class=\"n\">value</span><span class=\"p\">)</span>\n    <span class=\"n\">__swig_getmethods__</span> <span class=\"o\">=</span> <span class=\"p\">{}</span>\n    <span class=\"fm\">__getattr__</span> <span class=\"o\">=</span> <span class=\"k\">lambda</span> <span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">name</span><span class=\"p\">:</span> <span class=\"n\">_swig_getattr</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">SnowboyVad</span><span class=\"p\">,</span> <span class=\"n\">name</span><span class=\"p\">)</span>\n    <span class=\"fm\">__repr__</span> <span class=\"o\">=</span> <span class=\"n\">_swig_repr</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">resource_filename</span><span class=\"p\">):</span>\n        <span class=\"n\">this</span> <span class=\"o\">=</span> <span class=\"n\">_snowboydetect</span><span class=\"o\">.</span><span class=\"n\">new_SnowboyVad</span><span class=\"p\">(</span><span class=\"n\">resource_filename</span><span class=\"p\">)</span>\n        <span class=\"k\">try</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">this</span><span class=\"o\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">this</span><span class=\"p\">)</span>\n        <span class=\"k\">except</span> <span class=\"n\">__builtin__</span><span class=\"o\">.</span><span class=\"n\">Exception</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">this</span> <span class=\"o\">=</span> <span class=\"n\">this</span>\n\n<div class=\"viewcode-block\" id=\"SnowboyVad.Reset\"><a class=\"viewcode-back\" href=\"../../snowboy.html#snowboy.snowboydetect.SnowboyVad.Reset\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">Reset</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"n\">_snowboydetect</span><span class=\"o\">.</span><span class=\"n\">SnowboyVad_Reset</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"SnowboyVad.RunVad\"><a class=\"viewcode-back\" href=\"../../snowboy.html#snowboy.snowboydetect.SnowboyVad.RunVad\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">RunVad</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">args</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"n\">_snowboydetect</span><span class=\"o\">.</span><span class=\"n\">SnowboyVad_RunVad</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">args</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"SnowboyVad.SetAudioGain\"><a class=\"viewcode-back\" href=\"../../snowboy.html#snowboy.snowboydetect.SnowboyVad.SetAudioGain\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">SetAudioGain</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">audio_gain</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"n\">_snowboydetect</span><span class=\"o\">.</span><span class=\"n\">SnowboyVad_SetAudioGain</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">audio_gain</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"SnowboyVad.ApplyFrontend\"><a class=\"viewcode-back\" href=\"../../snowboy.html#snowboy.snowboydetect.SnowboyVad.ApplyFrontend\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">ApplyFrontend</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">apply_frontend</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"n\">_snowboydetect</span><span class=\"o\">.</span><span class=\"n\">SnowboyVad_ApplyFrontend</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">apply_frontend</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"SnowboyVad.SampleRate\"><a class=\"viewcode-back\" href=\"../../snowboy.html#snowboy.snowboydetect.SnowboyVad.SampleRate\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">SampleRate</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"n\">_snowboydetect</span><span class=\"o\">.</span><span class=\"n\">SnowboyVad_SampleRate</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"SnowboyVad.NumChannels\"><a class=\"viewcode-back\" href=\"../../snowboy.html#snowboy.snowboydetect.SnowboyVad.NumChannels\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">NumChannels</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"n\">_snowboydetect</span><span class=\"o\">.</span><span class=\"n\">SnowboyVad_NumChannels</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"SnowboyVad.BitsPerSample\"><a class=\"viewcode-back\" href=\"../../snowboy.html#snowboy.snowboydetect.SnowboyVad.BitsPerSample\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">BitsPerSample</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"n\">_snowboydetect</span><span class=\"o\">.</span><span class=\"n\">SnowboyVad_BitsPerSample</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">)</span></div>\n    <span class=\"n\">__swig_destroy__</span> <span class=\"o\">=</span> <span class=\"n\">_snowboydetect</span><span class=\"o\">.</span><span class=\"n\">delete_SnowboyVad</span>\n    <span class=\"fm\">__del__</span> <span class=\"o\">=</span> <span class=\"k\">lambda</span> <span class=\"bp\">self</span><span class=\"p\">:</span> <span class=\"kc\">None</span></div>\n<span class=\"n\">SnowboyVad_swigregister</span> <span class=\"o\">=</span> <span class=\"n\">_snowboydetect</span><span class=\"o\">.</span><span class=\"n\">SnowboyVad_swigregister</span>\n<span class=\"n\">SnowboyVad_swigregister</span><span class=\"p\">(</span><span class=\"n\">SnowboyVad</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># This file is compatible with both classic and new-style classes.</span>\n\n\n</pre></div>\n\n           </div>\n           \n          </div>\n          <footer>\n  \n\n  <hr/>\n\n  <div role=\"contentinfo\">\n    <p>\n        &copy; Copyright 2019, wzpan\n\n    </p>\n  </div>\n  Built with <a href=\"http://sphinx-doc.org/\">Sphinx</a> using a <a href=\"https://github.com/rtfd/sphinx_rtd_theme\">theme</a> provided by <a href=\"https://readthedocs.org\">Read the Docs</a>. \n\n</footer>\n\n        </div>\n      </div>\n\n    </section>\n\n  </div>\n  \n\n\n  <script type=\"text/javascript\">\n      jQuery(function () {\n          SphinxRtdTheme.Navigation.enable(true);\n      });\n  </script>\n\n  \n  \n    \n   \n\n</body>\n</html>"
  },
  {
    "path": "docs/_modules/wukong.html",
    "content": "\n\n<!DOCTYPE html>\n<!--[if IE 8]><html class=\"no-js lt-ie9\" lang=\"zh-CN\" > <![endif]-->\n<!--[if gt IE 8]><!--> <html class=\"no-js\" lang=\"zh-CN\" > <!--<![endif]-->\n<head>\n  <meta charset=\"utf-8\">\n  \n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  \n  <title>wukong &mdash; wukong-robot 1.2.0 文档</title>\n  \n\n  \n  \n  \n  \n\n  \n  <script type=\"text/javascript\" src=\"../_static/js/modernizr.min.js\"></script>\n  \n    \n      <script type=\"text/javascript\" id=\"documentation_options\" data-url_root=\"../\" src=\"../_static/documentation_options.js\"></script>\n        <script type=\"text/javascript\" src=\"../_static/jquery.js\"></script>\n        <script type=\"text/javascript\" src=\"../_static/underscore.js\"></script>\n        <script type=\"text/javascript\" src=\"../_static/doctools.js\"></script>\n        <script type=\"text/javascript\" src=\"../_static/language_data.js\"></script>\n        <script type=\"text/javascript\" src=\"../_static/translations.js\"></script>\n    \n    <script type=\"text/javascript\" src=\"../_static/js/theme.js\"></script>\n\n    \n\n  \n  <link rel=\"stylesheet\" href=\"../_static/css/theme.css\" type=\"text/css\" />\n  <link rel=\"stylesheet\" href=\"../_static/pygments.css\" type=\"text/css\" />\n    <link rel=\"index\" title=\"索引\" href=\"../genindex.html\" />\n    <link rel=\"search\" title=\"搜索\" href=\"../search.html\" /> \n</head>\n\n<body class=\"wy-body-for-nav\">\n\n   \n  <div class=\"wy-grid-for-nav\">\n    \n    <nav data-toggle=\"wy-nav-shift\" class=\"wy-nav-side\">\n      <div class=\"wy-side-scroll\">\n        <div class=\"wy-side-nav-search\" >\n          \n\n          \n            <a href=\"../index.html\" class=\"icon icon-home\"> wukong-robot\n          \n\n          \n          </a>\n\n          \n            \n            \n          \n\n          \n<div role=\"search\">\n  <form id=\"rtd-search-form\" class=\"wy-form\" action=\"../search.html\" method=\"get\">\n    <input type=\"text\" name=\"q\" placeholder=\"Search docs\" />\n    <input type=\"hidden\" name=\"check_keywords\" value=\"yes\" />\n    <input type=\"hidden\" name=\"area\" value=\"default\" />\n  </form>\n</div>\n\n          \n        </div>\n\n        <div class=\"wy-menu wy-menu-vertical\" data-spy=\"affix\" role=\"navigation\" aria-label=\"main navigation\">\n          \n            \n            \n              \n            \n            \n              <!-- Local TOC -->\n              <div class=\"local-toc\"></div>\n            \n          \n        </div>\n      </div>\n    </nav>\n\n    <section data-toggle=\"wy-nav-shift\" class=\"wy-nav-content-wrap\">\n\n      \n      <nav class=\"wy-nav-top\" aria-label=\"top navigation\">\n        \n          <i data-toggle=\"wy-nav-top\" class=\"fa fa-bars\"></i>\n          <a href=\"../index.html\">wukong-robot</a>\n        \n      </nav>\n\n\n      <div class=\"wy-nav-content\">\n        \n        <div class=\"rst-content\">\n        \n          \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<div role=\"navigation\" aria-label=\"breadcrumbs navigation\">\n\n  <ul class=\"wy-breadcrumbs\">\n    \n      <li><a href=\"../index.html\">Docs</a> &raquo;</li>\n        \n          <li><a href=\"index.html\">模块代码</a> &raquo;</li>\n        \n      <li>wukong</li>\n    \n    \n      <li class=\"wy-breadcrumbs-aside\">\n        \n      </li>\n    \n  </ul>\n\n  \n  <hr/>\n</div>\n          <div role=\"main\" class=\"document\" itemscope=\"itemscope\" itemtype=\"http://schema.org/Article\">\n           <div itemprop=\"articleBody\">\n            \n  <h1>wukong 源代码</h1><div class=\"highlight\"><pre>\n<span></span><span class=\"c1\"># -*- coding: utf-8-*-</span>\n<span class=\"kn\">from</span> <span class=\"nn\">snowboy</span> <span class=\"k\">import</span> <span class=\"n\">snowboydecoder</span>\n<span class=\"kn\">from</span> <span class=\"nn\">robot</span> <span class=\"k\">import</span> <span class=\"n\">config</span><span class=\"p\">,</span> <span class=\"n\">utils</span><span class=\"p\">,</span> <span class=\"n\">constants</span><span class=\"p\">,</span> <span class=\"n\">logging</span><span class=\"p\">,</span> <span class=\"n\">statistic</span><span class=\"p\">,</span> <span class=\"n\">Player</span>\n<span class=\"kn\">from</span> <span class=\"nn\">robot.Updater</span> <span class=\"k\">import</span> <span class=\"n\">Updater</span>\n<span class=\"kn\">from</span> <span class=\"nn\">robot.ConfigMonitor</span> <span class=\"k\">import</span> <span class=\"n\">ConfigMonitor</span>\n<span class=\"kn\">from</span> <span class=\"nn\">robot.Conversation</span> <span class=\"k\">import</span> <span class=\"n\">Conversation</span>\n<span class=\"kn\">from</span> <span class=\"nn\">server</span> <span class=\"k\">import</span> <span class=\"n\">server</span>\n<span class=\"kn\">from</span> <span class=\"nn\">watchdog.observers</span> <span class=\"k\">import</span> <span class=\"n\">Observer</span>\n<span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">import</span> <span class=\"nn\">signal</span>\n<span class=\"kn\">import</span> <span class=\"nn\">hashlib</span>\n<span class=\"kn\">import</span> <span class=\"nn\">fire</span>\n<span class=\"kn\">import</span> <span class=\"nn\">urllib3</span>\n<span class=\"n\">urllib3</span><span class=\"o\">.</span><span class=\"n\">disable_warnings</span><span class=\"p\">(</span><span class=\"n\">urllib3</span><span class=\"o\">.</span><span class=\"n\">exceptions</span><span class=\"o\">.</span><span class=\"n\">InsecureRequestWarning</span><span class=\"p\">)</span>\n\n<span class=\"n\">logger</span> <span class=\"o\">=</span> <span class=\"n\">logging</span><span class=\"o\">.</span><span class=\"n\">getLogger</span><span class=\"p\">(</span><span class=\"vm\">__name__</span><span class=\"p\">)</span>\n\n<div class=\"viewcode-block\" id=\"Wukong\"><a class=\"viewcode-back\" href=\"../wukong.html#wukong.Wukong\">[文档]</a><span class=\"k\">class</span> <span class=\"nc\">Wukong</span><span class=\"p\">(</span><span class=\"nb\">object</span><span class=\"p\">):</span>\n\n    <span class=\"n\">_profiling</span> <span class=\"o\">=</span> <span class=\"kc\">False</span>\n    <span class=\"n\">_dev</span> <span class=\"o\">=</span> <span class=\"kc\">False</span>\n    \n<div class=\"viewcode-block\" id=\"Wukong.init\"><a class=\"viewcode-back\" href=\"../wukong.html#wukong.Wukong.init\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">init</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">global</span> <span class=\"n\">conversation</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">detector</span> <span class=\"o\">=</span> <span class=\"kc\">None</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_interrupted</span> <span class=\"o\">=</span> <span class=\"kc\">False</span>        \n        <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"s1\">&#39;&#39;&#39;</span>\n<span class=\"s1\">********************************************************</span>\n<span class=\"s1\">*          wukong-robot - 中文语音对话机器人           *</span>\n<span class=\"s1\">*          (c) 2019 潘伟洲 &lt;m@hahack.com&gt;              *</span>\n<span class=\"s1\">*     https://github.com/wzpan/wukong-robot.git        *</span>\n<span class=\"s1\">********************************************************</span>\n\n<span class=\"s1\">            如需退出，可以按 Ctrl-4 组合键。</span>\n\n<span class=\"s1\">&#39;&#39;&#39;</span><span class=\"p\">)</span>\n        \n        <span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">init</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_conversation</span> <span class=\"o\">=</span> <span class=\"n\">Conversation</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_profiling</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_conversation</span><span class=\"o\">.</span><span class=\"n\">say</span><span class=\"p\">(</span><span class=\"s1\">&#39;</span><span class=\"si\">{}</span><span class=\"s1\"> 你好！试试对我喊唤醒词叫醒我吧&#39;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;first_name&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;主人&#39;</span><span class=\"p\">)),</span> <span class=\"kc\">True</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_observer</span> <span class=\"o\">=</span> <span class=\"n\">Observer</span><span class=\"p\">()</span>\n        <span class=\"n\">event_handler</span> <span class=\"o\">=</span> <span class=\"n\">ConfigMonitor</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_conversation</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_observer</span><span class=\"o\">.</span><span class=\"n\">schedule</span><span class=\"p\">(</span><span class=\"n\">event_handler</span><span class=\"p\">,</span> <span class=\"n\">constants</span><span class=\"o\">.</span><span class=\"n\">CONFIG_PATH</span><span class=\"p\">,</span> <span class=\"kc\">False</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_observer</span><span class=\"o\">.</span><span class=\"n\">schedule</span><span class=\"p\">(</span><span class=\"n\">event_handler</span><span class=\"p\">,</span> <span class=\"n\">constants</span><span class=\"o\">.</span><span class=\"n\">DATA_PATH</span><span class=\"p\">,</span> <span class=\"kc\">False</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_observer</span><span class=\"o\">.</span><span class=\"n\">start</span><span class=\"p\">()</span></div>\n\n    <span class=\"k\">def</span> <span class=\"nf\">_signal_handler</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">signal</span><span class=\"p\">,</span> <span class=\"n\">frame</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_interrupted</span> <span class=\"o\">=</span> <span class=\"kc\">True</span>\n        <span class=\"n\">utils</span><span class=\"o\">.</span><span class=\"n\">clean</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_observer</span><span class=\"o\">.</span><span class=\"n\">stop</span><span class=\"p\">()</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">_detected_callback</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">utils</span><span class=\"o\">.</span><span class=\"n\">is_proper_time</span><span class=\"p\">():</span>\n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">warning</span><span class=\"p\">(</span><span class=\"s1\">&#39;勿扰模式开启中&#39;</span><span class=\"p\">)</span>\n            <span class=\"k\">return</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_conversation</span><span class=\"o\">.</span><span class=\"n\">isRecording</span><span class=\"p\">:</span>\n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">warning</span><span class=\"p\">(</span><span class=\"s1\">&#39;正在录音中，跳过&#39;</span><span class=\"p\">)</span>\n            <span class=\"k\">return</span>\n        <span class=\"n\">Player</span><span class=\"o\">.</span><span class=\"n\">play</span><span class=\"p\">(</span><span class=\"n\">constants</span><span class=\"o\">.</span><span class=\"n\">getData</span><span class=\"p\">(</span><span class=\"s1\">&#39;beep_hi.wav&#39;</span><span class=\"p\">))</span>\n        <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s1\">&#39;开始录音&#39;</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_conversation</span><span class=\"o\">.</span><span class=\"n\">interrupt</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_conversation</span><span class=\"o\">.</span><span class=\"n\">isRecording</span> <span class=\"o\">=</span> <span class=\"kc\">True</span><span class=\"p\">;</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">_do_not_bother_on_callback</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;/do_not_bother/hotword_switch&#39;</span><span class=\"p\">,</span> <span class=\"kc\">False</span><span class=\"p\">):</span>\n            <span class=\"n\">utils</span><span class=\"o\">.</span><span class=\"n\">do_not_bother</span> <span class=\"o\">=</span> <span class=\"kc\">True</span>\n            <span class=\"n\">Player</span><span class=\"o\">.</span><span class=\"n\">play</span><span class=\"p\">(</span><span class=\"n\">constants</span><span class=\"o\">.</span><span class=\"n\">getData</span><span class=\"p\">(</span><span class=\"s1\">&#39;off.wav&#39;</span><span class=\"p\">))</span>\n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s1\">&#39;勿扰模式打开&#39;</span><span class=\"p\">)</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">_do_not_bother_off_callback</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;/do_not_bother/hotword_switch&#39;</span><span class=\"p\">,</span> <span class=\"kc\">False</span><span class=\"p\">):</span>\n            <span class=\"n\">utils</span><span class=\"o\">.</span><span class=\"n\">do_not_bother</span> <span class=\"o\">=</span> <span class=\"kc\">False</span>\n            <span class=\"n\">Player</span><span class=\"o\">.</span><span class=\"n\">play</span><span class=\"p\">(</span><span class=\"n\">constants</span><span class=\"o\">.</span><span class=\"n\">getData</span><span class=\"p\">(</span><span class=\"s1\">&#39;on.wav&#39;</span><span class=\"p\">))</span>\n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s1\">&#39;勿扰模式关闭&#39;</span><span class=\"p\">)</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">_interrupt_callback</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_interrupted</span>\n\n<div class=\"viewcode-block\" id=\"Wukong.run\"><a class=\"viewcode-back\" href=\"../wukong.html#wukong.Wukong.run\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">run</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">init</span><span class=\"p\">()</span>\n\n        <span class=\"c1\"># capture SIGINT signal, e.g., Ctrl+C</span>\n        <span class=\"n\">signal</span><span class=\"o\">.</span><span class=\"n\">signal</span><span class=\"p\">(</span><span class=\"n\">signal</span><span class=\"o\">.</span><span class=\"n\">SIGINT</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_signal_handler</span><span class=\"p\">)</span>\n\n        <span class=\"c1\"># site</span>\n        <span class=\"n\">server</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_conversation</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"p\">)</span>\n\n        <span class=\"n\">statistic</span><span class=\"o\">.</span><span class=\"n\">report</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">)</span>\n\n        <span class=\"k\">try</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">initDetector</span><span class=\"p\">()</span>\n        <span class=\"k\">except</span> <span class=\"ne\">AttributeError</span><span class=\"p\">:</span>\n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">error</span><span class=\"p\">(</span><span class=\"s1\">&#39;初始化离线唤醒功能失败&#39;</span><span class=\"p\">)</span>\n            <span class=\"k\">pass</span></div>\n\n<div class=\"viewcode-block\" id=\"Wukong.initDetector\"><a class=\"viewcode-back\" href=\"../wukong.html#wukong.Wukong.initDetector\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">initDetector</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">detector</span> <span class=\"ow\">is</span> <span class=\"ow\">not</span> <span class=\"kc\">None</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">detector</span><span class=\"o\">.</span><span class=\"n\">terminate</span><span class=\"p\">()</span>\n        <span class=\"k\">if</span> <span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;/do_not_bother/hotword_switch&#39;</span><span class=\"p\">,</span> <span class=\"kc\">False</span><span class=\"p\">):</span>\n            <span class=\"n\">models</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n                <span class=\"n\">constants</span><span class=\"o\">.</span><span class=\"n\">getHotwordModel</span><span class=\"p\">(</span><span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;hotword&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;wukong.pmdl&#39;</span><span class=\"p\">)),</span>\n                <span class=\"n\">constants</span><span class=\"o\">.</span><span class=\"n\">getHotwordModel</span><span class=\"p\">(</span><span class=\"n\">utils</span><span class=\"o\">.</span><span class=\"n\">get_do_not_bother_on_hotword</span><span class=\"p\">()),</span>\n                <span class=\"n\">constants</span><span class=\"o\">.</span><span class=\"n\">getHotwordModel</span><span class=\"p\">(</span><span class=\"n\">utils</span><span class=\"o\">.</span><span class=\"n\">get_do_not_bother_off_hotword</span><span class=\"p\">())</span>\n            <span class=\"p\">]</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"n\">models</span> <span class=\"o\">=</span> <span class=\"n\">constants</span><span class=\"o\">.</span><span class=\"n\">getHotwordModel</span><span class=\"p\">(</span><span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;hotword&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;wukong.pmdl&#39;</span><span class=\"p\">))</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">detector</span> <span class=\"o\">=</span> <span class=\"n\">snowboydecoder</span><span class=\"o\">.</span><span class=\"n\">HotwordDetector</span><span class=\"p\">(</span><span class=\"n\">models</span><span class=\"p\">,</span> <span class=\"n\">sensitivity</span><span class=\"o\">=</span><span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;sensitivity&#39;</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">))</span>\n        <span class=\"c1\"># main loop</span>\n        <span class=\"k\">try</span><span class=\"p\">:</span>\n            <span class=\"k\">if</span> <span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;/do_not_bother/hotword_switch&#39;</span><span class=\"p\">,</span> <span class=\"kc\">False</span><span class=\"p\">):</span>\n                <span class=\"n\">callbacks</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_detected_callback</span><span class=\"p\">,</span>\n                             <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_do_not_bother_on_callback</span><span class=\"p\">,</span>\n                             <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_do_not_bother_off_callback</span><span class=\"p\">]</span>\n            <span class=\"k\">else</span><span class=\"p\">:</span>\n                <span class=\"n\">callbacks</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_detected_callback</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">detector</span><span class=\"o\">.</span><span class=\"n\">start</span><span class=\"p\">(</span><span class=\"n\">detected_callback</span><span class=\"o\">=</span><span class=\"n\">callbacks</span><span class=\"p\">,</span>\n                                <span class=\"n\">audio_recorder_callback</span><span class=\"o\">=</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_conversation</span><span class=\"o\">.</span><span class=\"n\">converse</span><span class=\"p\">,</span>\n                                <span class=\"n\">interrupt_check</span><span class=\"o\">=</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_interrupt_callback</span><span class=\"p\">,</span>\n                                <span class=\"n\">silent_count_threshold</span><span class=\"o\">=</span><span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;silent_threshold&#39;</span><span class=\"p\">,</span> <span class=\"mi\">15</span><span class=\"p\">),</span>\n                                <span class=\"n\">recording_timeout</span><span class=\"o\">=</span><span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;recording_timeout&#39;</span><span class=\"p\">,</span> <span class=\"mi\">5</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"mi\">4</span><span class=\"p\">,</span>\n                                <span class=\"n\">sleep_time</span><span class=\"o\">=</span><span class=\"mf\">0.03</span><span class=\"p\">)</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">detector</span><span class=\"o\">.</span><span class=\"n\">terminate</span><span class=\"p\">()</span>\n        <span class=\"k\">except</span> <span class=\"ne\">Exception</span> <span class=\"k\">as</span> <span class=\"n\">e</span><span class=\"p\">:</span>\n            <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">critical</span><span class=\"p\">(</span><span class=\"s1\">&#39;离线唤醒机制初始化失败：</span><span class=\"si\">{}</span><span class=\"s1\">&#39;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">e</span><span class=\"p\">))</span></div>\n\n<div class=\"viewcode-block\" id=\"Wukong.md5\"><a class=\"viewcode-back\" href=\"../wukong.html#wukong.Wukong.md5\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">md5</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">password</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"n\">hashlib</span><span class=\"o\">.</span><span class=\"n\">md5</span><span class=\"p\">(</span><span class=\"n\">password</span><span class=\"o\">.</span><span class=\"n\">encode</span><span class=\"p\">(</span><span class=\"s1\">&#39;utf-8&#39;</span><span class=\"p\">))</span><span class=\"o\">.</span><span class=\"n\">hexdigest</span><span class=\"p\">()</span></div>\n\n<div class=\"viewcode-block\" id=\"Wukong.update\"><a class=\"viewcode-back\" href=\"../wukong.html#wukong.Wukong.update\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">update</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"n\">updater</span> <span class=\"o\">=</span> <span class=\"n\">Updater</span><span class=\"p\">()</span>\n        <span class=\"k\">return</span> <span class=\"n\">updater</span><span class=\"o\">.</span><span class=\"n\">update</span><span class=\"p\">()</span></div>\n\n<div class=\"viewcode-block\" id=\"Wukong.fetch\"><a class=\"viewcode-back\" href=\"../wukong.html#wukong.Wukong.fetch\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">fetch</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"n\">updater</span> <span class=\"o\">=</span> <span class=\"n\">Updater</span><span class=\"p\">()</span>\n        <span class=\"n\">updater</span><span class=\"o\">.</span><span class=\"n\">fetch</span><span class=\"p\">()</span></div>\n\n<div class=\"viewcode-block\" id=\"Wukong.restart\"><a class=\"viewcode-back\" href=\"../wukong.html#wukong.Wukong.restart\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">restart</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">critical</span><span class=\"p\">(</span><span class=\"s1\">&#39;程序重启...&#39;</span><span class=\"p\">)</span>\n        <span class=\"k\">try</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">detector</span><span class=\"o\">.</span><span class=\"n\">terminate</span><span class=\"p\">()</span>\n        <span class=\"k\">except</span> <span class=\"ne\">AttributeError</span><span class=\"p\">:</span>\n            <span class=\"k\">pass</span>\n        <span class=\"n\">python</span> <span class=\"o\">=</span> <span class=\"n\">sys</span><span class=\"o\">.</span><span class=\"n\">executable</span>\n        <span class=\"n\">os</span><span class=\"o\">.</span><span class=\"n\">execl</span><span class=\"p\">(</span><span class=\"n\">python</span><span class=\"p\">,</span> <span class=\"n\">python</span><span class=\"p\">,</span> <span class=\"o\">*</span> <span class=\"n\">sys</span><span class=\"o\">.</span><span class=\"n\">argv</span><span class=\"p\">)</span></div>\n\n<div class=\"viewcode-block\" id=\"Wukong.profiling\"><a class=\"viewcode-back\" href=\"../wukong.html#wukong.Wukong.profiling\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">profiling</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s1\">&#39;性能调优&#39;</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_profiling</span> <span class=\"o\">=</span> <span class=\"kc\">True</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">()</span></div>\n\n<div class=\"viewcode-block\" id=\"Wukong.dev\"><a class=\"viewcode-back\" href=\"../wukong.html#wukong.Wukong.dev\">[文档]</a>    <span class=\"k\">def</span> <span class=\"nf\">dev</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"n\">logger</span><span class=\"o\">.</span><span class=\"n\">info</span><span class=\"p\">(</span><span class=\"s1\">&#39;使用测试环境&#39;</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_dev</span> <span class=\"o\">=</span> <span class=\"kc\">True</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">()</span></div></div>\n\n<span class=\"k\">if</span> <span class=\"vm\">__name__</span> <span class=\"o\">==</span> <span class=\"s1\">&#39;__main__&#39;</span><span class=\"p\">:</span>\n    <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">sys</span><span class=\"o\">.</span><span class=\"n\">argv</span><span class=\"p\">)</span> <span class=\"o\">==</span> <span class=\"mi\">1</span><span class=\"p\">:</span>\n        <span class=\"n\">wukong</span> <span class=\"o\">=</span> <span class=\"n\">Wukong</span><span class=\"p\">()</span>\n        <span class=\"n\">wukong</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">()</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">fire</span><span class=\"o\">.</span><span class=\"n\">Fire</span><span class=\"p\">(</span><span class=\"n\">Wukong</span><span class=\"p\">)</span>\n\n</pre></div>\n\n           </div>\n           \n          </div>\n          <footer>\n  \n\n  <hr/>\n\n  <div role=\"contentinfo\">\n    <p>\n        &copy; Copyright 2019, wzpan\n\n    </p>\n  </div>\n  Built with <a href=\"http://sphinx-doc.org/\">Sphinx</a> using a <a href=\"https://github.com/rtfd/sphinx_rtd_theme\">theme</a> provided by <a href=\"https://readthedocs.org\">Read the Docs</a>. \n\n</footer>\n\n        </div>\n      </div>\n\n    </section>\n\n  </div>\n  \n\n\n  <script type=\"text/javascript\">\n      jQuery(function () {\n          SphinxRtdTheme.Navigation.enable(true);\n      });\n  </script>\n\n  \n  \n    \n   \n\n</body>\n</html>"
  },
  {
    "path": "docs/_sources/AI.rst.txt",
    "content": "AI module\n=========\n\n.. automodule:: AI\n    :members:\n    :undoc-members:\n    :show-inheritance:\n"
  },
  {
    "path": "docs/_sources/ASR.rst.txt",
    "content": "ASR module\n==========\n\n.. automodule:: ASR\n    :members:\n    :undoc-members:\n    :show-inheritance:\n"
  },
  {
    "path": "docs/_sources/Brain.rst.txt",
    "content": "Brain module\n============\n\n.. automodule:: Brain\n    :members:\n    :undoc-members:\n    :show-inheritance:\n"
  },
  {
    "path": "docs/_sources/ConfigMonitor.rst.txt",
    "content": "ConfigMonitor module\n====================\n\n.. automodule:: ConfigMonitor\n    :members:\n    :undoc-members:\n    :show-inheritance:\n"
  },
  {
    "path": "docs/_sources/Conversation.rst.txt",
    "content": "Conversation module\n===================\n\n.. automodule:: Conversation\n    :members:\n    :undoc-members:\n    :show-inheritance:\n"
  },
  {
    "path": "docs/_sources/Player.rst.txt",
    "content": "Player module\n=============\n\n.. automodule:: Player\n    :members:\n    :undoc-members:\n    :show-inheritance:\n"
  },
  {
    "path": "docs/_sources/TTS.rst.txt",
    "content": "TTS module\n==========\n\n.. automodule:: TTS\n    :members:\n    :undoc-members:\n    :show-inheritance:\n"
  },
  {
    "path": "docs/_sources/Updater.rst.txt",
    "content": "Updater module\n==============\n\n.. automodule:: Updater\n    :members:\n    :undoc-members:\n    :show-inheritance:\n"
  },
  {
    "path": "docs/_sources/config.rst.txt",
    "content": "config module\n=============\n\n.. automodule:: config\n    :members:\n    :undoc-members:\n    :show-inheritance:\n"
  },
  {
    "path": "docs/_sources/constants.rst.txt",
    "content": "constants module\n================\n\n.. automodule:: constants\n    :members:\n    :undoc-members:\n    :show-inheritance:\n"
  },
  {
    "path": "docs/_sources/drivers.rst.txt",
    "content": "drivers package\n===============\n\nSubmodules\n----------\n\ndrivers.apa102 module\n---------------------\n\n.. automodule:: drivers.apa102\n    :members:\n    :undoc-members:\n    :show-inheritance:\n\ndrivers.pixels module\n---------------------\n\n.. automodule:: drivers.pixels\n    :members:\n    :undoc-members:\n    :show-inheritance:\n\n\nModule contents\n---------------\n\n.. automodule:: drivers\n    :members:\n    :undoc-members:\n    :show-inheritance:\n"
  },
  {
    "path": "docs/_sources/index.rst.txt",
    "content": ".. wukong-robot documentation master file, created by\n   sphinx-quickstart on Sun Feb 17 01:03:29 2019.\n   You can adapt this file completely to your liking, but it should at least\n   contain the root `toctree` directive.\n\nWelcome to wukong-robot's documentation!\n========================================\n\n.. toctree::\n   :maxdepth: 2\n   :caption: Contents:\n\n.. automodule:: wukong\n   :members:\n\n\nIndices and tables\n==================\n\n* :ref:`genindex`\n* :ref:`modindex`\n* :ref:`search`\n"
  },
  {
    "path": "docs/_sources/logging.rst.txt",
    "content": "logging module\n==============\n\n.. automodule:: logging\n    :members:\n    :undoc-members:\n    :show-inheritance:\n"
  },
  {
    "path": "docs/_sources/modules.rst.txt",
    "content": "wukong-robot\n============\n\n.. toctree::\n   :maxdepth: 4\n\n   plugins\n   robot\n   snowboy\n   wukong\n"
  },
  {
    "path": "docs/_sources/plugin_loader.rst.txt",
    "content": "plugin\\_loader module\n=====================\n\n.. automodule:: plugin_loader\n    :members:\n    :undoc-members:\n    :show-inheritance:\n"
  },
  {
    "path": "docs/_sources/plugins.rst.txt",
    "content": "plugins package\n===============\n\nSubmodules\n----------\n\nplugins.Camera module\n---------------------\n\n.. automodule:: plugins.Camera\n    :members:\n    :undoc-members:\n    :show-inheritance:\n\nplugins.CleanCache module\n-------------------------\n\n.. automodule:: plugins.CleanCache\n    :members:\n    :undoc-members:\n    :show-inheritance:\n\nplugins.Echo module\n-------------------\n\n.. automodule:: plugins.Echo\n    :members:\n    :undoc-members:\n    :show-inheritance:\n\nplugins.Email module\n--------------------\n\n.. automodule:: plugins.Email\n    :members:\n    :undoc-members:\n    :show-inheritance:\n\nplugins.Geek module\n-------------------\n\n.. automodule:: plugins.Geek\n    :members:\n    :undoc-members:\n    :show-inheritance:\n\nplugins.LocalPlayer module\n--------------------------\n\n.. automodule:: plugins.LocalPlayer\n    :members:\n    :undoc-members:\n    :show-inheritance:\n\nplugins.Poem module\n-------------------\n\n.. automodule:: plugins.Poem\n    :members:\n    :undoc-members:\n    :show-inheritance:\n\n\nModule contents\n---------------\n\n.. automodule:: plugins\n    :members:\n    :undoc-members:\n    :show-inheritance:\n"
  },
  {
    "path": "docs/_sources/robot.drivers.rst.txt",
    "content": "robot.drivers package\n=====================\n\nSubmodules\n----------\n\nrobot.drivers.apa102 module\n---------------------------\n\n.. automodule:: robot.drivers.apa102\n    :members:\n    :undoc-members:\n    :show-inheritance:\n\nrobot.drivers.pixels module\n---------------------------\n\n.. automodule:: robot.drivers.pixels\n    :members:\n    :undoc-members:\n    :show-inheritance:\n\n\nModule contents\n---------------\n\n.. automodule:: robot.drivers\n    :members:\n    :undoc-members:\n    :show-inheritance:\n"
  },
  {
    "path": "docs/_sources/robot.rst.txt",
    "content": "robot package\n=============\n\nSubpackages\n-----------\n\n.. toctree::\n\n    robot.sdk\n\nSubmodules\n----------\n\nrobot.AI module\n---------------\n\n.. automodule:: robot.AI\n    :members:\n    :undoc-members:\n    :show-inheritance:\n\nrobot.ASR module\n----------------\n\n.. automodule:: robot.ASR\n    :members:\n    :undoc-members:\n    :show-inheritance:\n\nrobot.Brain module\n------------------\n\n.. automodule:: robot.Brain\n    :members:\n    :undoc-members:\n    :show-inheritance:\n\nrobot.ConfigMonitor module\n--------------------------\n\n.. automodule:: robot.ConfigMonitor\n    :members:\n    :undoc-members:\n    :show-inheritance:\n\nrobot.Conversation module\n-------------------------\n\n.. automodule:: robot.Conversation\n    :members:\n    :undoc-members:\n    :show-inheritance:\n\nrobot.NLU module\n----------------\n\n.. automodule:: robot.NLU\n    :members:\n    :undoc-members:\n    :show-inheritance:\n\nrobot.Player module\n-------------------\n\n.. automodule:: robot.Player\n    :members:\n    :undoc-members:\n    :show-inheritance:\n\nrobot.TTS module\n----------------\n\n.. automodule:: robot.TTS\n    :members:\n    :undoc-members:\n    :show-inheritance:\n\nrobot.Updater module\n--------------------\n\n.. automodule:: robot.Updater\n    :members:\n    :undoc-members:\n    :show-inheritance:\n\nrobot.config module\n-------------------\n\n.. automodule:: robot.config\n    :members:\n    :undoc-members:\n    :show-inheritance:\n\nrobot.constants module\n----------------------\n\n.. automodule:: robot.constants\n    :members:\n    :undoc-members:\n    :show-inheritance:\n\nrobot.logging module\n--------------------\n\n.. automodule:: robot.logging\n    :members:\n    :undoc-members:\n    :show-inheritance:\n\nrobot.plugin\\_loader module\n---------------------------\n\n.. automodule:: robot.plugin_loader\n    :members:\n    :undoc-members:\n    :show-inheritance:\n\nrobot.statistic module\n----------------------\n\n.. automodule:: robot.statistic\n    :members:\n    :undoc-members:\n    :show-inheritance:\n\nrobot.utils module\n------------------\n\n.. automodule:: robot.utils\n    :members:\n    :undoc-members:\n    :show-inheritance:\n\n\nModule contents\n---------------\n\n.. automodule:: robot\n    :members:\n    :undoc-members:\n    :show-inheritance:\n"
  },
  {
    "path": "docs/_sources/robot.sdk.rst.txt",
    "content": "robot.sdk package\n=================\n\nSubmodules\n----------\n\nrobot.sdk.AbstractPlugin module\n-------------------------------\n\n.. automodule:: robot.sdk.AbstractPlugin\n    :members:\n    :undoc-members:\n    :show-inheritance:\n\nrobot.sdk.AliSpeech module\n--------------------------\n\n.. automodule:: robot.sdk.AliSpeech\n    :members:\n    :undoc-members:\n    :show-inheritance:\n\nrobot.sdk.RASRsdk module\n------------------------\n\n.. automodule:: robot.sdk.RASRsdk\n    :members:\n    :undoc-members:\n    :show-inheritance:\n\nrobot.sdk.TencentSpeech module\n------------------------------\n\n.. automodule:: robot.sdk.TencentSpeech\n    :members:\n    :undoc-members:\n    :show-inheritance:\n\nrobot.sdk.XunfeiSpeech module\n-----------------------------\n\n.. automodule:: robot.sdk.XunfeiSpeech\n    :members:\n    :undoc-members:\n    :show-inheritance:\n\nrobot.sdk.unit module\n---------------------\n\n.. automodule:: robot.sdk.unit\n    :members:\n    :undoc-members:\n    :show-inheritance:\n\n\nModule contents\n---------------\n\n.. automodule:: robot.sdk\n    :members:\n    :undoc-members:\n    :show-inheritance:\n"
  },
  {
    "path": "docs/_sources/snowboy.rst.txt",
    "content": "snowboy package\n===============\n\nSubmodules\n----------\n\nsnowboy.snowboydecoder module\n-----------------------------\n\n.. automodule:: snowboy.snowboydecoder\n    :members:\n    :undoc-members:\n    :show-inheritance:\n\nsnowboy.snowboydetect module\n----------------------------\n\n.. automodule:: snowboy.snowboydetect\n    :members:\n    :undoc-members:\n    :show-inheritance:\n\n\nModule contents\n---------------\n\n.. automodule:: snowboy\n    :members:\n    :undoc-members:\n    :show-inheritance:\n"
  },
  {
    "path": "docs/_sources/statistic.rst.txt",
    "content": "statistic module\n================\n\n.. automodule:: statistic\n    :members:\n    :undoc-members:\n    :show-inheritance:\n"
  },
  {
    "path": "docs/_sources/utils.rst.txt",
    "content": "utils module\n============\n\n.. automodule:: utils\n    :members:\n    :undoc-members:\n    :show-inheritance:\n"
  },
  {
    "path": "docs/_sources/wukong.rst.txt",
    "content": "wukong module\n=============\n\n.. automodule:: wukong\n    :members:\n    :undoc-members:\n    :show-inheritance:\n"
  },
  {
    "path": "docs/_static/alabaster.css",
    "content": "@import url(\"basic.css\");\n\n/* -- page layout ----------------------------------------------------------- */\n\nbody {\n    font-family: Georgia, serif;\n    font-size: 17px;\n    background-color: #fff;\n    color: #000;\n    margin: 0;\n    padding: 0;\n}\n\n\ndiv.document {\n    width: 940px;\n    margin: 30px auto 0 auto;\n}\n\ndiv.documentwrapper {\n    float: left;\n    width: 100%;\n}\n\ndiv.bodywrapper {\n    margin: 0 0 0 220px;\n}\n\ndiv.sphinxsidebar {\n    width: 220px;\n    font-size: 14px;\n    line-height: 1.5;\n}\n\nhr {\n    border: 1px solid #B1B4B6;\n}\n\ndiv.body {\n    background-color: #fff;\n    color: #3E4349;\n    padding: 0 30px 0 30px;\n}\n\ndiv.body > .section {\n    text-align: left;\n}\n\ndiv.footer {\n    width: 940px;\n    margin: 20px auto 30px auto;\n    font-size: 14px;\n    color: #888;\n    text-align: right;\n}\n\ndiv.footer a {\n    color: #888;\n}\n\np.caption {\n    font-family: inherit;\n    font-size: inherit;\n}\n\n\ndiv.relations {\n    display: none;\n}\n\n\ndiv.sphinxsidebar a {\n    color: #444;\n    text-decoration: none;\n    border-bottom: 1px dotted #999;\n}\n\ndiv.sphinxsidebar a:hover {\n    border-bottom: 1px solid #999;\n}\n\ndiv.sphinxsidebarwrapper {\n    padding: 18px 10px;\n}\n\ndiv.sphinxsidebarwrapper p.logo {\n    padding: 0;\n    margin: -10px 0 0 0px;\n    text-align: center;\n}\n\ndiv.sphinxsidebarwrapper h1.logo {\n    margin-top: -10px;\n    text-align: center;\n    margin-bottom: 5px;\n    text-align: left;\n}\n\ndiv.sphinxsidebarwrapper h1.logo-name {\n    margin-top: 0px;\n}\n\ndiv.sphinxsidebarwrapper p.blurb {\n    margin-top: 0;\n    font-style: normal;\n}\n\ndiv.sphinxsidebar h3,\ndiv.sphinxsidebar h4 {\n    font-family: Georgia, serif;\n    color: #444;\n    font-size: 24px;\n    font-weight: normal;\n    margin: 0 0 5px 0;\n    padding: 0;\n}\n\ndiv.sphinxsidebar h4 {\n    font-size: 20px;\n}\n\ndiv.sphinxsidebar h3 a {\n    color: #444;\n}\n\ndiv.sphinxsidebar p.logo a,\ndiv.sphinxsidebar h3 a,\ndiv.sphinxsidebar p.logo a:hover,\ndiv.sphinxsidebar h3 a:hover {\n    border: none;\n}\n\ndiv.sphinxsidebar p {\n    color: #555;\n    margin: 10px 0;\n}\n\ndiv.sphinxsidebar ul {\n    margin: 10px 0;\n    padding: 0;\n    color: #000;\n}\n\ndiv.sphinxsidebar ul li.toctree-l1 > a {\n    font-size: 120%;\n}\n\ndiv.sphinxsidebar ul li.toctree-l2 > a {\n    font-size: 110%;\n}\n\ndiv.sphinxsidebar input {\n    border: 1px solid #CCC;\n    font-family: Georgia, serif;\n    font-size: 1em;\n}\n\ndiv.sphinxsidebar hr {\n    border: none;\n    height: 1px;\n    color: #AAA;\n    background: #AAA;\n\n    text-align: left;\n    margin-left: 0;\n    width: 50%;\n}\n\ndiv.sphinxsidebar .badge {\n    border-bottom: none;\n}\n\ndiv.sphinxsidebar .badge:hover {\n    border-bottom: none;\n}\n\n/* To address an issue with donation coming after search */\ndiv.sphinxsidebar h3.donation {\n    margin-top: 10px;\n}\n\n/* -- body styles ----------------------------------------------------------- */\n\na {\n    color: #004B6B;\n    text-decoration: underline;\n}\n\na:hover {\n    color: #6D4100;\n    text-decoration: underline;\n}\n\ndiv.body h1,\ndiv.body h2,\ndiv.body h3,\ndiv.body h4,\ndiv.body h5,\ndiv.body h6 {\n    font-family: Georgia, serif;\n    font-weight: normal;\n    margin: 30px 0px 10px 0px;\n    padding: 0;\n}\n\ndiv.body h1 { margin-top: 0; padding-top: 0; font-size: 240%; }\ndiv.body h2 { font-size: 180%; }\ndiv.body h3 { font-size: 150%; }\ndiv.body h4 { font-size: 130%; }\ndiv.body h5 { font-size: 100%; }\ndiv.body h6 { font-size: 100%; }\n\na.headerlink {\n    color: #DDD;\n    padding: 0 4px;\n    text-decoration: none;\n}\n\na.headerlink:hover {\n    color: #444;\n    background: #EAEAEA;\n}\n\ndiv.body p, div.body dd, div.body li {\n    line-height: 1.4em;\n}\n\ndiv.admonition {\n    margin: 20px 0px;\n    padding: 10px 30px;\n    background-color: #EEE;\n    border: 1px solid #CCC;\n}\n\ndiv.admonition tt.xref, div.admonition code.xref, div.admonition a tt {\n    background-color: #FBFBFB;\n    border-bottom: 1px solid #fafafa;\n}\n\ndiv.admonition p.admonition-title {\n    font-family: Georgia, serif;\n    font-weight: normal;\n    font-size: 24px;\n    margin: 0 0 10px 0;\n    padding: 0;\n    line-height: 1;\n}\n\ndiv.admonition p.last {\n    margin-bottom: 0;\n}\n\ndiv.highlight {\n    background-color: #fff;\n}\n\ndt:target, .highlight {\n    background: #FAF3E8;\n}\n\ndiv.warning {\n    background-color: #FCC;\n    border: 1px solid #FAA;\n}\n\ndiv.danger {\n    background-color: #FCC;\n    border: 1px solid #FAA;\n    -moz-box-shadow: 2px 2px 4px #D52C2C;\n    -webkit-box-shadow: 2px 2px 4px #D52C2C;\n    box-shadow: 2px 2px 4px #D52C2C;\n}\n\ndiv.error {\n    background-color: #FCC;\n    border: 1px solid #FAA;\n    -moz-box-shadow: 2px 2px 4px #D52C2C;\n    -webkit-box-shadow: 2px 2px 4px #D52C2C;\n    box-shadow: 2px 2px 4px #D52C2C;\n}\n\ndiv.caution {\n    background-color: #FCC;\n    border: 1px solid #FAA;\n}\n\ndiv.attention {\n    background-color: #FCC;\n    border: 1px solid #FAA;\n}\n\ndiv.important {\n    background-color: #EEE;\n    border: 1px solid #CCC;\n}\n\ndiv.note {\n    background-color: #EEE;\n    border: 1px solid #CCC;\n}\n\ndiv.tip {\n    background-color: #EEE;\n    border: 1px solid #CCC;\n}\n\ndiv.hint {\n    background-color: #EEE;\n    border: 1px solid #CCC;\n}\n\ndiv.seealso {\n    background-color: #EEE;\n    border: 1px solid #CCC;\n}\n\ndiv.topic {\n    background-color: #EEE;\n}\n\np.admonition-title {\n    display: inline;\n}\n\np.admonition-title:after {\n    content: \":\";\n}\n\npre, tt, code {\n    font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace;\n    font-size: 0.9em;\n}\n\n.hll {\n    background-color: #FFC;\n    margin: 0 -12px;\n    padding: 0 12px;\n    display: block;\n}\n\nimg.screenshot {\n}\n\ntt.descname, tt.descclassname, code.descname, code.descclassname {\n    font-size: 0.95em;\n}\n\ntt.descname, code.descname {\n    padding-right: 0.08em;\n}\n\nimg.screenshot {\n    -moz-box-shadow: 2px 2px 4px #EEE;\n    -webkit-box-shadow: 2px 2px 4px #EEE;\n    box-shadow: 2px 2px 4px #EEE;\n}\n\ntable.docutils {\n    border: 1px solid #888;\n    -moz-box-shadow: 2px 2px 4px #EEE;\n    -webkit-box-shadow: 2px 2px 4px #EEE;\n    box-shadow: 2px 2px 4px #EEE;\n}\n\ntable.docutils td, table.docutils th {\n    border: 1px solid #888;\n    padding: 0.25em 0.7em;\n}\n\ntable.field-list, table.footnote {\n    border: none;\n    -moz-box-shadow: none;\n    -webkit-box-shadow: none;\n    box-shadow: none;\n}\n\ntable.footnote {\n    margin: 15px 0;\n    width: 100%;\n    border: 1px solid #EEE;\n    background: #FDFDFD;\n    font-size: 0.9em;\n}\n\ntable.footnote + table.footnote {\n    margin-top: -15px;\n    border-top: none;\n}\n\ntable.field-list th {\n    padding: 0 0.8em 0 0;\n}\n\ntable.field-list td {\n    padding: 0;\n}\n\ntable.field-list p {\n    margin-bottom: 0.8em;\n}\n\n/* Cloned from\n * https://github.com/sphinx-doc/sphinx/commit/ef60dbfce09286b20b7385333d63a60321784e68\n */\n.field-name {\n    -moz-hyphens: manual;\n    -ms-hyphens: manual;\n    -webkit-hyphens: manual;\n    hyphens: manual;\n}\n\ntable.footnote td.label {\n    width: .1px;\n    padding: 0.3em 0 0.3em 0.5em;\n}\n\ntable.footnote td {\n    padding: 0.3em 0.5em;\n}\n\ndl {\n    margin: 0;\n    padding: 0;\n}\n\ndl dd {\n    margin-left: 30px;\n}\n\nblockquote {\n    margin: 0 0 0 30px;\n    padding: 0;\n}\n\nul, ol {\n    /* Matches the 30px from the narrow-screen \"li > ul\" selector below */\n    margin: 10px 0 10px 30px;\n    padding: 0;\n}\n\npre {\n    background: #EEE;\n    padding: 7px 30px;\n    margin: 15px 0px;\n    line-height: 1.3em;\n}\n\ndiv.viewcode-block:target {\n    background: #ffd;\n}\n\ndl pre, blockquote pre, li pre {\n    margin-left: 0;\n    padding-left: 30px;\n}\n\ntt, code {\n    background-color: #ecf0f3;\n    color: #222;\n    /* padding: 1px 2px; */\n}\n\ntt.xref, code.xref, a tt {\n    background-color: #FBFBFB;\n    border-bottom: 1px solid #fff;\n}\n\na.reference {\n    text-decoration: none;\n    border-bottom: 1px dotted #004B6B;\n}\n\n/* Don't put an underline on images */\na.image-reference, a.image-reference:hover {\n    border-bottom: none;\n}\n\na.reference:hover {\n    border-bottom: 1px solid #6D4100;\n}\n\na.footnote-reference {\n    text-decoration: none;\n    font-size: 0.7em;\n    vertical-align: top;\n    border-bottom: 1px dotted #004B6B;\n}\n\na.footnote-reference:hover {\n    border-bottom: 1px solid #6D4100;\n}\n\na:hover tt, a:hover code {\n    background: #EEE;\n}\n\n\n@media screen and (max-width: 870px) {\n\n    div.sphinxsidebar {\n    \tdisplay: none;\n    }\n\n    div.document {\n       width: 100%;\n\n    }\n\n    div.documentwrapper {\n    \tmargin-left: 0;\n    \tmargin-top: 0;\n    \tmargin-right: 0;\n    \tmargin-bottom: 0;\n    }\n\n    div.bodywrapper {\n    \tmargin-top: 0;\n    \tmargin-right: 0;\n    \tmargin-bottom: 0;\n    \tmargin-left: 0;\n    }\n\n    ul {\n    \tmargin-left: 0;\n    }\n\n\tli > ul {\n        /* Matches the 30px from the \"ul, ol\" selector above */\n\t\tmargin-left: 30px;\n\t}\n\n    .document {\n    \twidth: auto;\n    }\n\n    .footer {\n    \twidth: auto;\n    }\n\n    .bodywrapper {\n    \tmargin: 0;\n    }\n\n    .footer {\n    \twidth: auto;\n    }\n\n    .github {\n        display: none;\n    }\n\n\n\n}\n\n\n\n@media screen and (max-width: 875px) {\n\n    body {\n        margin: 0;\n        padding: 20px 30px;\n    }\n\n    div.documentwrapper {\n        float: none;\n        background: #fff;\n    }\n\n    div.sphinxsidebar {\n        display: block;\n        float: none;\n        width: 102.5%;\n        margin: 50px -30px -20px -30px;\n        padding: 10px 20px;\n        background: #333;\n        color: #FFF;\n    }\n\n    div.sphinxsidebar h3, div.sphinxsidebar h4, div.sphinxsidebar p,\n    div.sphinxsidebar h3 a {\n        color: #fff;\n    }\n\n    div.sphinxsidebar a {\n        color: #AAA;\n    }\n\n    div.sphinxsidebar p.logo {\n        display: none;\n    }\n\n    div.document {\n        width: 100%;\n        margin: 0;\n    }\n\n    div.footer {\n        display: none;\n    }\n\n    div.bodywrapper {\n        margin: 0;\n    }\n\n    div.body {\n        min-height: 0;\n        padding: 0;\n    }\n\n    .rtd_doc_footer {\n        display: none;\n    }\n\n    .document {\n        width: auto;\n    }\n\n    .footer {\n        width: auto;\n    }\n\n    .footer {\n        width: auto;\n    }\n\n    .github {\n        display: none;\n    }\n}\n\n\n/* misc. */\n\n.revsys-inline {\n    display: none!important;\n}\n\n/* Make nested-list/multi-paragraph items look better in Releases changelog\n * pages. Without this, docutils' magical list fuckery causes inconsistent\n * formatting between different release sub-lists.\n */\ndiv#changelog > div.section > ul > li > p:only-child {\n    margin-bottom: 0;\n}\n\n/* Hide fugly table cell borders in ..bibliography:: directive output */\ntable.docutils.citation, table.docutils.citation td, table.docutils.citation th {\n  border: none;\n  /* Below needed in some edge cases; if not applied, bottom shadows appear */\n  -moz-box-shadow: none;\n  -webkit-box-shadow: none;\n  box-shadow: none;\n}\n\n\n/* relbar */\n\n.related {\n    line-height: 30px;\n    width: 100%;\n    font-size: 0.9rem;\n}\n\n.related.top {\n    border-bottom: 1px solid #EEE;\n    margin-bottom: 20px;\n}\n\n.related.bottom {\n    border-top: 1px solid #EEE;\n}\n\n.related ul {\n    padding: 0;\n    margin: 0;\n    list-style: none;\n}\n\n.related li {\n    display: inline;\n}\n\nnav#rellinks {\n    float: right;\n}\n\nnav#rellinks li+li:before {\n    content: \"|\";\n}\n\nnav#breadcrumbs li+li:before {\n    content: \"\\00BB\";\n}\n\n/* Hide certain items when printing */\n@media print {\n    div.related {\n        display: none;\n    }\n}"
  },
  {
    "path": "docs/_static/basic.css",
    "content": "/*\n * basic.css\n * ~~~~~~~~~\n *\n * Sphinx stylesheet -- basic theme.\n *\n * :copyright: Copyright 2007-2019 by the Sphinx team, see AUTHORS.\n * :license: BSD, see LICENSE for details.\n *\n */\n\n/* -- main layout ----------------------------------------------------------- */\n\ndiv.clearer {\n    clear: both;\n}\n\n/* -- relbar ---------------------------------------------------------------- */\n\ndiv.related {\n    width: 100%;\n    font-size: 90%;\n}\n\ndiv.related h3 {\n    display: none;\n}\n\ndiv.related ul {\n    margin: 0;\n    padding: 0 0 0 10px;\n    list-style: none;\n}\n\ndiv.related li {\n    display: inline;\n}\n\ndiv.related li.right {\n    float: right;\n    margin-right: 5px;\n}\n\n/* -- sidebar --------------------------------------------------------------- */\n\ndiv.sphinxsidebarwrapper {\n    padding: 10px 5px 0 10px;\n}\n\ndiv.sphinxsidebar {\n    float: left;\n    width: 230px;\n    margin-left: -100%;\n    font-size: 90%;\n    word-wrap: break-word;\n    overflow-wrap : break-word;\n}\n\ndiv.sphinxsidebar ul {\n    list-style: none;\n}\n\ndiv.sphinxsidebar ul ul,\ndiv.sphinxsidebar ul.want-points {\n    margin-left: 20px;\n    list-style: square;\n}\n\ndiv.sphinxsidebar ul ul {\n    margin-top: 0;\n    margin-bottom: 0;\n}\n\ndiv.sphinxsidebar form {\n    margin-top: 10px;\n}\n\ndiv.sphinxsidebar input {\n    border: 1px solid #98dbcc;\n    font-family: sans-serif;\n    font-size: 1em;\n}\n\ndiv.sphinxsidebar #searchbox form.search {\n    overflow: hidden;\n}\n\ndiv.sphinxsidebar #searchbox input[type=\"text\"] {\n    float: left;\n    width: 80%;\n    padding: 0.25em;\n    box-sizing: border-box;\n}\n\ndiv.sphinxsidebar #searchbox input[type=\"submit\"] {\n    float: left;\n    width: 20%;\n    border-left: none;\n    padding: 0.25em;\n    box-sizing: border-box;\n}\n\n\nimg {\n    border: 0;\n    max-width: 100%;\n}\n\n/* -- search page ----------------------------------------------------------- */\n\nul.search {\n    margin: 10px 0 0 20px;\n    padding: 0;\n}\n\nul.search li {\n    padding: 5px 0 5px 20px;\n    background-image: url(file.png);\n    background-repeat: no-repeat;\n    background-position: 0 7px;\n}\n\nul.search li a {\n    font-weight: bold;\n}\n\nul.search li div.context {\n    color: #888;\n    margin: 2px 0 0 30px;\n    text-align: left;\n}\n\nul.keywordmatches li.goodmatch a {\n    font-weight: bold;\n}\n\n/* -- index page ------------------------------------------------------------ */\n\ntable.contentstable {\n    width: 90%;\n    margin-left: auto;\n    margin-right: auto;\n}\n\ntable.contentstable p.biglink {\n    line-height: 150%;\n}\n\na.biglink {\n    font-size: 1.3em;\n}\n\nspan.linkdescr {\n    font-style: italic;\n    padding-top: 5px;\n    font-size: 90%;\n}\n\n/* -- general index --------------------------------------------------------- */\n\ntable.indextable {\n    width: 100%;\n}\n\ntable.indextable td {\n    text-align: left;\n    vertical-align: top;\n}\n\ntable.indextable ul {\n    margin-top: 0;\n    margin-bottom: 0;\n    list-style-type: none;\n}\n\ntable.indextable > tbody > tr > td > ul {\n    padding-left: 0em;\n}\n\ntable.indextable tr.pcap {\n    height: 10px;\n}\n\ntable.indextable tr.cap {\n    margin-top: 10px;\n    background-color: #f2f2f2;\n}\n\nimg.toggler {\n    margin-right: 3px;\n    margin-top: 3px;\n    cursor: pointer;\n}\n\ndiv.modindex-jumpbox {\n    border-top: 1px solid #ddd;\n    border-bottom: 1px solid #ddd;\n    margin: 1em 0 1em 0;\n    padding: 0.4em;\n}\n\ndiv.genindex-jumpbox {\n    border-top: 1px solid #ddd;\n    border-bottom: 1px solid #ddd;\n    margin: 1em 0 1em 0;\n    padding: 0.4em;\n}\n\n/* -- domain module index --------------------------------------------------- */\n\ntable.modindextable td {\n    padding: 2px;\n    border-collapse: collapse;\n}\n\n/* -- general body styles --------------------------------------------------- */\n\ndiv.body {\n    min-width: 450px;\n    max-width: 800px;\n}\n\ndiv.body p, div.body dd, div.body li, div.body blockquote {\n    -moz-hyphens: auto;\n    -ms-hyphens: auto;\n    -webkit-hyphens: auto;\n    hyphens: auto;\n}\n\na.headerlink {\n    visibility: hidden;\n}\n\nh1:hover > a.headerlink,\nh2:hover > a.headerlink,\nh3:hover > a.headerlink,\nh4:hover > a.headerlink,\nh5:hover > a.headerlink,\nh6:hover > a.headerlink,\ndt:hover > a.headerlink,\ncaption:hover > a.headerlink,\np.caption:hover > a.headerlink,\ndiv.code-block-caption:hover > a.headerlink {\n    visibility: visible;\n}\n\ndiv.body p.caption {\n    text-align: inherit;\n}\n\ndiv.body td {\n    text-align: left;\n}\n\n.first {\n    margin-top: 0 !important;\n}\n\np.rubric {\n    margin-top: 30px;\n    font-weight: bold;\n}\n\nimg.align-left, .figure.align-left, object.align-left {\n    clear: left;\n    float: left;\n    margin-right: 1em;\n}\n\nimg.align-right, .figure.align-right, object.align-right {\n    clear: right;\n    float: right;\n    margin-left: 1em;\n}\n\nimg.align-center, .figure.align-center, object.align-center {\n  display: block;\n  margin-left: auto;\n  margin-right: auto;\n}\n\n.align-left {\n    text-align: left;\n}\n\n.align-center {\n    text-align: center;\n}\n\n.align-right {\n    text-align: right;\n}\n\n/* -- sidebars -------------------------------------------------------------- */\n\ndiv.sidebar {\n    margin: 0 0 0.5em 1em;\n    border: 1px solid #ddb;\n    padding: 7px 7px 0 7px;\n    background-color: #ffe;\n    width: 40%;\n    float: right;\n}\n\np.sidebar-title {\n    font-weight: bold;\n}\n\n/* -- topics ---------------------------------------------------------------- */\n\ndiv.topic {\n    border: 1px solid #ccc;\n    padding: 7px 7px 0 7px;\n    margin: 10px 0 10px 0;\n}\n\np.topic-title {\n    font-size: 1.1em;\n    font-weight: bold;\n    margin-top: 10px;\n}\n\n/* -- admonitions ----------------------------------------------------------- */\n\ndiv.admonition {\n    margin-top: 10px;\n    margin-bottom: 10px;\n    padding: 7px;\n}\n\ndiv.admonition dt {\n    font-weight: bold;\n}\n\ndiv.admonition dl {\n    margin-bottom: 0;\n}\n\np.admonition-title {\n    margin: 0px 10px 5px 0px;\n    font-weight: bold;\n}\n\ndiv.body p.centered {\n    text-align: center;\n    margin-top: 25px;\n}\n\n/* -- tables ---------------------------------------------------------------- */\n\ntable.docutils {\n    border: 0;\n    border-collapse: collapse;\n}\n\ntable.align-center {\n    margin-left: auto;\n    margin-right: auto;\n}\n\ntable caption span.caption-number {\n    font-style: italic;\n}\n\ntable caption span.caption-text {\n}\n\ntable.docutils td, table.docutils th {\n    padding: 1px 8px 1px 5px;\n    border-top: 0;\n    border-left: 0;\n    border-right: 0;\n    border-bottom: 1px solid #aaa;\n}\n\ntable.footnote td, table.footnote th {\n    border: 0 !important;\n}\n\nth {\n    text-align: left;\n    padding-right: 5px;\n}\n\ntable.citation {\n    border-left: solid 1px gray;\n    margin-left: 1px;\n}\n\ntable.citation td {\n    border-bottom: none;\n}\n\n/* -- figures --------------------------------------------------------------- */\n\ndiv.figure {\n    margin: 0.5em;\n    padding: 0.5em;\n}\n\ndiv.figure p.caption {\n    padding: 0.3em;\n}\n\ndiv.figure p.caption span.caption-number {\n    font-style: italic;\n}\n\ndiv.figure p.caption span.caption-text {\n}\n\n/* -- field list styles ----------------------------------------------------- */\n\ntable.field-list td, table.field-list th {\n    border: 0 !important;\n}\n\n.field-list ul {\n    margin: 0;\n    padding-left: 1em;\n}\n\n.field-list p {\n    margin: 0;\n}\n\n.field-name {\n    -moz-hyphens: manual;\n    -ms-hyphens: manual;\n    -webkit-hyphens: manual;\n    hyphens: manual;\n}\n\n/* -- hlist styles ---------------------------------------------------------- */\n\ntable.hlist td {\n    vertical-align: top;\n}\n\n\n/* -- other body styles ----------------------------------------------------- */\n\nol.arabic {\n    list-style: decimal;\n}\n\nol.loweralpha {\n    list-style: lower-alpha;\n}\n\nol.upperalpha {\n    list-style: upper-alpha;\n}\n\nol.lowerroman {\n    list-style: lower-roman;\n}\n\nol.upperroman {\n    list-style: upper-roman;\n}\n\ndl {\n    margin-bottom: 15px;\n}\n\ndd p {\n    margin-top: 0px;\n}\n\ndd ul, dd table {\n    margin-bottom: 10px;\n}\n\ndd {\n    margin-top: 3px;\n    margin-bottom: 10px;\n    margin-left: 30px;\n}\n\ndt:target, span.highlighted {\n    background-color: #fbe54e;\n}\n\nrect.highlighted {\n    fill: #fbe54e;\n}\n\ndl.glossary dt {\n    font-weight: bold;\n    font-size: 1.1em;\n}\n\n.optional {\n    font-size: 1.3em;\n}\n\n.sig-paren {\n    font-size: larger;\n}\n\n.versionmodified {\n    font-style: italic;\n}\n\n.system-message {\n    background-color: #fda;\n    padding: 5px;\n    border: 3px solid red;\n}\n\n.footnote:target  {\n    background-color: #ffa;\n}\n\n.line-block {\n    display: block;\n    margin-top: 1em;\n    margin-bottom: 1em;\n}\n\n.line-block .line-block {\n    margin-top: 0;\n    margin-bottom: 0;\n    margin-left: 1.5em;\n}\n\n.guilabel, .menuselection {\n    font-family: sans-serif;\n}\n\n.accelerator {\n    text-decoration: underline;\n}\n\n.classifier {\n    font-style: oblique;\n}\n\nabbr, acronym {\n    border-bottom: dotted 1px;\n    cursor: help;\n}\n\n/* -- code displays --------------------------------------------------------- */\n\npre {\n    overflow: auto;\n    overflow-y: hidden;  /* fixes display issues on Chrome browsers */\n}\n\nspan.pre {\n    -moz-hyphens: none;\n    -ms-hyphens: none;\n    -webkit-hyphens: none;\n    hyphens: none;\n}\n\ntd.linenos pre {\n    padding: 5px 0px;\n    border: 0;\n    background-color: transparent;\n    color: #aaa;\n}\n\ntable.highlighttable {\n    margin-left: 0.5em;\n}\n\ntable.highlighttable td {\n    padding: 0 0.5em 0 0.5em;\n}\n\ndiv.code-block-caption {\n    padding: 2px 5px;\n    font-size: small;\n}\n\ndiv.code-block-caption code {\n    background-color: transparent;\n}\n\ndiv.code-block-caption + div > div.highlight > pre {\n    margin-top: 0;\n}\n\ndiv.code-block-caption span.caption-number {\n    padding: 0.1em 0.3em;\n    font-style: italic;\n}\n\ndiv.code-block-caption span.caption-text {\n}\n\ndiv.literal-block-wrapper {\n    padding: 1em 1em 0;\n}\n\ndiv.literal-block-wrapper div.highlight {\n    margin: 0;\n}\n\ncode.descname {\n    background-color: transparent;\n    font-weight: bold;\n    font-size: 1.2em;\n}\n\ncode.descclassname {\n    background-color: transparent;\n}\n\ncode.xref, a code {\n    background-color: transparent;\n    font-weight: bold;\n}\n\nh1 code, h2 code, h3 code, h4 code, h5 code, h6 code {\n    background-color: transparent;\n}\n\n.viewcode-link {\n    float: right;\n}\n\n.viewcode-back {\n    float: right;\n    font-family: sans-serif;\n}\n\ndiv.viewcode-block:target {\n    margin: -1px -10px;\n    padding: 0 10px;\n}\n\n/* -- math display ---------------------------------------------------------- */\n\nimg.math {\n    vertical-align: middle;\n}\n\ndiv.body div.math p {\n    text-align: center;\n}\n\nspan.eqno {\n    float: right;\n}\n\nspan.eqno a.headerlink {\n    position: relative;\n    left: 0px;\n    z-index: 1;\n}\n\ndiv.math:hover a.headerlink {\n    visibility: visible;\n}\n\n/* -- printout stylesheet --------------------------------------------------- */\n\n@media print {\n    div.document,\n    div.documentwrapper,\n    div.bodywrapper {\n        margin: 0 !important;\n        width: 100%;\n    }\n\n    div.sphinxsidebar,\n    div.related,\n    div.footer,\n    #top-link {\n        display: none;\n    }\n}"
  },
  {
    "path": "docs/_static/css/badge_only.css",
    "content": "﻿.fa:before{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:\"\"}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-weight:normal;font-style:normal;src:url(\"../fonts/fontawesome-webfont.eot\");src:url(\"../fonts/fontawesome-webfont.eot?#iefix\") format(\"embedded-opentype\"),url(\"../fonts/fontawesome-webfont.woff\") format(\"woff\"),url(\"../fonts/fontawesome-webfont.ttf\") format(\"truetype\"),url(\"../fonts/fontawesome-webfont.svg#FontAwesome\") format(\"svg\")}.fa:before{display:inline-block;font-family:FontAwesome;font-style:normal;font-weight:normal;line-height:1;text-decoration:inherit}a .fa{display:inline-block;text-decoration:inherit}li .fa{display:inline-block}li .fa-large:before,li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-0.8em}ul.fas li .fa{width:.8em}ul.fas li .fa-large:before,ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before{content:\"\"}.icon-book:before{content:\"\"}.fa-caret-down:before{content:\"\"}.icon-caret-down:before{content:\"\"}.fa-caret-up:before{content:\"\"}.icon-caret-up:before{content:\"\"}.fa-caret-left:before{content:\"\"}.icon-caret-left:before{content:\"\"}.fa-caret-right:before{content:\"\"}.icon-caret-right:before{content:\"\"}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:\"Lato\",\"proxima-nova\",\"Helvetica Neue\",Arial,sans-serif;z-index:400}.rst-versions a{color:#2980B9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27AE60;*zoom:1}.rst-versions .rst-current-version:before,.rst-versions .rst-current-version:after{display:table;content:\"\"}.rst-versions .rst-current-version:after{clear:both}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book{float:left}.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#E74C3C;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#F1C40F;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:gray;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:solid 1px #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .icon-book{float:none}.rst-versions.rst-badge .fa-book{float:none}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book{float:left}.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge .rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width: 768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}}\n"
  },
  {
    "path": "docs/_static/css/theme.css",
    "content": "/* sphinx_rtd_theme version 0.4.3 | MIT license */\n/* Built 20190212 16:02 */\n*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}audio:not([controls]){display:none}[hidden]{display:none}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a:hover,a:active{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}blockquote{margin:0}dfn{font-style:italic}ins{background:#ff9;color:#000;text-decoration:none}mark{background:#ff0;color:#000;font-style:italic;font-weight:bold}pre,code,.rst-content tt,.rst-content code,kbd,samp{font-family:monospace,serif;_font-family:\"courier new\",monospace;font-size:1em}pre{white-space:pre}q{quotes:none}q:before,q:after{content:\"\";content:none}small{font-size:85%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}ul,ol,dl{margin:0;padding:0;list-style:none;list-style-image:none}li{list-style:none}dd{margin:0}img{border:0;-ms-interpolation-mode:bicubic;vertical-align:middle;max-width:100%}svg:not(:root){overflow:hidden}figure{margin:0}form{margin:0}fieldset{border:0;margin:0;padding:0}label{cursor:pointer}legend{border:0;*margin-left:-7px;padding:0;white-space:normal}button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}button,input{line-height:normal}button,input[type=\"button\"],input[type=\"reset\"],input[type=\"submit\"]{cursor:pointer;-webkit-appearance:button;*overflow:visible}button[disabled],input[disabled]{cursor:default}input[type=\"checkbox\"],input[type=\"radio\"]{box-sizing:border-box;padding:0;*width:13px;*height:13px}input[type=\"search\"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type=\"search\"]::-webkit-search-decoration,input[type=\"search\"]::-webkit-search-cancel-button{-webkit-appearance:none}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}textarea{overflow:auto;vertical-align:top;resize:vertical}table{border-collapse:collapse;border-spacing:0}td{vertical-align:top}.chromeframe{margin:.2em 0;background:#ccc;color:#000;padding:.2em 0}.ir{display:block;border:0;text-indent:-999em;overflow:hidden;background-color:transparent;background-repeat:no-repeat;text-align:left;direction:ltr;*line-height:0}.ir br{display:none}.hidden{display:none !important;visibility:hidden}.visuallyhidden{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.visuallyhidden.focusable:active,.visuallyhidden.focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}.invisible{visibility:hidden}.relative{position:relative}big,small{font-size:100%}@media print{html,body,section{background:none !important}*{box-shadow:none !important;text-shadow:none !important;filter:none !important;-ms-filter:none !important}a,a:visited{text-decoration:underline}.ir a:after,a[href^=\"javascript:\"]:after,a[href^=\"#\"]:after{content:\"\"}pre,blockquote{page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:.5cm}p,h2,.rst-content .toctree-wrapper p.caption,h3{orphans:3;widows:3}h2,.rst-content .toctree-wrapper p.caption,h3{page-break-after:avoid}}.fa:before,.wy-menu-vertical li span.toctree-expand:before,.wy-menu-vertical li.on a span.toctree-expand:before,.wy-menu-vertical li.current>a span.toctree-expand:before,.rst-content .admonition-title:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content dl dt .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content .code-block-caption .headerlink:before,.rst-content tt.download span:first-child:before,.rst-content code.download span:first-child:before,.icon:before,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-alert,.rst-content .note,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .warning,.rst-content .seealso,.rst-content .admonition-todo,.rst-content .admonition,.btn,input[type=\"text\"],input[type=\"password\"],input[type=\"email\"],input[type=\"url\"],input[type=\"date\"],input[type=\"month\"],input[type=\"time\"],input[type=\"datetime\"],input[type=\"datetime-local\"],input[type=\"week\"],input[type=\"number\"],input[type=\"search\"],input[type=\"tel\"],input[type=\"color\"],select,textarea,.wy-menu-vertical li.on a,.wy-menu-vertical li.current>a,.wy-side-nav-search>a,.wy-side-nav-search .wy-dropdown>a,.wy-nav-top a{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:\"\"}.clearfix:after{clear:both}/*!\n *  Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome\n *  License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)\n */@font-face{font-family:'FontAwesome';src:url(\"../fonts/fontawesome-webfont.eot?v=4.7.0\");src:url(\"../fonts/fontawesome-webfont.eot?#iefix&v=4.7.0\") format(\"embedded-opentype\"),url(\"../fonts/fontawesome-webfont.woff2?v=4.7.0\") format(\"woff2\"),url(\"../fonts/fontawesome-webfont.woff?v=4.7.0\") format(\"woff\"),url(\"../fonts/fontawesome-webfont.ttf?v=4.7.0\") format(\"truetype\"),url(\"../fonts/fontawesome-webfont.svg?v=4.7.0#fontawesomeregular\") format(\"svg\");font-weight:normal;font-style:normal}.fa,.wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.current>a span.toctree-expand,.rst-content .admonition-title,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content dl dt .headerlink,.rst-content p.caption .headerlink,.rst-content table>caption .headerlink,.rst-content .code-block-caption .headerlink,.rst-content tt.download span:first-child,.rst-content code.download span:first-child,.icon{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.3333333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.2857142857em;text-align:center}.fa-ul{padding-left:0;margin-left:2.1428571429em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.1428571429em;width:2.1428571429em;top:.1428571429em;text-align:center}.fa-li.fa-lg{left:-1.8571428571em}.fa-border{padding:.2em .25em .15em;border:solid 0.08em #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left,.wy-menu-vertical li span.fa-pull-left.toctree-expand,.wy-menu-vertical li.on a span.fa-pull-left.toctree-expand,.wy-menu-vertical li.current>a span.fa-pull-left.toctree-expand,.rst-content .fa-pull-left.admonition-title,.rst-content h1 .fa-pull-left.headerlink,.rst-content h2 .fa-pull-left.headerlink,.rst-content h3 .fa-pull-left.headerlink,.rst-content h4 .fa-pull-left.headerlink,.rst-content h5 .fa-pull-left.headerlink,.rst-content h6 .fa-pull-left.headerlink,.rst-content dl dt .fa-pull-left.headerlink,.rst-content p.caption .fa-pull-left.headerlink,.rst-content table>caption .fa-pull-left.headerlink,.rst-content .code-block-caption .fa-pull-left.headerlink,.rst-content tt.download span.fa-pull-left:first-child,.rst-content code.download span.fa-pull-left:first-child,.fa-pull-left.icon{margin-right:.3em}.fa.fa-pull-right,.wy-menu-vertical li span.fa-pull-right.toctree-expand,.wy-menu-vertical li.on a span.fa-pull-right.toctree-expand,.wy-menu-vertical li.current>a span.fa-pull-right.toctree-expand,.rst-content .fa-pull-right.admonition-title,.rst-content h1 .fa-pull-right.headerlink,.rst-content h2 .fa-pull-right.headerlink,.rst-content h3 .fa-pull-right.headerlink,.rst-content h4 .fa-pull-right.headerlink,.rst-content h5 .fa-pull-right.headerlink,.rst-content h6 .fa-pull-right.headerlink,.rst-content dl dt .fa-pull-right.headerlink,.rst-content p.caption .fa-pull-right.headerlink,.rst-content table>caption .fa-pull-right.headerlink,.rst-content .code-block-caption .fa-pull-right.headerlink,.rst-content tt.download span.fa-pull-right:first-child,.rst-content code.download span.fa-pull-right:first-child,.fa-pull-right.icon{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left,.wy-menu-vertical li span.pull-left.toctree-expand,.wy-menu-vertical li.on a span.pull-left.toctree-expand,.wy-menu-vertical li.current>a span.pull-left.toctree-expand,.rst-content .pull-left.admonition-title,.rst-content h1 .pull-left.headerlink,.rst-content h2 .pull-left.headerlink,.rst-content h3 .pull-left.headerlink,.rst-content h4 .pull-left.headerlink,.rst-content h5 .pull-left.headerlink,.rst-content h6 .pull-left.headerlink,.rst-content dl dt .pull-left.headerlink,.rst-content p.caption .pull-left.headerlink,.rst-content table>caption .pull-left.headerlink,.rst-content .code-block-caption .pull-left.headerlink,.rst-content tt.download span.pull-left:first-child,.rst-content code.download span.pull-left:first-child,.pull-left.icon{margin-right:.3em}.fa.pull-right,.wy-menu-vertical li span.pull-right.toctree-expand,.wy-menu-vertical li.on a span.pull-right.toctree-expand,.wy-menu-vertical li.current>a span.pull-right.toctree-expand,.rst-content .pull-right.admonition-title,.rst-content h1 .pull-right.headerlink,.rst-content h2 .pull-right.headerlink,.rst-content h3 .pull-right.headerlink,.rst-content h4 .pull-right.headerlink,.rst-content h5 .pull-right.headerlink,.rst-content h6 .pull-right.headerlink,.rst-content dl dt .pull-right.headerlink,.rst-content p.caption .pull-right.headerlink,.rst-content table>caption .pull-right.headerlink,.rst-content .code-block-caption .pull-right.headerlink,.rst-content tt.download span.pull-right:first-child,.rst-content code.download span.pull-right:first-child,.pull-right.icon{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:\"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)\";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:\"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)\";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:\"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)\";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:\"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)\";-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{-ms-filter:\"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)\";-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:\"\"}.fa-music:before{content:\"\"}.fa-search:before,.icon-search:before{content:\"\"}.fa-envelope-o:before{content:\"\"}.fa-heart:before{content:\"\"}.fa-star:before{content:\"\"}.fa-star-o:before{content:\"\"}.fa-user:before{content:\"\"}.fa-film:before{content:\"\"}.fa-th-large:before{content:\"\"}.fa-th:before{content:\"\"}.fa-th-list:before{content:\"\"}.fa-check:before{content:\"\"}.fa-remove:before,.fa-close:before,.fa-times:before{content:\"\"}.fa-search-plus:before{content:\"\"}.fa-search-minus:before{content:\"\"}.fa-power-off:before{content:\"\"}.fa-signal:before{content:\"\"}.fa-gear:before,.fa-cog:before{content:\"\"}.fa-trash-o:before{content:\"\"}.fa-home:before,.icon-home:before{content:\"\"}.fa-file-o:before{content:\"\"}.fa-clock-o:before{content:\"\"}.fa-road:before{content:\"\"}.fa-download:before,.rst-content tt.download span:first-child:before,.rst-content code.download span:first-child:before{content:\"\"}.fa-arrow-circle-o-down:before{content:\"\"}.fa-arrow-circle-o-up:before{content:\"\"}.fa-inbox:before{content:\"\"}.fa-play-circle-o:before{content:\"\"}.fa-rotate-right:before,.fa-repeat:before{content:\"\"}.fa-refresh:before{content:\"\"}.fa-list-alt:before{content:\"\"}.fa-lock:before{content:\"\"}.fa-flag:before{content:\"\"}.fa-headphones:before{content:\"\"}.fa-volume-off:before{content:\"\"}.fa-volume-down:before{content:\"\"}.fa-volume-up:before{content:\"\"}.fa-qrcode:before{content:\"\"}.fa-barcode:before{content:\"\"}.fa-tag:before{content:\"\"}.fa-tags:before{content:\"\"}.fa-book:before,.icon-book:before{content:\"\"}.fa-bookmark:before{content:\"\"}.fa-print:before{content:\"\"}.fa-camera:before{content:\"\"}.fa-font:before{content:\"\"}.fa-bold:before{content:\"\"}.fa-italic:before{content:\"\"}.fa-text-height:before{content:\"\"}.fa-text-width:before{content:\"\"}.fa-align-left:before{content:\"\"}.fa-align-center:before{content:\"\"}.fa-align-right:before{content:\"\"}.fa-align-justify:before{content:\"\"}.fa-list:before{content:\"\"}.fa-dedent:before,.fa-outdent:before{content:\"\"}.fa-indent:before{content:\"\"}.fa-video-camera:before{content:\"\"}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:\"\"}.fa-pencil:before{content:\"\"}.fa-map-marker:before{content:\"\"}.fa-adjust:before{content:\"\"}.fa-tint:before{content:\"\"}.fa-edit:before,.fa-pencil-square-o:before{content:\"\"}.fa-share-square-o:before{content:\"\"}.fa-check-square-o:before{content:\"\"}.fa-arrows:before{content:\"\"}.fa-step-backward:before{content:\"\"}.fa-fast-backward:before{content:\"\"}.fa-backward:before{content:\"\"}.fa-play:before{content:\"\"}.fa-pause:before{content:\"\"}.fa-stop:before{content:\"\"}.fa-forward:before{content:\"\"}.fa-fast-forward:before{content:\"\"}.fa-step-forward:before{content:\"\"}.fa-eject:before{content:\"\"}.fa-chevron-left:before{content:\"\"}.fa-chevron-right:before{content:\"\"}.fa-plus-circle:before{content:\"\"}.fa-minus-circle:before{content:\"\"}.fa-times-circle:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before{content:\"\"}.fa-check-circle:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before{content:\"\"}.fa-question-circle:before{content:\"\"}.fa-info-circle:before{content:\"\"}.fa-crosshairs:before{content:\"\"}.fa-times-circle-o:before{content:\"\"}.fa-check-circle-o:before{content:\"\"}.fa-ban:before{content:\"\"}.fa-arrow-left:before{content:\"\"}.fa-arrow-right:before{content:\"\"}.fa-arrow-up:before{content:\"\"}.fa-arrow-down:before{content:\"\"}.fa-mail-forward:before,.fa-share:before{content:\"\"}.fa-expand:before{content:\"\"}.fa-compress:before{content:\"\"}.fa-plus:before{content:\"\"}.fa-minus:before{content:\"\"}.fa-asterisk:before{content:\"\"}.fa-exclamation-circle:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.rst-content .admonition-title:before{content:\"\"}.fa-gift:before{content:\"\"}.fa-leaf:before{content:\"\"}.fa-fire:before,.icon-fire:before{content:\"\"}.fa-eye:before{content:\"\"}.fa-eye-slash:before{content:\"\"}.fa-warning:before,.fa-exclamation-triangle:before{content:\"\"}.fa-plane:before{content:\"\"}.fa-calendar:before{content:\"\"}.fa-random:before{content:\"\"}.fa-comment:before{content:\"\"}.fa-magnet:before{content:\"\"}.fa-chevron-up:before{content:\"\"}.fa-chevron-down:before{content:\"\"}.fa-retweet:before{content:\"\"}.fa-shopping-cart:before{content:\"\"}.fa-folder:before{content:\"\"}.fa-folder-open:before{content:\"\"}.fa-arrows-v:before{content:\"\"}.fa-arrows-h:before{content:\"\"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:\"\"}.fa-twitter-square:before{content:\"\"}.fa-facebook-square:before{content:\"\"}.fa-camera-retro:before{content:\"\"}.fa-key:before{content:\"\"}.fa-gears:before,.fa-cogs:before{content:\"\"}.fa-comments:before{content:\"\"}.fa-thumbs-o-up:before{content:\"\"}.fa-thumbs-o-down:before{content:\"\"}.fa-star-half:before{content:\"\"}.fa-heart-o:before{content:\"\"}.fa-sign-out:before{content:\"\"}.fa-linkedin-square:before{content:\"\"}.fa-thumb-tack:before{content:\"\"}.fa-external-link:before{content:\"\"}.fa-sign-in:before{content:\"\"}.fa-trophy:before{content:\"\"}.fa-github-square:before{content:\"\"}.fa-upload:before{content:\"\"}.fa-lemon-o:before{content:\"\"}.fa-phone:before{content:\"\"}.fa-square-o:before{content:\"\"}.fa-bookmark-o:before{content:\"\"}.fa-phone-square:before{content:\"\"}.fa-twitter:before{content:\"\"}.fa-facebook-f:before,.fa-facebook:before{content:\"\"}.fa-github:before,.icon-github:before{content:\"\"}.fa-unlock:before{content:\"\"}.fa-credit-card:before{content:\"\"}.fa-feed:before,.fa-rss:before{content:\"\"}.fa-hdd-o:before{content:\"\"}.fa-bullhorn:before{content:\"\"}.fa-bell:before{content:\"\"}.fa-certificate:before{content:\"\"}.fa-hand-o-right:before{content:\"\"}.fa-hand-o-left:before{content:\"\"}.fa-hand-o-up:before{content:\"\"}.fa-hand-o-down:before{content:\"\"}.fa-arrow-circle-left:before,.icon-circle-arrow-left:before{content:\"\"}.fa-arrow-circle-right:before,.icon-circle-arrow-right:before{content:\"\"}.fa-arrow-circle-up:before{content:\"\"}.fa-arrow-circle-down:before{content:\"\"}.fa-globe:before{content:\"\"}.fa-wrench:before{content:\"\"}.fa-tasks:before{content:\"\"}.fa-filter:before{content:\"\"}.fa-briefcase:before{content:\"\"}.fa-arrows-alt:before{content:\"\"}.fa-group:before,.fa-users:before{content:\"\"}.fa-chain:before,.fa-link:before,.icon-link:before{content:\"\"}.fa-cloud:before{content:\"\"}.fa-flask:before{content:\"\"}.fa-cut:before,.fa-scissors:before{content:\"\"}.fa-copy:before,.fa-files-o:before{content:\"\"}.fa-paperclip:before{content:\"\"}.fa-save:before,.fa-floppy-o:before{content:\"\"}.fa-square:before{content:\"\"}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:\"\"}.fa-list-ul:before{content:\"\"}.fa-list-ol:before{content:\"\"}.fa-strikethrough:before{content:\"\"}.fa-underline:before{content:\"\"}.fa-table:before{content:\"\"}.fa-magic:before{content:\"\"}.fa-truck:before{content:\"\"}.fa-pinterest:before{content:\"\"}.fa-pinterest-square:before{content:\"\"}.fa-google-plus-square:before{content:\"\"}.fa-google-plus:before{content:\"\"}.fa-money:before{content:\"\"}.fa-caret-down:before,.wy-dropdown .caret:before,.icon-caret-down:before{content:\"\"}.fa-caret-up:before{content:\"\"}.fa-caret-left:before{content:\"\"}.fa-caret-right:before{content:\"\"}.fa-columns:before{content:\"\"}.fa-unsorted:before,.fa-sort:before{content:\"\"}.fa-sort-down:before,.fa-sort-desc:before{content:\"\"}.fa-sort-up:before,.fa-sort-asc:before{content:\"\"}.fa-envelope:before{content:\"\"}.fa-linkedin:before{content:\"\"}.fa-rotate-left:before,.fa-undo:before{content:\"\"}.fa-legal:before,.fa-gavel:before{content:\"\"}.fa-dashboard:before,.fa-tachometer:before{content:\"\"}.fa-comment-o:before{content:\"\"}.fa-comments-o:before{content:\"\"}.fa-flash:before,.fa-bolt:before{content:\"\"}.fa-sitemap:before{content:\"\"}.fa-umbrella:before{content:\"\"}.fa-paste:before,.fa-clipboard:before{content:\"\"}.fa-lightbulb-o:before{content:\"\"}.fa-exchange:before{content:\"\"}.fa-cloud-download:before{content:\"\"}.fa-cloud-upload:before{content:\"\"}.fa-user-md:before{content:\"\"}.fa-stethoscope:before{content:\"\"}.fa-suitcase:before{content:\"\"}.fa-bell-o:before{content:\"\"}.fa-coffee:before{content:\"\"}.fa-cutlery:before{content:\"\"}.fa-file-text-o:before{content:\"\"}.fa-building-o:before{content:\"\"}.fa-hospital-o:before{content:\"\"}.fa-ambulance:before{content:\"\"}.fa-medkit:before{content:\"\"}.fa-fighter-jet:before{content:\"\"}.fa-beer:before{content:\"\"}.fa-h-square:before{content:\"\"}.fa-plus-square:before{content:\"\"}.fa-angle-double-left:before{content:\"\"}.fa-angle-double-right:before{content:\"\"}.fa-angle-double-up:before{content:\"\"}.fa-angle-double-down:before{content:\"\"}.fa-angle-left:before{content:\"\"}.fa-angle-right:before{content:\"\"}.fa-angle-up:before{content:\"\"}.fa-angle-down:before{content:\"\"}.fa-desktop:before{content:\"\"}.fa-laptop:before{content:\"\"}.fa-tablet:before{content:\"\"}.fa-mobile-phone:before,.fa-mobile:before{content:\"\"}.fa-circle-o:before{content:\"\"}.fa-quote-left:before{content:\"\"}.fa-quote-right:before{content:\"\"}.fa-spinner:before{content:\"\"}.fa-circle:before{content:\"\"}.fa-mail-reply:before,.fa-reply:before{content:\"\"}.fa-github-alt:before{content:\"\"}.fa-folder-o:before{content:\"\"}.fa-folder-open-o:before{content:\"\"}.fa-smile-o:before{content:\"\"}.fa-frown-o:before{content:\"\"}.fa-meh-o:before{content:\"\"}.fa-gamepad:before{content:\"\"}.fa-keyboard-o:before{content:\"\"}.fa-flag-o:before{content:\"\"}.fa-flag-checkered:before{content:\"\"}.fa-terminal:before{content:\"\"}.fa-code:before{content:\"\"}.fa-mail-reply-all:before,.fa-reply-all:before{content:\"\"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:\"\"}.fa-location-arrow:before{content:\"\"}.fa-crop:before{content:\"\"}.fa-code-fork:before{content:\"\"}.fa-unlink:before,.fa-chain-broken:before{content:\"\"}.fa-question:before{content:\"\"}.fa-info:before{content:\"\"}.fa-exclamation:before{content:\"\"}.fa-superscript:before{content:\"\"}.fa-subscript:before{content:\"\"}.fa-eraser:before{content:\"\"}.fa-puzzle-piece:before{content:\"\"}.fa-microphone:before{content:\"\"}.fa-microphone-slash:before{content:\"\"}.fa-shield:before{content:\"\"}.fa-calendar-o:before{content:\"\"}.fa-fire-extinguisher:before{content:\"\"}.fa-rocket:before{content:\"\"}.fa-maxcdn:before{content:\"\"}.fa-chevron-circle-left:before{content:\"\"}.fa-chevron-circle-right:before{content:\"\"}.fa-chevron-circle-up:before{content:\"\"}.fa-chevron-circle-down:before{content:\"\"}.fa-html5:before{content:\"\"}.fa-css3:before{content:\"\"}.fa-anchor:before{content:\"\"}.fa-unlock-alt:before{content:\"\"}.fa-bullseye:before{content:\"\"}.fa-ellipsis-h:before{content:\"\"}.fa-ellipsis-v:before{content:\"\"}.fa-rss-square:before{content:\"\"}.fa-play-circle:before{content:\"\"}.fa-ticket:before{content:\"\"}.fa-minus-square:before{content:\"\"}.fa-minus-square-o:before,.wy-menu-vertical li.on a span.toctree-expand:before,.wy-menu-vertical li.current>a span.toctree-expand:before{content:\"\"}.fa-level-up:before{content:\"\"}.fa-level-down:before{content:\"\"}.fa-check-square:before{content:\"\"}.fa-pencil-square:before{content:\"\"}.fa-external-link-square:before{content:\"\"}.fa-share-square:before{content:\"\"}.fa-compass:before{content:\"\"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:\"\"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:\"\"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:\"\"}.fa-euro:before,.fa-eur:before{content:\"\"}.fa-gbp:before{content:\"\"}.fa-dollar:before,.fa-usd:before{content:\"\"}.fa-rupee:before,.fa-inr:before{content:\"\"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:\"\"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:\"\"}.fa-won:before,.fa-krw:before{content:\"\"}.fa-bitcoin:before,.fa-btc:before{content:\"\"}.fa-file:before{content:\"\"}.fa-file-text:before{content:\"\"}.fa-sort-alpha-asc:before{content:\"\"}.fa-sort-alpha-desc:before{content:\"\"}.fa-sort-amount-asc:before{content:\"\"}.fa-sort-amount-desc:before{content:\"\"}.fa-sort-numeric-asc:before{content:\"\"}.fa-sort-numeric-desc:before{content:\"\"}.fa-thumbs-up:before{content:\"\"}.fa-thumbs-down:before{content:\"\"}.fa-youtube-square:before{content:\"\"}.fa-youtube:before{content:\"\"}.fa-xing:before{content:\"\"}.fa-xing-square:before{content:\"\"}.fa-youtube-play:before{content:\"\"}.fa-dropbox:before{content:\"\"}.fa-stack-overflow:before{content:\"\"}.fa-instagram:before{content:\"\"}.fa-flickr:before{content:\"\"}.fa-adn:before{content:\"\"}.fa-bitbucket:before,.icon-bitbucket:before{content:\"\"}.fa-bitbucket-square:before{content:\"\"}.fa-tumblr:before{content:\"\"}.fa-tumblr-square:before{content:\"\"}.fa-long-arrow-down:before{content:\"\"}.fa-long-arrow-up:before{content:\"\"}.fa-long-arrow-left:before{content:\"\"}.fa-long-arrow-right:before{content:\"\"}.fa-apple:before{content:\"\"}.fa-windows:before{content:\"\"}.fa-android:before{content:\"\"}.fa-linux:before{content:\"\"}.fa-dribbble:before{content:\"\"}.fa-skype:before{content:\"\"}.fa-foursquare:before{content:\"\"}.fa-trello:before{content:\"\"}.fa-female:before{content:\"\"}.fa-male:before{content:\"\"}.fa-gittip:before,.fa-gratipay:before{content:\"\"}.fa-sun-o:before{content:\"\"}.fa-moon-o:before{content:\"\"}.fa-archive:before{content:\"\"}.fa-bug:before{content:\"\"}.fa-vk:before{content:\"\"}.fa-weibo:before{content:\"\"}.fa-renren:before{content:\"\"}.fa-pagelines:before{content:\"\"}.fa-stack-exchange:before{content:\"\"}.fa-arrow-circle-o-right:before{content:\"\"}.fa-arrow-circle-o-left:before{content:\"\"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:\"\"}.fa-dot-circle-o:before{content:\"\"}.fa-wheelchair:before{content:\"\"}.fa-vimeo-square:before{content:\"\"}.fa-turkish-lira:before,.fa-try:before{content:\"\"}.fa-plus-square-o:before,.wy-menu-vertical li span.toctree-expand:before{content:\"\"}.fa-space-shuttle:before{content:\"\"}.fa-slack:before{content:\"\"}.fa-envelope-square:before{content:\"\"}.fa-wordpress:before{content:\"\"}.fa-openid:before{content:\"\"}.fa-institution:before,.fa-bank:before,.fa-university:before{content:\"\"}.fa-mortar-board:before,.fa-graduation-cap:before{content:\"\"}.fa-yahoo:before{content:\"\"}.fa-google:before{content:\"\"}.fa-reddit:before{content:\"\"}.fa-reddit-square:before{content:\"\"}.fa-stumbleupon-circle:before{content:\"\"}.fa-stumbleupon:before{content:\"\"}.fa-delicious:before{content:\"\"}.fa-digg:before{content:\"\"}.fa-pied-piper-pp:before{content:\"\"}.fa-pied-piper-alt:before{content:\"\"}.fa-drupal:before{content:\"\"}.fa-joomla:before{content:\"\"}.fa-language:before{content:\"\"}.fa-fax:before{content:\"\"}.fa-building:before{content:\"\"}.fa-child:before{content:\"\"}.fa-paw:before{content:\"\"}.fa-spoon:before{content:\"\"}.fa-cube:before{content:\"\"}.fa-cubes:before{content:\"\"}.fa-behance:before{content:\"\"}.fa-behance-square:before{content:\"\"}.fa-steam:before{content:\"\"}.fa-steam-square:before{content:\"\"}.fa-recycle:before{content:\"\"}.fa-automobile:before,.fa-car:before{content:\"\"}.fa-cab:before,.fa-taxi:before{content:\"\"}.fa-tree:before{content:\"\"}.fa-spotify:before{content:\"\"}.fa-deviantart:before{content:\"\"}.fa-soundcloud:before{content:\"\"}.fa-database:before{content:\"\"}.fa-file-pdf-o:before{content:\"\"}.fa-file-word-o:before{content:\"\"}.fa-file-excel-o:before{content:\"\"}.fa-file-powerpoint-o:before{content:\"\"}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:\"\"}.fa-file-zip-o:before,.fa-file-archive-o:before{content:\"\"}.fa-file-sound-o:before,.fa-file-audio-o:before{content:\"\"}.fa-file-movie-o:before,.fa-file-video-o:before{content:\"\"}.fa-file-code-o:before{content:\"\"}.fa-vine:before{content:\"\"}.fa-codepen:before{content:\"\"}.fa-jsfiddle:before{content:\"\"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:\"\"}.fa-circle-o-notch:before{content:\"\"}.fa-ra:before,.fa-resistance:before,.fa-rebel:before{content:\"\"}.fa-ge:before,.fa-empire:before{content:\"\"}.fa-git-square:before{content:\"\"}.fa-git:before{content:\"\"}.fa-y-combinator-square:before,.fa-yc-square:before,.fa-hacker-news:before{content:\"\"}.fa-tencent-weibo:before{content:\"\"}.fa-qq:before{content:\"\"}.fa-wechat:before,.fa-weixin:before{content:\"\"}.fa-send:before,.fa-paper-plane:before{content:\"\"}.fa-send-o:before,.fa-paper-plane-o:before{content:\"\"}.fa-history:before{content:\"\"}.fa-circle-thin:before{content:\"\"}.fa-header:before{content:\"\"}.fa-paragraph:before{content:\"\"}.fa-sliders:before{content:\"\"}.fa-share-alt:before{content:\"\"}.fa-share-alt-square:before{content:\"\"}.fa-bomb:before{content:\"\"}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:\"\"}.fa-tty:before{content:\"\"}.fa-binoculars:before{content:\"\"}.fa-plug:before{content:\"\"}.fa-slideshare:before{content:\"\"}.fa-twitch:before{content:\"\"}.fa-yelp:before{content:\"\"}.fa-newspaper-o:before{content:\"\"}.fa-wifi:before{content:\"\"}.fa-calculator:before{content:\"\"}.fa-paypal:before{content:\"\"}.fa-google-wallet:before{content:\"\"}.fa-cc-visa:before{content:\"\"}.fa-cc-mastercard:before{content:\"\"}.fa-cc-discover:before{content:\"\"}.fa-cc-amex:before{content:\"\"}.fa-cc-paypal:before{content:\"\"}.fa-cc-stripe:before{content:\"\"}.fa-bell-slash:before{content:\"\"}.fa-bell-slash-o:before{content:\"\"}.fa-trash:before{content:\"\"}.fa-copyright:before{content:\"\"}.fa-at:before{content:\"\"}.fa-eyedropper:before{content:\"\"}.fa-paint-brush:before{content:\"\"}.fa-birthday-cake:before{content:\"\"}.fa-area-chart:before{content:\"\"}.fa-pie-chart:before{content:\"\"}.fa-line-chart:before{content:\"\"}.fa-lastfm:before{content:\"\"}.fa-lastfm-square:before{content:\"\"}.fa-toggle-off:before{content:\"\"}.fa-toggle-on:before{content:\"\"}.fa-bicycle:before{content:\"\"}.fa-bus:before{content:\"\"}.fa-ioxhost:before{content:\"\"}.fa-angellist:before{content:\"\"}.fa-cc:before{content:\"\"}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:\"\"}.fa-meanpath:before{content:\"\"}.fa-buysellads:before{content:\"\"}.fa-connectdevelop:before{content:\"\"}.fa-dashcube:before{content:\"\"}.fa-forumbee:before{content:\"\"}.fa-leanpub:before{content:\"\"}.fa-sellsy:before{content:\"\"}.fa-shirtsinbulk:before{content:\"\"}.fa-simplybuilt:before{content:\"\"}.fa-skyatlas:before{content:\"\"}.fa-cart-plus:before{content:\"\"}.fa-cart-arrow-down:before{content:\"\"}.fa-diamond:before{content:\"\"}.fa-ship:before{content:\"\"}.fa-user-secret:before{content:\"\"}.fa-motorcycle:before{content:\"\"}.fa-street-view:before{content:\"\"}.fa-heartbeat:before{content:\"\"}.fa-venus:before{content:\"\"}.fa-mars:before{content:\"\"}.fa-mercury:before{content:\"\"}.fa-intersex:before,.fa-transgender:before{content:\"\"}.fa-transgender-alt:before{content:\"\"}.fa-venus-double:before{content:\"\"}.fa-mars-double:before{content:\"\"}.fa-venus-mars:before{content:\"\"}.fa-mars-stroke:before{content:\"\"}.fa-mars-stroke-v:before{content:\"\"}.fa-mars-stroke-h:before{content:\"\"}.fa-neuter:before{content:\"\"}.fa-genderless:before{content:\"\"}.fa-facebook-official:before{content:\"\"}.fa-pinterest-p:before{content:\"\"}.fa-whatsapp:before{content:\"\"}.fa-server:before{content:\"\"}.fa-user-plus:before{content:\"\"}.fa-user-times:before{content:\"\"}.fa-hotel:before,.fa-bed:before{content:\"\"}.fa-viacoin:before{content:\"\"}.fa-train:before{content:\"\"}.fa-subway:before{content:\"\"}.fa-medium:before{content:\"\"}.fa-yc:before,.fa-y-combinator:before{content:\"\"}.fa-optin-monster:before{content:\"\"}.fa-opencart:before{content:\"\"}.fa-expeditedssl:before{content:\"\"}.fa-battery-4:before,.fa-battery:before,.fa-battery-full:before{content:\"\"}.fa-battery-3:before,.fa-battery-three-quarters:before{content:\"\"}.fa-battery-2:before,.fa-battery-half:before{content:\"\"}.fa-battery-1:before,.fa-battery-quarter:before{content:\"\"}.fa-battery-0:before,.fa-battery-empty:before{content:\"\"}.fa-mouse-pointer:before{content:\"\"}.fa-i-cursor:before{content:\"\"}.fa-object-group:before{content:\"\"}.fa-object-ungroup:before{content:\"\"}.fa-sticky-note:before{content:\"\"}.fa-sticky-note-o:before{content:\"\"}.fa-cc-jcb:before{content:\"\"}.fa-cc-diners-club:before{content:\"\"}.fa-clone:before{content:\"\"}.fa-balance-scale:before{content:\"\"}.fa-hourglass-o:before{content:\"\"}.fa-hourglass-1:before,.fa-hourglass-start:before{content:\"\"}.fa-hourglass-2:before,.fa-hourglass-half:before{content:\"\"}.fa-hourglass-3:before,.fa-hourglass-end:before{content:\"\"}.fa-hourglass:before{content:\"\"}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:\"\"}.fa-hand-stop-o:before,.fa-hand-paper-o:before{content:\"\"}.fa-hand-scissors-o:before{content:\"\"}.fa-hand-lizard-o:before{content:\"\"}.fa-hand-spock-o:before{content:\"\"}.fa-hand-pointer-o:before{content:\"\"}.fa-hand-peace-o:before{content:\"\"}.fa-trademark:before{content:\"\"}.fa-registered:before{content:\"\"}.fa-creative-commons:before{content:\"\"}.fa-gg:before{content:\"\"}.fa-gg-circle:before{content:\"\"}.fa-tripadvisor:before{content:\"\"}.fa-odnoklassniki:before{content:\"\"}.fa-odnoklassniki-square:before{content:\"\"}.fa-get-pocket:before{content:\"\"}.fa-wikipedia-w:before{content:\"\"}.fa-safari:before{content:\"\"}.fa-chrome:before{content:\"\"}.fa-firefox:before{content:\"\"}.fa-opera:before{content:\"\"}.fa-internet-explorer:before{content:\"\"}.fa-tv:before,.fa-television:before{content:\"\"}.fa-contao:before{content:\"\"}.fa-500px:before{content:\"\"}.fa-amazon:before{content:\"\"}.fa-calendar-plus-o:before{content:\"\"}.fa-calendar-minus-o:before{content:\"\"}.fa-calendar-times-o:before{content:\"\"}.fa-calendar-check-o:before{content:\"\"}.fa-industry:before{content:\"\"}.fa-map-pin:before{content:\"\"}.fa-map-signs:before{content:\"\"}.fa-map-o:before{content:\"\"}.fa-map:before{content:\"\"}.fa-commenting:before{content:\"\"}.fa-commenting-o:before{content:\"\"}.fa-houzz:before{content:\"\"}.fa-vimeo:before{content:\"\"}.fa-black-tie:before{content:\"\"}.fa-fonticons:before{content:\"\"}.fa-reddit-alien:before{content:\"\"}.fa-edge:before{content:\"\"}.fa-credit-card-alt:before{content:\"\"}.fa-codiepie:before{content:\"\"}.fa-modx:before{content:\"\"}.fa-fort-awesome:before{content:\"\"}.fa-usb:before{content:\"\"}.fa-product-hunt:before{content:\"\"}.fa-mixcloud:before{content:\"\"}.fa-scribd:before{content:\"\"}.fa-pause-circle:before{content:\"\"}.fa-pause-circle-o:before{content:\"\"}.fa-stop-circle:before{content:\"\"}.fa-stop-circle-o:before{content:\"\"}.fa-shopping-bag:before{content:\"\"}.fa-shopping-basket:before{content:\"\"}.fa-hashtag:before{content:\"\"}.fa-bluetooth:before{content:\"\"}.fa-bluetooth-b:before{content:\"\"}.fa-percent:before{content:\"\"}.fa-gitlab:before,.icon-gitlab:before{content:\"\"}.fa-wpbeginner:before{content:\"\"}.fa-wpforms:before{content:\"\"}.fa-envira:before{content:\"\"}.fa-universal-access:before{content:\"\"}.fa-wheelchair-alt:before{content:\"\"}.fa-question-circle-o:before{content:\"\"}.fa-blind:before{content:\"\"}.fa-audio-description:before{content:\"\"}.fa-volume-control-phone:before{content:\"\"}.fa-braille:before{content:\"\"}.fa-assistive-listening-systems:before{content:\"\"}.fa-asl-interpreting:before,.fa-american-sign-language-interpreting:before{content:\"\"}.fa-deafness:before,.fa-hard-of-hearing:before,.fa-deaf:before{content:\"\"}.fa-glide:before{content:\"\"}.fa-glide-g:before{content:\"\"}.fa-signing:before,.fa-sign-language:before{content:\"\"}.fa-low-vision:before{content:\"\"}.fa-viadeo:before{content:\"\"}.fa-viadeo-square:before{content:\"\"}.fa-snapchat:before{content:\"\"}.fa-snapchat-ghost:before{content:\"\"}.fa-snapchat-square:before{content:\"\"}.fa-pied-piper:before{content:\"\"}.fa-first-order:before{content:\"\"}.fa-yoast:before{content:\"\"}.fa-themeisle:before{content:\"\"}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:\"\"}.fa-fa:before,.fa-font-awesome:before{content:\"\"}.fa-handshake-o:before{content:\"\"}.fa-envelope-open:before{content:\"\"}.fa-envelope-open-o:before{content:\"\"}.fa-linode:before{content:\"\"}.fa-address-book:before{content:\"\"}.fa-address-book-o:before{content:\"\"}.fa-vcard:before,.fa-address-card:before{content:\"\"}.fa-vcard-o:before,.fa-address-card-o:before{content:\"\"}.fa-user-circle:before{content:\"\"}.fa-user-circle-o:before{content:\"\"}.fa-user-o:before{content:\"\"}.fa-id-badge:before{content:\"\"}.fa-drivers-license:before,.fa-id-card:before{content:\"\"}.fa-drivers-license-o:before,.fa-id-card-o:before{content:\"\"}.fa-quora:before{content:\"\"}.fa-free-code-camp:before{content:\"\"}.fa-telegram:before{content:\"\"}.fa-thermometer-4:before,.fa-thermometer:before,.fa-thermometer-full:before{content:\"\"}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:\"\"}.fa-thermometer-2:before,.fa-thermometer-half:before{content:\"\"}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:\"\"}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:\"\"}.fa-shower:before{content:\"\"}.fa-bathtub:before,.fa-s15:before,.fa-bath:before{content:\"\"}.fa-podcast:before{content:\"\"}.fa-window-maximize:before{content:\"\"}.fa-window-minimize:before{content:\"\"}.fa-window-restore:before{content:\"\"}.fa-times-rectangle:before,.fa-window-close:before{content:\"\"}.fa-times-rectangle-o:before,.fa-window-close-o:before{content:\"\"}.fa-bandcamp:before{content:\"\"}.fa-grav:before{content:\"\"}.fa-etsy:before{content:\"\"}.fa-imdb:before{content:\"\"}.fa-ravelry:before{content:\"\"}.fa-eercast:before{content:\"\"}.fa-microchip:before{content:\"\"}.fa-snowflake-o:before{content:\"\"}.fa-superpowers:before{content:\"\"}.fa-wpexplorer:before{content:\"\"}.fa-meetup:before{content:\"\"}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}.fa,.wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.current>a span.toctree-expand,.rst-content .admonition-title,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content dl dt .headerlink,.rst-content p.caption .headerlink,.rst-content table>caption .headerlink,.rst-content .code-block-caption .headerlink,.rst-content tt.download span:first-child,.rst-content code.download span:first-child,.icon,.wy-dropdown .caret,.wy-inline-validate.wy-inline-validate-success .wy-input-context,.wy-inline-validate.wy-inline-validate-danger .wy-input-context,.wy-inline-validate.wy-inline-validate-warning .wy-input-context,.wy-inline-validate.wy-inline-validate-info .wy-input-context{font-family:inherit}.fa:before,.wy-menu-vertical li span.toctree-expand:before,.wy-menu-vertical li.on a span.toctree-expand:before,.wy-menu-vertical li.current>a span.toctree-expand:before,.rst-content .admonition-title:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content dl dt .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content .code-block-caption .headerlink:before,.rst-content tt.download span:first-child:before,.rst-content code.download span:first-child:before,.icon:before,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before{font-family:\"FontAwesome\";display:inline-block;font-style:normal;font-weight:normal;line-height:1;text-decoration:inherit}a .fa,a .wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li a span.toctree-expand,.wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.current>a span.toctree-expand,a .rst-content .admonition-title,.rst-content a .admonition-title,a .rst-content h1 .headerlink,.rst-content h1 a .headerlink,a .rst-content h2 .headerlink,.rst-content h2 a .headerlink,a .rst-content h3 .headerlink,.rst-content h3 a .headerlink,a .rst-content h4 .headerlink,.rst-content h4 a .headerlink,a .rst-content h5 .headerlink,.rst-content h5 a .headerlink,a .rst-content h6 .headerlink,.rst-content h6 a .headerlink,a .rst-content dl dt .headerlink,.rst-content dl dt a .headerlink,a .rst-content p.caption .headerlink,.rst-content p.caption a .headerlink,a .rst-content table>caption .headerlink,.rst-content table>caption a .headerlink,a .rst-content .code-block-caption .headerlink,.rst-content .code-block-caption a .headerlink,a .rst-content tt.download span:first-child,.rst-content tt.download a span:first-child,a .rst-content code.download span:first-child,.rst-content code.download a span:first-child,a .icon{display:inline-block;text-decoration:inherit}.btn .fa,.btn .wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li .btn span.toctree-expand,.btn .wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.on a .btn span.toctree-expand,.btn .wy-menu-vertical li.current>a span.toctree-expand,.wy-menu-vertical li.current>a .btn span.toctree-expand,.btn .rst-content .admonition-title,.rst-content .btn .admonition-title,.btn .rst-content h1 .headerlink,.rst-content h1 .btn .headerlink,.btn .rst-content h2 .headerlink,.rst-content h2 .btn .headerlink,.btn .rst-content h3 .headerlink,.rst-content h3 .btn .headerlink,.btn .rst-content h4 .headerlink,.rst-content h4 .btn .headerlink,.btn .rst-content h5 .headerlink,.rst-content h5 .btn .headerlink,.btn .rst-content h6 .headerlink,.rst-content h6 .btn .headerlink,.btn .rst-content dl dt .headerlink,.rst-content dl dt .btn .headerlink,.btn .rst-content p.caption .headerlink,.rst-content p.caption .btn .headerlink,.btn .rst-content table>caption .headerlink,.rst-content table>caption .btn .headerlink,.btn .rst-content .code-block-caption .headerlink,.rst-content .code-block-caption .btn .headerlink,.btn .rst-content tt.download span:first-child,.rst-content tt.download .btn span:first-child,.btn .rst-content code.download span:first-child,.rst-content code.download .btn span:first-child,.btn .icon,.nav .fa,.nav .wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li .nav span.toctree-expand,.nav .wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.on a .nav span.toctree-expand,.nav .wy-menu-vertical li.current>a span.toctree-expand,.wy-menu-vertical li.current>a .nav span.toctree-expand,.nav .rst-content .admonition-title,.rst-content .nav .admonition-title,.nav .rst-content h1 .headerlink,.rst-content h1 .nav .headerlink,.nav .rst-content h2 .headerlink,.rst-content h2 .nav .headerlink,.nav .rst-content h3 .headerlink,.rst-content h3 .nav .headerlink,.nav .rst-content h4 .headerlink,.rst-content h4 .nav .headerlink,.nav .rst-content h5 .headerlink,.rst-content h5 .nav .headerlink,.nav .rst-content h6 .headerlink,.rst-content h6 .nav .headerlink,.nav .rst-content dl dt .headerlink,.rst-content dl dt .nav .headerlink,.nav .rst-content p.caption .headerlink,.rst-content p.caption .nav .headerlink,.nav .rst-content table>caption .headerlink,.rst-content table>caption .nav .headerlink,.nav .rst-content .code-block-caption .headerlink,.rst-content .code-block-caption .nav .headerlink,.nav .rst-content tt.download span:first-child,.rst-content tt.download .nav span:first-child,.nav .rst-content code.download span:first-child,.rst-content code.download .nav span:first-child,.nav .icon{display:inline}.btn .fa.fa-large,.btn .wy-menu-vertical li span.fa-large.toctree-expand,.wy-menu-vertical li .btn span.fa-large.toctree-expand,.btn .rst-content .fa-large.admonition-title,.rst-content .btn .fa-large.admonition-title,.btn .rst-content h1 .fa-large.headerlink,.rst-content h1 .btn .fa-large.headerlink,.btn .rst-content h2 .fa-large.headerlink,.rst-content h2 .btn .fa-large.headerlink,.btn .rst-content h3 .fa-large.headerlink,.rst-content h3 .btn .fa-large.headerlink,.btn .rst-content h4 .fa-large.headerlink,.rst-content h4 .btn .fa-large.headerlink,.btn .rst-content h5 .fa-large.headerlink,.rst-content h5 .btn .fa-large.headerlink,.btn .rst-content h6 .fa-large.headerlink,.rst-content h6 .btn .fa-large.headerlink,.btn .rst-content dl dt .fa-large.headerlink,.rst-content dl dt .btn .fa-large.headerlink,.btn .rst-content p.caption .fa-large.headerlink,.rst-content p.caption .btn .fa-large.headerlink,.btn .rst-content table>caption .fa-large.headerlink,.rst-content table>caption .btn .fa-large.headerlink,.btn .rst-content .code-block-caption .fa-large.headerlink,.rst-content .code-block-caption .btn .fa-large.headerlink,.btn .rst-content tt.download span.fa-large:first-child,.rst-content tt.download .btn span.fa-large:first-child,.btn .rst-content code.download span.fa-large:first-child,.rst-content code.download .btn span.fa-large:first-child,.btn .fa-large.icon,.nav .fa.fa-large,.nav .wy-menu-vertical li span.fa-large.toctree-expand,.wy-menu-vertical li .nav span.fa-large.toctree-expand,.nav .rst-content .fa-large.admonition-title,.rst-content .nav .fa-large.admonition-title,.nav .rst-content h1 .fa-large.headerlink,.rst-content h1 .nav .fa-large.headerlink,.nav .rst-content h2 .fa-large.headerlink,.rst-content h2 .nav .fa-large.headerlink,.nav .rst-content h3 .fa-large.headerlink,.rst-content h3 .nav .fa-large.headerlink,.nav .rst-content h4 .fa-large.headerlink,.rst-content h4 .nav .fa-large.headerlink,.nav .rst-content h5 .fa-large.headerlink,.rst-content h5 .nav .fa-large.headerlink,.nav .rst-content h6 .fa-large.headerlink,.rst-content h6 .nav .fa-large.headerlink,.nav .rst-content dl dt .fa-large.headerlink,.rst-content dl dt .nav .fa-large.headerlink,.nav .rst-content p.caption .fa-large.headerlink,.rst-content p.caption .nav .fa-large.headerlink,.nav .rst-content table>caption .fa-large.headerlink,.rst-content table>caption .nav .fa-large.headerlink,.nav .rst-content .code-block-caption .fa-large.headerlink,.rst-content .code-block-caption .nav .fa-large.headerlink,.nav .rst-content tt.download span.fa-large:first-child,.rst-content tt.download .nav span.fa-large:first-child,.nav .rst-content code.download span.fa-large:first-child,.rst-content code.download .nav span.fa-large:first-child,.nav .fa-large.icon{line-height:.9em}.btn .fa.fa-spin,.btn .wy-menu-vertical li span.fa-spin.toctree-expand,.wy-menu-vertical li .btn span.fa-spin.toctree-expand,.btn .rst-content .fa-spin.admonition-title,.rst-content .btn .fa-spin.admonition-title,.btn .rst-content h1 .fa-spin.headerlink,.rst-content h1 .btn .fa-spin.headerlink,.btn .rst-content h2 .fa-spin.headerlink,.rst-content h2 .btn .fa-spin.headerlink,.btn .rst-content h3 .fa-spin.headerlink,.rst-content h3 .btn .fa-spin.headerlink,.btn .rst-content h4 .fa-spin.headerlink,.rst-content h4 .btn .fa-spin.headerlink,.btn .rst-content h5 .fa-spin.headerlink,.rst-content h5 .btn .fa-spin.headerlink,.btn .rst-content h6 .fa-spin.headerlink,.rst-content h6 .btn .fa-spin.headerlink,.btn .rst-content dl dt .fa-spin.headerlink,.rst-content dl dt .btn .fa-spin.headerlink,.btn .rst-content p.caption .fa-spin.headerlink,.rst-content p.caption .btn .fa-spin.headerlink,.btn .rst-content table>caption .fa-spin.headerlink,.rst-content table>caption .btn .fa-spin.headerlink,.btn .rst-content .code-block-caption .fa-spin.headerlink,.rst-content .code-block-caption .btn .fa-spin.headerlink,.btn .rst-content tt.download span.fa-spin:first-child,.rst-content tt.download .btn span.fa-spin:first-child,.btn .rst-content code.download span.fa-spin:first-child,.rst-content code.download .btn span.fa-spin:first-child,.btn .fa-spin.icon,.nav .fa.fa-spin,.nav .wy-menu-vertical li span.fa-spin.toctree-expand,.wy-menu-vertical li .nav span.fa-spin.toctree-expand,.nav .rst-content .fa-spin.admonition-title,.rst-content .nav .fa-spin.admonition-title,.nav .rst-content h1 .fa-spin.headerlink,.rst-content h1 .nav .fa-spin.headerlink,.nav .rst-content h2 .fa-spin.headerlink,.rst-content h2 .nav .fa-spin.headerlink,.nav .rst-content h3 .fa-spin.headerlink,.rst-content h3 .nav .fa-spin.headerlink,.nav .rst-content h4 .fa-spin.headerlink,.rst-content h4 .nav .fa-spin.headerlink,.nav .rst-content h5 .fa-spin.headerlink,.rst-content h5 .nav .fa-spin.headerlink,.nav .rst-content h6 .fa-spin.headerlink,.rst-content h6 .nav .fa-spin.headerlink,.nav .rst-content dl dt .fa-spin.headerlink,.rst-content dl dt .nav .fa-spin.headerlink,.nav .rst-content p.caption .fa-spin.headerlink,.rst-content p.caption .nav .fa-spin.headerlink,.nav .rst-content table>caption .fa-spin.headerlink,.rst-content table>caption .nav .fa-spin.headerlink,.nav .rst-content .code-block-caption .fa-spin.headerlink,.rst-content .code-block-caption .nav .fa-spin.headerlink,.nav .rst-content tt.download span.fa-spin:first-child,.rst-content tt.download .nav span.fa-spin:first-child,.nav .rst-content code.download span.fa-spin:first-child,.rst-content code.download .nav span.fa-spin:first-child,.nav .fa-spin.icon{display:inline-block}.btn.fa:before,.wy-menu-vertical li span.btn.toctree-expand:before,.rst-content .btn.admonition-title:before,.rst-content h1 .btn.headerlink:before,.rst-content h2 .btn.headerlink:before,.rst-content h3 .btn.headerlink:before,.rst-content h4 .btn.headerlink:before,.rst-content h5 .btn.headerlink:before,.rst-content h6 .btn.headerlink:before,.rst-content dl dt .btn.headerlink:before,.rst-content p.caption .btn.headerlink:before,.rst-content table>caption .btn.headerlink:before,.rst-content .code-block-caption .btn.headerlink:before,.rst-content tt.download span.btn:first-child:before,.rst-content code.download span.btn:first-child:before,.btn.icon:before{opacity:.5;-webkit-transition:opacity .05s ease-in;-moz-transition:opacity .05s ease-in;transition:opacity .05s ease-in}.btn.fa:hover:before,.wy-menu-vertical li span.btn.toctree-expand:hover:before,.rst-content .btn.admonition-title:hover:before,.rst-content h1 .btn.headerlink:hover:before,.rst-content h2 .btn.headerlink:hover:before,.rst-content h3 .btn.headerlink:hover:before,.rst-content h4 .btn.headerlink:hover:before,.rst-content h5 .btn.headerlink:hover:before,.rst-content h6 .btn.headerlink:hover:before,.rst-content dl dt .btn.headerlink:hover:before,.rst-content p.caption .btn.headerlink:hover:before,.rst-content table>caption .btn.headerlink:hover:before,.rst-content .code-block-caption .btn.headerlink:hover:before,.rst-content tt.download span.btn:first-child:hover:before,.rst-content code.download span.btn:first-child:hover:before,.btn.icon:hover:before{opacity:1}.btn-mini .fa:before,.btn-mini .wy-menu-vertical li span.toctree-expand:before,.wy-menu-vertical li .btn-mini span.toctree-expand:before,.btn-mini .rst-content .admonition-title:before,.rst-content .btn-mini .admonition-title:before,.btn-mini .rst-content h1 .headerlink:before,.rst-content h1 .btn-mini .headerlink:before,.btn-mini .rst-content h2 .headerlink:before,.rst-content h2 .btn-mini .headerlink:before,.btn-mini .rst-content h3 .headerlink:before,.rst-content h3 .btn-mini .headerlink:before,.btn-mini .rst-content h4 .headerlink:before,.rst-content h4 .btn-mini .headerlink:before,.btn-mini .rst-content h5 .headerlink:before,.rst-content h5 .btn-mini .headerlink:before,.btn-mini .rst-content h6 .headerlink:before,.rst-content h6 .btn-mini .headerlink:before,.btn-mini .rst-content dl dt .headerlink:before,.rst-content dl dt .btn-mini .headerlink:before,.btn-mini .rst-content p.caption .headerlink:before,.rst-content p.caption .btn-mini .headerlink:before,.btn-mini .rst-content table>caption .headerlink:before,.rst-content table>caption .btn-mini .headerlink:before,.btn-mini .rst-content .code-block-caption .headerlink:before,.rst-content .code-block-caption .btn-mini .headerlink:before,.btn-mini .rst-content tt.download span:first-child:before,.rst-content tt.download .btn-mini span:first-child:before,.btn-mini .rst-content code.download span:first-child:before,.rst-content code.download .btn-mini span:first-child:before,.btn-mini .icon:before{font-size:14px;vertical-align:-15%}.wy-alert,.rst-content .note,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .warning,.rst-content .seealso,.rst-content .admonition-todo,.rst-content .admonition{padding:12px;line-height:24px;margin-bottom:24px;background:#e7f2fa}.wy-alert-title,.rst-content .admonition-title{color:#fff;font-weight:bold;display:block;color:#fff;background:#6ab0de;margin:-12px;padding:6px 12px;margin-bottom:12px}.wy-alert.wy-alert-danger,.rst-content .wy-alert-danger.note,.rst-content .wy-alert-danger.attention,.rst-content .wy-alert-danger.caution,.rst-content .danger,.rst-content .error,.rst-content .wy-alert-danger.hint,.rst-content .wy-alert-danger.important,.rst-content .wy-alert-danger.tip,.rst-content .wy-alert-danger.warning,.rst-content .wy-alert-danger.seealso,.rst-content .wy-alert-danger.admonition-todo,.rst-content .wy-alert-danger.admonition{background:#fdf3f2}.wy-alert.wy-alert-danger .wy-alert-title,.rst-content .wy-alert-danger.note .wy-alert-title,.rst-content .wy-alert-danger.attention .wy-alert-title,.rst-content .wy-alert-danger.caution .wy-alert-title,.rst-content .danger .wy-alert-title,.rst-content .error .wy-alert-title,.rst-content .wy-alert-danger.hint .wy-alert-title,.rst-content .wy-alert-danger.important .wy-alert-title,.rst-content .wy-alert-danger.tip .wy-alert-title,.rst-content .wy-alert-danger.warning .wy-alert-title,.rst-content .wy-alert-danger.seealso .wy-alert-title,.rst-content .wy-alert-danger.admonition-todo .wy-alert-title,.rst-content .wy-alert-danger.admonition .wy-alert-title,.wy-alert.wy-alert-danger .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-danger .admonition-title,.rst-content .wy-alert-danger.note .admonition-title,.rst-content .wy-alert-danger.attention .admonition-title,.rst-content .wy-alert-danger.caution .admonition-title,.rst-content .danger .admonition-title,.rst-content .error .admonition-title,.rst-content .wy-alert-danger.hint .admonition-title,.rst-content .wy-alert-danger.important .admonition-title,.rst-content .wy-alert-danger.tip .admonition-title,.rst-content .wy-alert-danger.warning .admonition-title,.rst-content .wy-alert-danger.seealso .admonition-title,.rst-content .wy-alert-danger.admonition-todo .admonition-title,.rst-content .wy-alert-danger.admonition .admonition-title{background:#f29f97}.wy-alert.wy-alert-warning,.rst-content .wy-alert-warning.note,.rst-content .attention,.rst-content .caution,.rst-content .wy-alert-warning.danger,.rst-content .wy-alert-warning.error,.rst-content .wy-alert-warning.hint,.rst-content .wy-alert-warning.important,.rst-content .wy-alert-warning.tip,.rst-content .warning,.rst-content .wy-alert-warning.seealso,.rst-content .admonition-todo,.rst-content .wy-alert-warning.admonition{background:#ffedcc}.wy-alert.wy-alert-warning .wy-alert-title,.rst-content .wy-alert-warning.note .wy-alert-title,.rst-content .attention .wy-alert-title,.rst-content .caution .wy-alert-title,.rst-content .wy-alert-warning.danger .wy-alert-title,.rst-content .wy-alert-warning.error .wy-alert-title,.rst-content .wy-alert-warning.hint .wy-alert-title,.rst-content .wy-alert-warning.important .wy-alert-title,.rst-content .wy-alert-warning.tip .wy-alert-title,.rst-content .warning .wy-alert-title,.rst-content .wy-alert-warning.seealso .wy-alert-title,.rst-content .admonition-todo .wy-alert-title,.rst-content .wy-alert-warning.admonition .wy-alert-title,.wy-alert.wy-alert-warning .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-warning .admonition-title,.rst-content .wy-alert-warning.note .admonition-title,.rst-content .attention .admonition-title,.rst-content .caution .admonition-title,.rst-content .wy-alert-warning.danger .admonition-title,.rst-content .wy-alert-warning.error .admonition-title,.rst-content .wy-alert-warning.hint .admonition-title,.rst-content .wy-alert-warning.important .admonition-title,.rst-content .wy-alert-warning.tip .admonition-title,.rst-content .warning .admonition-title,.rst-content .wy-alert-warning.seealso .admonition-title,.rst-content .admonition-todo .admonition-title,.rst-content .wy-alert-warning.admonition .admonition-title{background:#f0b37e}.wy-alert.wy-alert-info,.rst-content .note,.rst-content .wy-alert-info.attention,.rst-content .wy-alert-info.caution,.rst-content .wy-alert-info.danger,.rst-content .wy-alert-info.error,.rst-content .wy-alert-info.hint,.rst-content .wy-alert-info.important,.rst-content .wy-alert-info.tip,.rst-content .wy-alert-info.warning,.rst-content .seealso,.rst-content .wy-alert-info.admonition-todo,.rst-content .wy-alert-info.admonition{background:#e7f2fa}.wy-alert.wy-alert-info .wy-alert-title,.rst-content .note .wy-alert-title,.rst-content .wy-alert-info.attention .wy-alert-title,.rst-content .wy-alert-info.caution .wy-alert-title,.rst-content .wy-alert-info.danger .wy-alert-title,.rst-content .wy-alert-info.error .wy-alert-title,.rst-content .wy-alert-info.hint .wy-alert-title,.rst-content .wy-alert-info.important .wy-alert-title,.rst-content .wy-alert-info.tip .wy-alert-title,.rst-content .wy-alert-info.warning .wy-alert-title,.rst-content .seealso .wy-alert-title,.rst-content .wy-alert-info.admonition-todo .wy-alert-title,.rst-content .wy-alert-info.admonition .wy-alert-title,.wy-alert.wy-alert-info .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-info .admonition-title,.rst-content .note .admonition-title,.rst-content .wy-alert-info.attention .admonition-title,.rst-content .wy-alert-info.caution .admonition-title,.rst-content .wy-alert-info.danger .admonition-title,.rst-content .wy-alert-info.error .admonition-title,.rst-content .wy-alert-info.hint .admonition-title,.rst-content .wy-alert-info.important .admonition-title,.rst-content .wy-alert-info.tip .admonition-title,.rst-content .wy-alert-info.warning .admonition-title,.rst-content .seealso .admonition-title,.rst-content .wy-alert-info.admonition-todo .admonition-title,.rst-content .wy-alert-info.admonition .admonition-title{background:#6ab0de}.wy-alert.wy-alert-success,.rst-content .wy-alert-success.note,.rst-content .wy-alert-success.attention,.rst-content .wy-alert-success.caution,.rst-content .wy-alert-success.danger,.rst-content .wy-alert-success.error,.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .wy-alert-success.warning,.rst-content .wy-alert-success.seealso,.rst-content .wy-alert-success.admonition-todo,.rst-content .wy-alert-success.admonition{background:#dbfaf4}.wy-alert.wy-alert-success .wy-alert-title,.rst-content .wy-alert-success.note .wy-alert-title,.rst-content .wy-alert-success.attention .wy-alert-title,.rst-content .wy-alert-success.caution .wy-alert-title,.rst-content .wy-alert-success.danger .wy-alert-title,.rst-content .wy-alert-success.error .wy-alert-title,.rst-content .hint .wy-alert-title,.rst-content .important .wy-alert-title,.rst-content .tip .wy-alert-title,.rst-content .wy-alert-success.warning .wy-alert-title,.rst-content .wy-alert-success.seealso .wy-alert-title,.rst-content .wy-alert-success.admonition-todo .wy-alert-title,.rst-content .wy-alert-success.admonition .wy-alert-title,.wy-alert.wy-alert-success .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-success .admonition-title,.rst-content .wy-alert-success.note .admonition-title,.rst-content .wy-alert-success.attention .admonition-title,.rst-content .wy-alert-success.caution .admonition-title,.rst-content .wy-alert-success.danger .admonition-title,.rst-content .wy-alert-success.error .admonition-title,.rst-content .hint .admonition-title,.rst-content .important .admonition-title,.rst-content .tip .admonition-title,.rst-content .wy-alert-success.warning .admonition-title,.rst-content .wy-alert-success.seealso .admonition-title,.rst-content .wy-alert-success.admonition-todo .admonition-title,.rst-content .wy-alert-success.admonition .admonition-title{background:#1abc9c}.wy-alert.wy-alert-neutral,.rst-content .wy-alert-neutral.note,.rst-content .wy-alert-neutral.attention,.rst-content .wy-alert-neutral.caution,.rst-content .wy-alert-neutral.danger,.rst-content .wy-alert-neutral.error,.rst-content .wy-alert-neutral.hint,.rst-content .wy-alert-neutral.important,.rst-content .wy-alert-neutral.tip,.rst-content .wy-alert-neutral.warning,.rst-content .wy-alert-neutral.seealso,.rst-content .wy-alert-neutral.admonition-todo,.rst-content .wy-alert-neutral.admonition{background:#f3f6f6}.wy-alert.wy-alert-neutral .wy-alert-title,.rst-content .wy-alert-neutral.note .wy-alert-title,.rst-content .wy-alert-neutral.attention .wy-alert-title,.rst-content .wy-alert-neutral.caution .wy-alert-title,.rst-content .wy-alert-neutral.danger .wy-alert-title,.rst-content .wy-alert-neutral.error .wy-alert-title,.rst-content .wy-alert-neutral.hint .wy-alert-title,.rst-content .wy-alert-neutral.important .wy-alert-title,.rst-content .wy-alert-neutral.tip .wy-alert-title,.rst-content .wy-alert-neutral.warning .wy-alert-title,.rst-content .wy-alert-neutral.seealso .wy-alert-title,.rst-content .wy-alert-neutral.admonition-todo .wy-alert-title,.rst-content .wy-alert-neutral.admonition .wy-alert-title,.wy-alert.wy-alert-neutral .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-neutral .admonition-title,.rst-content .wy-alert-neutral.note .admonition-title,.rst-content .wy-alert-neutral.attention .admonition-title,.rst-content .wy-alert-neutral.caution .admonition-title,.rst-content .wy-alert-neutral.danger .admonition-title,.rst-content .wy-alert-neutral.error .admonition-title,.rst-content .wy-alert-neutral.hint .admonition-title,.rst-content .wy-alert-neutral.important .admonition-title,.rst-content .wy-alert-neutral.tip .admonition-title,.rst-content .wy-alert-neutral.warning .admonition-title,.rst-content .wy-alert-neutral.seealso .admonition-title,.rst-content .wy-alert-neutral.admonition-todo .admonition-title,.rst-content .wy-alert-neutral.admonition .admonition-title{color:#404040;background:#e1e4e5}.wy-alert.wy-alert-neutral a,.rst-content .wy-alert-neutral.note a,.rst-content .wy-alert-neutral.attention a,.rst-content .wy-alert-neutral.caution a,.rst-content .wy-alert-neutral.danger a,.rst-content .wy-alert-neutral.error a,.rst-content .wy-alert-neutral.hint a,.rst-content .wy-alert-neutral.important a,.rst-content .wy-alert-neutral.tip a,.rst-content .wy-alert-neutral.warning a,.rst-content .wy-alert-neutral.seealso a,.rst-content .wy-alert-neutral.admonition-todo a,.rst-content .wy-alert-neutral.admonition a{color:#2980B9}.wy-alert p:last-child,.rst-content .note p:last-child,.rst-content .attention p:last-child,.rst-content .caution p:last-child,.rst-content .danger p:last-child,.rst-content .error p:last-child,.rst-content .hint p:last-child,.rst-content .important p:last-child,.rst-content .tip p:last-child,.rst-content .warning p:last-child,.rst-content .seealso p:last-child,.rst-content .admonition-todo p:last-child,.rst-content .admonition p:last-child{margin-bottom:0}.wy-tray-container{position:fixed;bottom:0px;left:0;z-index:600}.wy-tray-container li{display:block;width:300px;background:transparent;color:#fff;text-align:center;box-shadow:0 5px 5px 0 rgba(0,0,0,0.1);padding:0 24px;min-width:20%;opacity:0;height:0;line-height:56px;overflow:hidden;-webkit-transition:all .3s ease-in;-moz-transition:all .3s ease-in;transition:all .3s ease-in}.wy-tray-container li.wy-tray-item-success{background:#27AE60}.wy-tray-container li.wy-tray-item-info{background:#2980B9}.wy-tray-container li.wy-tray-item-warning{background:#E67E22}.wy-tray-container li.wy-tray-item-danger{background:#E74C3C}.wy-tray-container li.on{opacity:1;height:56px}@media screen and (max-width: 768px){.wy-tray-container{bottom:auto;top:0;width:100%}.wy-tray-container li{width:100%}}button{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle;cursor:pointer;line-height:normal;-webkit-appearance:button;*overflow:visible}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}button[disabled]{cursor:default}.btn{display:inline-block;border-radius:2px;line-height:normal;white-space:nowrap;text-align:center;cursor:pointer;font-size:100%;padding:6px 12px 8px 12px;color:#fff;border:1px solid rgba(0,0,0,0.1);background-color:#27AE60;text-decoration:none;font-weight:normal;font-family:\"Lato\",\"proxima-nova\",\"Helvetica Neue\",Arial,sans-serif;box-shadow:0px 1px 2px -1px rgba(255,255,255,0.5) inset,0px -2px 0px 0px rgba(0,0,0,0.1) inset;outline-none:false;vertical-align:middle;*display:inline;zoom:1;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transition:all .1s linear;-moz-transition:all .1s linear;transition:all .1s linear}.btn-hover{background:#2e8ece;color:#fff}.btn:hover{background:#2cc36b;color:#fff}.btn:focus{background:#2cc36b;outline:0}.btn:active{box-shadow:0px -1px 0px 0px rgba(0,0,0,0.05) inset,0px 2px 0px 0px rgba(0,0,0,0.1) inset;padding:8px 12px 6px 12px}.btn:visited{color:#fff}.btn:disabled{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:.4;cursor:not-allowed;box-shadow:none}.btn-disabled{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:.4;cursor:not-allowed;box-shadow:none}.btn-disabled:hover,.btn-disabled:focus,.btn-disabled:active{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:.4;cursor:not-allowed;box-shadow:none}.btn::-moz-focus-inner{padding:0;border:0}.btn-small{font-size:80%}.btn-info{background-color:#2980B9 !important}.btn-info:hover{background-color:#2e8ece !important}.btn-neutral{background-color:#f3f6f6 !important;color:#404040 !important}.btn-neutral:hover{background-color:#e5ebeb !important;color:#404040}.btn-neutral:visited{color:#404040 !important}.btn-success{background-color:#27AE60 !important}.btn-success:hover{background-color:#295 !important}.btn-danger{background-color:#E74C3C !important}.btn-danger:hover{background-color:#ea6153 !important}.btn-warning{background-color:#E67E22 !important}.btn-warning:hover{background-color:#e98b39 !important}.btn-invert{background-color:#222}.btn-invert:hover{background-color:#2f2f2f !important}.btn-link{background-color:transparent !important;color:#2980B9;box-shadow:none;border-color:transparent !important}.btn-link:hover{background-color:transparent !important;color:#409ad5 !important;box-shadow:none}.btn-link:active{background-color:transparent !important;color:#409ad5 !important;box-shadow:none}.btn-link:visited{color:#9B59B6}.wy-btn-group .btn,.wy-control .btn{vertical-align:middle}.wy-btn-group{margin-bottom:24px;*zoom:1}.wy-btn-group:before,.wy-btn-group:after{display:table;content:\"\"}.wy-btn-group:after{clear:both}.wy-dropdown{position:relative;display:inline-block}.wy-dropdown-active .wy-dropdown-menu{display:block}.wy-dropdown-menu{position:absolute;left:0;display:none;float:left;top:100%;min-width:100%;background:#fcfcfc;z-index:100;border:solid 1px #cfd7dd;box-shadow:0 2px 2px 0 rgba(0,0,0,0.1);padding:12px}.wy-dropdown-menu>dd>a{display:block;clear:both;color:#404040;white-space:nowrap;font-size:90%;padding:0 12px;cursor:pointer}.wy-dropdown-menu>dd>a:hover{background:#2980B9;color:#fff}.wy-dropdown-menu>dd.divider{border-top:solid 1px #cfd7dd;margin:6px 0}.wy-dropdown-menu>dd.search{padding-bottom:12px}.wy-dropdown-menu>dd.search input[type=\"search\"]{width:100%}.wy-dropdown-menu>dd.call-to-action{background:#e3e3e3;text-transform:uppercase;font-weight:500;font-size:80%}.wy-dropdown-menu>dd.call-to-action:hover{background:#e3e3e3}.wy-dropdown-menu>dd.call-to-action .btn{color:#fff}.wy-dropdown.wy-dropdown-up .wy-dropdown-menu{bottom:100%;top:auto;left:auto;right:0}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu{background:#fcfcfc;margin-top:2px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a{padding:6px 12px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a:hover{background:#2980B9;color:#fff}.wy-dropdown.wy-dropdown-left .wy-dropdown-menu{right:0;left:auto;text-align:right}.wy-dropdown-arrow:before{content:\" \";border-bottom:5px solid #f5f5f5;border-left:5px solid transparent;border-right:5px solid transparent;position:absolute;display:block;top:-4px;left:50%;margin-left:-3px}.wy-dropdown-arrow.wy-dropdown-arrow-left:before{left:11px}.wy-form-stacked select{display:block}.wy-form-aligned input,.wy-form-aligned textarea,.wy-form-aligned select,.wy-form-aligned .wy-help-inline,.wy-form-aligned label{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-form-aligned .wy-control-group>label{display:inline-block;vertical-align:middle;width:10em;margin:6px 12px 0 0;float:left}.wy-form-aligned .wy-control{float:left}.wy-form-aligned .wy-control label{display:block}.wy-form-aligned .wy-control select{margin-top:6px}fieldset{border:0;margin:0;padding:0}legend{display:block;width:100%;border:0;padding:0;white-space:normal;margin-bottom:24px;font-size:150%;*margin-left:-7px}label{display:block;margin:0 0 .3125em 0;color:#333;font-size:90%}input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}.wy-control-group{margin-bottom:24px;*zoom:1;max-width:68em;margin-left:auto;margin-right:auto;*zoom:1}.wy-control-group:before,.wy-control-group:after{display:table;content:\"\"}.wy-control-group:after{clear:both}.wy-control-group:before,.wy-control-group:after{display:table;content:\"\"}.wy-control-group:after{clear:both}.wy-control-group.wy-control-group-required>label:after{content:\" *\";color:#E74C3C}.wy-control-group .wy-form-full,.wy-control-group .wy-form-halves,.wy-control-group .wy-form-thirds{padding-bottom:12px}.wy-control-group .wy-form-full select,.wy-control-group .wy-form-halves select,.wy-control-group .wy-form-thirds select{width:100%}.wy-control-group .wy-form-full input[type=\"text\"],.wy-control-group .wy-form-full input[type=\"password\"],.wy-control-group .wy-form-full input[type=\"email\"],.wy-control-group .wy-form-full input[type=\"url\"],.wy-control-group .wy-form-full input[type=\"date\"],.wy-control-group .wy-form-full input[type=\"month\"],.wy-control-group .wy-form-full input[type=\"time\"],.wy-control-group .wy-form-full input[type=\"datetime\"],.wy-control-group .wy-form-full input[type=\"datetime-local\"],.wy-control-group .wy-form-full input[type=\"week\"],.wy-control-group .wy-form-full input[type=\"number\"],.wy-control-group .wy-form-full input[type=\"search\"],.wy-control-group .wy-form-full input[type=\"tel\"],.wy-control-group .wy-form-full input[type=\"color\"],.wy-control-group .wy-form-halves input[type=\"text\"],.wy-control-group .wy-form-halves input[type=\"password\"],.wy-control-group .wy-form-halves input[type=\"email\"],.wy-control-group .wy-form-halves input[type=\"url\"],.wy-control-group .wy-form-halves input[type=\"date\"],.wy-control-group .wy-form-halves input[type=\"month\"],.wy-control-group .wy-form-halves input[type=\"time\"],.wy-control-group .wy-form-halves input[type=\"datetime\"],.wy-control-group .wy-form-halves input[type=\"datetime-local\"],.wy-control-group .wy-form-halves input[type=\"week\"],.wy-control-group .wy-form-halves input[type=\"number\"],.wy-control-group .wy-form-halves input[type=\"search\"],.wy-control-group .wy-form-halves input[type=\"tel\"],.wy-control-group .wy-form-halves input[type=\"color\"],.wy-control-group .wy-form-thirds input[type=\"text\"],.wy-control-group .wy-form-thirds input[type=\"password\"],.wy-control-group .wy-form-thirds input[type=\"email\"],.wy-control-group .wy-form-thirds input[type=\"url\"],.wy-control-group .wy-form-thirds input[type=\"date\"],.wy-control-group .wy-form-thirds input[type=\"month\"],.wy-control-group .wy-form-thirds input[type=\"time\"],.wy-control-group .wy-form-thirds input[type=\"datetime\"],.wy-control-group .wy-form-thirds input[type=\"datetime-local\"],.wy-control-group .wy-form-thirds input[type=\"week\"],.wy-control-group .wy-form-thirds input[type=\"number\"],.wy-control-group .wy-form-thirds input[type=\"search\"],.wy-control-group .wy-form-thirds input[type=\"tel\"],.wy-control-group .wy-form-thirds input[type=\"color\"]{width:100%}.wy-control-group .wy-form-full{float:left;display:block;margin-right:2.3576515979%;width:100%;margin-right:0}.wy-control-group .wy-form-full:last-child{margin-right:0}.wy-control-group .wy-form-halves{float:left;display:block;margin-right:2.3576515979%;width:48.821174201%}.wy-control-group .wy-form-halves:last-child{margin-right:0}.wy-control-group .wy-form-halves:nth-of-type(2n){margin-right:0}.wy-control-group .wy-form-halves:nth-of-type(2n+1){clear:left}.wy-control-group .wy-form-thirds{float:left;display:block;margin-right:2.3576515979%;width:31.7615656014%}.wy-control-group .wy-form-thirds:last-child{margin-right:0}.wy-control-group .wy-form-thirds:nth-of-type(3n){margin-right:0}.wy-control-group .wy-form-thirds:nth-of-type(3n+1){clear:left}.wy-control-group.wy-control-group-no-input .wy-control{margin:6px 0 0 0;font-size:90%}.wy-control-no-input{display:inline-block;margin:6px 0 0 0;font-size:90%}.wy-control-group.fluid-input input[type=\"text\"],.wy-control-group.fluid-input input[type=\"password\"],.wy-control-group.fluid-input input[type=\"email\"],.wy-control-group.fluid-input input[type=\"url\"],.wy-control-group.fluid-input input[type=\"date\"],.wy-control-group.fluid-input input[type=\"month\"],.wy-control-group.fluid-input input[type=\"time\"],.wy-control-group.fluid-input input[type=\"datetime\"],.wy-control-group.fluid-input input[type=\"datetime-local\"],.wy-control-group.fluid-input input[type=\"week\"],.wy-control-group.fluid-input input[type=\"number\"],.wy-control-group.fluid-input input[type=\"search\"],.wy-control-group.fluid-input input[type=\"tel\"],.wy-control-group.fluid-input input[type=\"color\"]{width:100%}.wy-form-message-inline{display:inline-block;padding-left:.3em;color:#666;vertical-align:middle;font-size:90%}.wy-form-message{display:block;color:#999;font-size:70%;margin-top:.3125em;font-style:italic}.wy-form-message p{font-size:inherit;font-style:italic;margin-bottom:6px}.wy-form-message p:last-child{margin-bottom:0}input{line-height:normal}input[type=\"button\"],input[type=\"reset\"],input[type=\"submit\"]{-webkit-appearance:button;cursor:pointer;font-family:\"Lato\",\"proxima-nova\",\"Helvetica Neue\",Arial,sans-serif;*overflow:visible}input[type=\"text\"],input[type=\"password\"],input[type=\"email\"],input[type=\"url\"],input[type=\"date\"],input[type=\"month\"],input[type=\"time\"],input[type=\"datetime\"],input[type=\"datetime-local\"],input[type=\"week\"],input[type=\"number\"],input[type=\"search\"],input[type=\"tel\"],input[type=\"color\"]{-webkit-appearance:none;padding:6px;display:inline-block;border:1px solid #ccc;font-size:80%;font-family:\"Lato\",\"proxima-nova\",\"Helvetica Neue\",Arial,sans-serif;box-shadow:inset 0 1px 3px #ddd;border-radius:0;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}input[type=\"datetime-local\"]{padding:.34375em .625em}input[disabled]{cursor:default}input[type=\"checkbox\"],input[type=\"radio\"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0;margin-right:.3125em;*height:13px;*width:13px}input[type=\"search\"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=\"search\"]::-webkit-search-cancel-button,input[type=\"search\"]::-webkit-search-decoration{-webkit-appearance:none}input[type=\"text\"]:focus,input[type=\"password\"]:focus,input[type=\"email\"]:focus,input[type=\"url\"]:focus,input[type=\"date\"]:focus,input[type=\"month\"]:focus,input[type=\"time\"]:focus,input[type=\"datetime\"]:focus,input[type=\"datetime-local\"]:focus,input[type=\"week\"]:focus,input[type=\"number\"]:focus,input[type=\"search\"]:focus,input[type=\"tel\"]:focus,input[type=\"color\"]:focus{outline:0;outline:thin dotted \\9;border-color:#333}input.no-focus:focus{border-color:#ccc !important}input[type=\"file\"]:focus,input[type=\"radio\"]:focus,input[type=\"checkbox\"]:focus{outline:thin dotted #333;outline:1px auto #129FEA}input[type=\"text\"][disabled],input[type=\"password\"][disabled],input[type=\"email\"][disabled],input[type=\"url\"][disabled],input[type=\"date\"][disabled],input[type=\"month\"][disabled],input[type=\"time\"][disabled],input[type=\"datetime\"][disabled],input[type=\"datetime-local\"][disabled],input[type=\"week\"][disabled],input[type=\"number\"][disabled],input[type=\"search\"][disabled],input[type=\"tel\"][disabled],input[type=\"color\"][disabled]{cursor:not-allowed;background-color:#fafafa}input:focus:invalid,textarea:focus:invalid,select:focus:invalid{color:#E74C3C;border:1px solid #E74C3C}input:focus:invalid:focus,textarea:focus:invalid:focus,select:focus:invalid:focus{border-color:#E74C3C}input[type=\"file\"]:focus:invalid:focus,input[type=\"radio\"]:focus:invalid:focus,input[type=\"checkbox\"]:focus:invalid:focus{outline-color:#E74C3C}input.wy-input-large{padding:12px;font-size:100%}textarea{overflow:auto;vertical-align:top;width:100%;font-family:\"Lato\",\"proxima-nova\",\"Helvetica Neue\",Arial,sans-serif}select,textarea{padding:.5em .625em;display:inline-block;border:1px solid #ccc;font-size:80%;box-shadow:inset 0 1px 3px #ddd;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}select{border:1px solid #ccc;background-color:#fff}select[multiple]{height:auto}select:focus,textarea:focus{outline:0}select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{cursor:not-allowed;background-color:#fafafa}input[type=\"radio\"][disabled],input[type=\"checkbox\"][disabled]{cursor:not-allowed}.wy-checkbox,.wy-radio{margin:6px 0;color:#404040;display:block}.wy-checkbox input,.wy-radio input{vertical-align:baseline}.wy-form-message-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-input-prefix,.wy-input-suffix{white-space:nowrap;padding:6px}.wy-input-prefix .wy-input-context,.wy-input-suffix .wy-input-context{line-height:27px;padding:0 8px;display:inline-block;font-size:80%;background-color:#f3f6f6;border:solid 1px #ccc;color:#999}.wy-input-suffix .wy-input-context{border-left:0}.wy-input-prefix .wy-input-context{border-right:0}.wy-switch{position:relative;display:block;height:24px;margin-top:12px;cursor:pointer}.wy-switch:before{position:absolute;content:\"\";display:block;left:0;top:0;width:36px;height:12px;border-radius:4px;background:#ccc;-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.wy-switch:after{position:absolute;content:\"\";display:block;width:18px;height:18px;border-radius:4px;background:#999;left:-3px;top:-3px;-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.wy-switch span{position:absolute;left:48px;display:block;font-size:12px;color:#ccc;line-height:1}.wy-switch.active:before{background:#1e8449}.wy-switch.active:after{left:24px;background:#27AE60}.wy-switch.disabled{cursor:not-allowed;opacity:.8}.wy-control-group.wy-control-group-error .wy-form-message,.wy-control-group.wy-control-group-error>label{color:#E74C3C}.wy-control-group.wy-control-group-error input[type=\"text\"],.wy-control-group.wy-control-group-error input[type=\"password\"],.wy-control-group.wy-control-group-error input[type=\"email\"],.wy-control-group.wy-control-group-error input[type=\"url\"],.wy-control-group.wy-control-group-error input[type=\"date\"],.wy-control-group.wy-control-group-error input[type=\"month\"],.wy-control-group.wy-control-group-error input[type=\"time\"],.wy-control-group.wy-control-group-error input[type=\"datetime\"],.wy-control-group.wy-control-group-error input[type=\"datetime-local\"],.wy-control-group.wy-control-group-error input[type=\"week\"],.wy-control-group.wy-control-group-error input[type=\"number\"],.wy-control-group.wy-control-group-error input[type=\"search\"],.wy-control-group.wy-control-group-error input[type=\"tel\"],.wy-control-group.wy-control-group-error input[type=\"color\"]{border:solid 1px #E74C3C}.wy-control-group.wy-control-group-error textarea{border:solid 1px #E74C3C}.wy-inline-validate{white-space:nowrap}.wy-inline-validate .wy-input-context{padding:.5em .625em;display:inline-block;font-size:80%}.wy-inline-validate.wy-inline-validate-success .wy-input-context{color:#27AE60}.wy-inline-validate.wy-inline-validate-danger .wy-input-context{color:#E74C3C}.wy-inline-validate.wy-inline-validate-warning .wy-input-context{color:#E67E22}.wy-inline-validate.wy-inline-validate-info .wy-input-context{color:#2980B9}.rotate-90{-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.rotate-180{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}.rotate-270{-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg)}.mirror{-webkit-transform:scaleX(-1);-moz-transform:scaleX(-1);-ms-transform:scaleX(-1);-o-transform:scaleX(-1);transform:scaleX(-1)}.mirror.rotate-90{-webkit-transform:scaleX(-1) rotate(90deg);-moz-transform:scaleX(-1) rotate(90deg);-ms-transform:scaleX(-1) rotate(90deg);-o-transform:scaleX(-1) rotate(90deg);transform:scaleX(-1) rotate(90deg)}.mirror.rotate-180{-webkit-transform:scaleX(-1) rotate(180deg);-moz-transform:scaleX(-1) rotate(180deg);-ms-transform:scaleX(-1) rotate(180deg);-o-transform:scaleX(-1) rotate(180deg);transform:scaleX(-1) rotate(180deg)}.mirror.rotate-270{-webkit-transform:scaleX(-1) rotate(270deg);-moz-transform:scaleX(-1) rotate(270deg);-ms-transform:scaleX(-1) rotate(270deg);-o-transform:scaleX(-1) rotate(270deg);transform:scaleX(-1) rotate(270deg)}@media only screen and (max-width: 480px){.wy-form button[type=\"submit\"]{margin:.7em 0 0}.wy-form input[type=\"text\"],.wy-form input[type=\"password\"],.wy-form input[type=\"email\"],.wy-form input[type=\"url\"],.wy-form input[type=\"date\"],.wy-form input[type=\"month\"],.wy-form input[type=\"time\"],.wy-form input[type=\"datetime\"],.wy-form input[type=\"datetime-local\"],.wy-form input[type=\"week\"],.wy-form input[type=\"number\"],.wy-form input[type=\"search\"],.wy-form input[type=\"tel\"],.wy-form input[type=\"color\"]{margin-bottom:.3em;display:block}.wy-form label{margin-bottom:.3em;display:block}.wy-form input[type=\"password\"],.wy-form input[type=\"email\"],.wy-form input[type=\"url\"],.wy-form input[type=\"date\"],.wy-form input[type=\"month\"],.wy-form input[type=\"time\"],.wy-form input[type=\"datetime\"],.wy-form input[type=\"datetime-local\"],.wy-form input[type=\"week\"],.wy-form input[type=\"number\"],.wy-form input[type=\"search\"],.wy-form input[type=\"tel\"],.wy-form input[type=\"color\"]{margin-bottom:0}.wy-form-aligned .wy-control-group label{margin-bottom:.3em;text-align:left;display:block;width:100%}.wy-form-aligned .wy-control{margin:1.5em 0 0 0}.wy-form .wy-help-inline,.wy-form-message-inline,.wy-form-message{display:block;font-size:80%;padding:6px 0}}@media screen and (max-width: 768px){.tablet-hide{display:none}}@media screen and (max-width: 480px){.mobile-hide{display:none}}.float-left{float:left}.float-right{float:right}.full-width{width:100%}.wy-table,.rst-content table.docutils,.rst-content table.field-list{border-collapse:collapse;border-spacing:0;empty-cells:show;margin-bottom:24px}.wy-table caption,.rst-content table.docutils caption,.rst-content table.field-list caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.wy-table td,.rst-content table.docutils td,.rst-content table.field-list td,.wy-table th,.rst-content table.docutils th,.rst-content table.field-list th{font-size:90%;margin:0;overflow:visible;padding:8px 16px}.wy-table td:first-child,.rst-content table.docutils td:first-child,.rst-content table.field-list td:first-child,.wy-table th:first-child,.rst-content table.docutils th:first-child,.rst-content table.field-list th:first-child{border-left-width:0}.wy-table thead,.rst-content table.docutils thead,.rst-content table.field-list thead{color:#000;text-align:left;vertical-align:bottom;white-space:nowrap}.wy-table thead th,.rst-content table.docutils thead th,.rst-content table.field-list thead th{font-weight:bold;border-bottom:solid 2px #e1e4e5}.wy-table td,.rst-content table.docutils td,.rst-content table.field-list td{background-color:transparent;vertical-align:middle}.wy-table td p,.rst-content table.docutils td p,.rst-content table.field-list td p{line-height:18px}.wy-table td p:last-child,.rst-content table.docutils td p:last-child,.rst-content table.field-list td p:last-child{margin-bottom:0}.wy-table .wy-table-cell-min,.rst-content table.docutils .wy-table-cell-min,.rst-content table.field-list .wy-table-cell-min{width:1%;padding-right:0}.wy-table .wy-table-cell-min input[type=checkbox],.rst-content table.docutils .wy-table-cell-min input[type=checkbox],.rst-content table.field-list .wy-table-cell-min input[type=checkbox],.wy-table .wy-table-cell-min input[type=checkbox],.rst-content table.docutils .wy-table-cell-min input[type=checkbox],.rst-content table.field-list .wy-table-cell-min input[type=checkbox]{margin:0}.wy-table-secondary{color:gray;font-size:90%}.wy-table-tertiary{color:gray;font-size:80%}.wy-table-odd td,.wy-table-striped tr:nth-child(2n-1) td,.rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td{background-color:#f3f6f6}.wy-table-backed{background-color:#f3f6f6}.wy-table-bordered-all,.rst-content table.docutils{border:1px solid #e1e4e5}.wy-table-bordered-all td,.rst-content table.docutils td{border-bottom:1px solid #e1e4e5;border-left:1px solid #e1e4e5}.wy-table-bordered-all tbody>tr:last-child td,.rst-content table.docutils tbody>tr:last-child td{border-bottom-width:0}.wy-table-bordered{border:1px solid #e1e4e5}.wy-table-bordered-rows td{border-bottom:1px solid #e1e4e5}.wy-table-bordered-rows tbody>tr:last-child td{border-bottom-width:0}.wy-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.wy-table-horizontal td,.wy-table-horizontal th{border-width:0 0 1px 0;border-bottom:1px solid #e1e4e5}.wy-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.wy-table-responsive{margin-bottom:24px;max-width:100%;overflow:auto}.wy-table-responsive table{margin-bottom:0 !important}.wy-table-responsive table td,.wy-table-responsive table th{white-space:nowrap}a{color:#2980B9;text-decoration:none;cursor:pointer}a:hover{color:#3091d1}a:visited{color:#9B59B6}html{height:100%;overflow-x:hidden}body{font-family:\"Lato\",\"proxima-nova\",\"Helvetica Neue\",Arial,sans-serif;font-weight:normal;color:#404040;min-height:100%;overflow-x:hidden;background:#edf0f2}.wy-text-left{text-align:left}.wy-text-center{text-align:center}.wy-text-right{text-align:right}.wy-text-large{font-size:120%}.wy-text-normal{font-size:100%}.wy-text-small,small{font-size:80%}.wy-text-strike{text-decoration:line-through}.wy-text-warning{color:#E67E22 !important}a.wy-text-warning:hover{color:#eb9950 !important}.wy-text-info{color:#2980B9 !important}a.wy-text-info:hover{color:#409ad5 !important}.wy-text-success{color:#27AE60 !important}a.wy-text-success:hover{color:#36d278 !important}.wy-text-danger{color:#E74C3C !important}a.wy-text-danger:hover{color:#ed7669 !important}.wy-text-neutral{color:#404040 !important}a.wy-text-neutral:hover{color:#595959 !important}h1,h2,.rst-content .toctree-wrapper p.caption,h3,h4,h5,h6,legend{margin-top:0;font-weight:700;font-family:\"Roboto Slab\",\"ff-tisa-web-pro\",\"Georgia\",Arial,sans-serif}p{line-height:24px;margin:0;font-size:16px;margin-bottom:24px}h1{font-size:175%}h2,.rst-content .toctree-wrapper p.caption{font-size:150%}h3{font-size:125%}h4{font-size:115%}h5{font-size:110%}h6{font-size:100%}hr{display:block;height:1px;border:0;border-top:1px solid #e1e4e5;margin:24px 0;padding:0}code,.rst-content tt,.rst-content code{white-space:nowrap;max-width:100%;background:#fff;border:solid 1px #e1e4e5;font-size:75%;padding:0 5px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,\"Liberation Mono\",\"Courier New\",Courier,monospace;color:#E74C3C;overflow-x:auto}code.code-large,.rst-content tt.code-large{font-size:90%}.wy-plain-list-disc,.rst-content .section ul,.rst-content .toctree-wrapper ul,article ul{list-style:disc;line-height:24px;margin-bottom:24px}.wy-plain-list-disc li,.rst-content .section ul li,.rst-content .toctree-wrapper ul li,article ul li{list-style:disc;margin-left:24px}.wy-plain-list-disc li p:last-child,.rst-content .section ul li p:last-child,.rst-content .toctree-wrapper ul li p:last-child,article ul li p:last-child{margin-bottom:0}.wy-plain-list-disc li ul,.rst-content .section ul li ul,.rst-content .toctree-wrapper ul li ul,article ul li ul{margin-bottom:0}.wy-plain-list-disc li li,.rst-content .section ul li li,.rst-content .toctree-wrapper ul li li,article ul li li{list-style:circle}.wy-plain-list-disc li li li,.rst-content .section ul li li li,.rst-content .toctree-wrapper ul li li li,article ul li li li{list-style:square}.wy-plain-list-disc li ol li,.rst-content .section ul li ol li,.rst-content .toctree-wrapper ul li ol li,article ul li ol li{list-style:decimal}.wy-plain-list-decimal,.rst-content .section ol,.rst-content ol.arabic,article ol{list-style:decimal;line-height:24px;margin-bottom:24px}.wy-plain-list-decimal li,.rst-content .section ol li,.rst-content ol.arabic li,article ol li{list-style:decimal;margin-left:24px}.wy-plain-list-decimal li p:last-child,.rst-content .section ol li p:last-child,.rst-content ol.arabic li p:last-child,article ol li p:last-child{margin-bottom:0}.wy-plain-list-decimal li ul,.rst-content .section ol li ul,.rst-content ol.arabic li ul,article ol li ul{margin-bottom:0}.wy-plain-list-decimal li ul li,.rst-content .section ol li ul li,.rst-content ol.arabic li ul li,article ol li ul li{list-style:disc}.wy-breadcrumbs{*zoom:1}.wy-breadcrumbs:before,.wy-breadcrumbs:after{display:table;content:\"\"}.wy-breadcrumbs:after{clear:both}.wy-breadcrumbs li{display:inline-block}.wy-breadcrumbs li.wy-breadcrumbs-aside{float:right}.wy-breadcrumbs li a{display:inline-block;padding:5px}.wy-breadcrumbs li a:first-child{padding-left:0}.wy-breadcrumbs li code,.wy-breadcrumbs li .rst-content tt,.rst-content .wy-breadcrumbs li tt{padding:5px;border:none;background:none}.wy-breadcrumbs li code.literal,.wy-breadcrumbs li .rst-content tt.literal,.rst-content .wy-breadcrumbs li tt.literal{color:#404040}.wy-breadcrumbs-extra{margin-bottom:0;color:#b3b3b3;font-size:80%;display:inline-block}@media screen and (max-width: 480px){.wy-breadcrumbs-extra{display:none}.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}@media print{.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}html{font-size:16px}.wy-affix{position:fixed;top:1.618em}.wy-menu a:hover{text-decoration:none}.wy-menu-horiz{*zoom:1}.wy-menu-horiz:before,.wy-menu-horiz:after{display:table;content:\"\"}.wy-menu-horiz:after{clear:both}.wy-menu-horiz ul,.wy-menu-horiz li{display:inline-block}.wy-menu-horiz li:hover{background:rgba(255,255,255,0.1)}.wy-menu-horiz li.divide-left{border-left:solid 1px #404040}.wy-menu-horiz li.divide-right{border-right:solid 1px #404040}.wy-menu-horiz a{height:32px;display:inline-block;line-height:32px;padding:0 16px}.wy-menu-vertical{width:300px}.wy-menu-vertical header,.wy-menu-vertical p.caption{color:#3a7ca8;height:32px;display:inline-block;line-height:32px;padding:0 1.618em;margin:12px 0 0 0;display:block;font-weight:bold;text-transform:uppercase;font-size:85%;white-space:nowrap}.wy-menu-vertical ul{margin-bottom:0}.wy-menu-vertical li.divide-top{border-top:solid 1px #404040}.wy-menu-vertical li.divide-bottom{border-bottom:solid 1px #404040}.wy-menu-vertical li.current{background:#e3e3e3}.wy-menu-vertical li.current a{color:gray;border-right:solid 1px #c9c9c9;padding:.4045em 2.427em}.wy-menu-vertical li.current a:hover{background:#d6d6d6}.wy-menu-vertical li code,.wy-menu-vertical li .rst-content tt,.rst-content .wy-menu-vertical li tt{border:none;background:inherit;color:inherit;padding-left:0;padding-right:0}.wy-menu-vertical li span.toctree-expand{display:block;float:left;margin-left:-1.2em;font-size:.8em;line-height:1.6em;color:#4d4d4d}.wy-menu-vertical li.on a,.wy-menu-vertical li.current>a{color:#404040;padding:.4045em 1.618em;font-weight:bold;position:relative;background:#fcfcfc;border:none;padding-left:1.618em -4px}.wy-menu-vertical li.on a:hover,.wy-menu-vertical li.current>a:hover{background:#fcfcfc}.wy-menu-vertical li.on a:hover span.toctree-expand,.wy-menu-vertical li.current>a:hover span.toctree-expand{color:gray}.wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.current>a span.toctree-expand{display:block;font-size:.8em;line-height:1.6em;color:#333}.wy-menu-vertical li.toctree-l1.current>a{border-bottom:solid 1px #c9c9c9;border-top:solid 1px #c9c9c9}.wy-menu-vertical li.toctree-l2 a,.wy-menu-vertical li.toctree-l3 a,.wy-menu-vertical li.toctree-l4 a{color:#404040}.wy-menu-vertical li.toctree-l1.current li.toctree-l2>ul,.wy-menu-vertical li.toctree-l2.current li.toctree-l3>ul{display:none}.wy-menu-vertical li.toctree-l1.current li.toctree-l2.current>ul,.wy-menu-vertical li.toctree-l2.current li.toctree-l3.current>ul{display:block}.wy-menu-vertical li.toctree-l2.current>a{background:#c9c9c9;padding:.4045em 2.427em}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{display:block;background:#c9c9c9;padding:.4045em 4.045em}.wy-menu-vertical li.toctree-l2 a:hover span.toctree-expand{color:gray}.wy-menu-vertical li.toctree-l2 span.toctree-expand{color:#a3a3a3}.wy-menu-vertical li.toctree-l3{font-size:.9em}.wy-menu-vertical li.toctree-l3.current>a{background:#bdbdbd;padding:.4045em 4.045em}.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{display:block;background:#bdbdbd;padding:.4045em 5.663em}.wy-menu-vertical li.toctree-l3 a:hover span.toctree-expand{color:gray}.wy-menu-vertical li.toctree-l3 span.toctree-expand{color:#969696}.wy-menu-vertical li.toctree-l4{font-size:.9em}.wy-menu-vertical li.current ul{display:block}.wy-menu-vertical li ul{margin-bottom:0;display:none}.wy-menu-vertical li ul li a{margin-bottom:0;color:#d9d9d9;font-weight:normal}.wy-menu-vertical a{display:inline-block;line-height:18px;padding:.4045em 1.618em;display:block;position:relative;font-size:90%;color:#d9d9d9}.wy-menu-vertical a:hover{background-color:#4e4a4a;cursor:pointer}.wy-menu-vertical a:hover span.toctree-expand{color:#d9d9d9}.wy-menu-vertical a:active{background-color:#2980B9;cursor:pointer;color:#fff}.wy-menu-vertical a:active span.toctree-expand{color:#fff}.wy-side-nav-search{display:block;width:300px;padding:.809em;margin-bottom:.809em;z-index:200;background-color:#2980B9;text-align:center;padding:.809em;display:block;color:#fcfcfc;margin-bottom:.809em}.wy-side-nav-search input[type=text]{width:100%;border-radius:50px;padding:6px 12px;border-color:#2472a4}.wy-side-nav-search img{display:block;margin:auto auto .809em auto;height:45px;width:45px;background-color:#2980B9;padding:5px;border-radius:100%}.wy-side-nav-search>a,.wy-side-nav-search .wy-dropdown>a{color:#fcfcfc;font-size:100%;font-weight:bold;display:inline-block;padding:4px 6px;margin-bottom:.809em}.wy-side-nav-search>a:hover,.wy-side-nav-search .wy-dropdown>a:hover{background:rgba(255,255,255,0.1)}.wy-side-nav-search>a img.logo,.wy-side-nav-search .wy-dropdown>a img.logo{display:block;margin:0 auto;height:auto;width:auto;border-radius:0;max-width:100%;background:transparent}.wy-side-nav-search>a.icon img.logo,.wy-side-nav-search .wy-dropdown>a.icon img.logo{margin-top:.85em}.wy-side-nav-search>div.version{margin-top:-.4045em;margin-bottom:.809em;font-weight:normal;color:rgba(255,255,255,0.3)}.wy-nav .wy-menu-vertical header{color:#2980B9}.wy-nav .wy-menu-vertical a{color:#b3b3b3}.wy-nav .wy-menu-vertical a:hover{background-color:#2980B9;color:#fff}[data-menu-wrap]{-webkit-transition:all .2s ease-in;-moz-transition:all .2s ease-in;transition:all .2s ease-in;position:absolute;opacity:1;width:100%;opacity:0}[data-menu-wrap].move-center{left:0;right:auto;opacity:1}[data-menu-wrap].move-left{right:auto;left:-100%;opacity:0}[data-menu-wrap].move-right{right:-100%;left:auto;opacity:0}.wy-body-for-nav{background:#fcfcfc}.wy-grid-for-nav{position:absolute;width:100%;height:100%}.wy-nav-side{position:fixed;top:0;bottom:0;left:0;padding-bottom:2em;width:300px;overflow-x:hidden;overflow-y:hidden;min-height:100%;color:#9b9b9b;background:#343131;z-index:200}.wy-side-scroll{width:320px;position:relative;overflow-x:hidden;overflow-y:scroll;height:100%}.wy-nav-top{display:none;background:#2980B9;color:#fff;padding:.4045em .809em;position:relative;line-height:50px;text-align:center;font-size:100%;*zoom:1}.wy-nav-top:before,.wy-nav-top:after{display:table;content:\"\"}.wy-nav-top:after{clear:both}.wy-nav-top a{color:#fff;font-weight:bold}.wy-nav-top img{margin-right:12px;height:45px;width:45px;background-color:#2980B9;padding:5px;border-radius:100%}.wy-nav-top i{font-size:30px;float:left;cursor:pointer;padding-top:inherit}.wy-nav-content-wrap{margin-left:300px;background:#fcfcfc;min-height:100%}.wy-nav-content{padding:1.618em 3.236em;height:100%;max-width:800px;margin:auto}.wy-body-mask{position:fixed;width:100%;height:100%;background:rgba(0,0,0,0.2);display:none;z-index:499}.wy-body-mask.on{display:block}footer{color:gray}footer p{margin-bottom:12px}footer span.commit code,footer span.commit .rst-content tt,.rst-content footer span.commit tt{padding:0px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,\"Liberation Mono\",\"Courier New\",Courier,monospace;font-size:1em;background:none;border:none;color:gray}.rst-footer-buttons{*zoom:1}.rst-footer-buttons:before,.rst-footer-buttons:after{width:100%}.rst-footer-buttons:before,.rst-footer-buttons:after{display:table;content:\"\"}.rst-footer-buttons:after{clear:both}.rst-breadcrumbs-buttons{margin-top:12px;*zoom:1}.rst-breadcrumbs-buttons:before,.rst-breadcrumbs-buttons:after{display:table;content:\"\"}.rst-breadcrumbs-buttons:after{clear:both}#search-results .search li{margin-bottom:24px;border-bottom:solid 1px #e1e4e5;padding-bottom:24px}#search-results .search li:first-child{border-top:solid 1px #e1e4e5;padding-top:24px}#search-results .search li a{font-size:120%;margin-bottom:12px;display:inline-block}#search-results .context{color:gray;font-size:90%}.genindextable li>ul{margin-left:24px}@media screen and (max-width: 768px){.wy-body-for-nav{background:#fcfcfc}.wy-nav-top{display:block}.wy-nav-side{left:-300px}.wy-nav-side.shift{width:85%;left:0}.wy-side-scroll{width:auto}.wy-side-nav-search{width:auto}.wy-menu.wy-menu-vertical{width:auto}.wy-nav-content-wrap{margin-left:0}.wy-nav-content-wrap .wy-nav-content{padding:1.618em}.wy-nav-content-wrap.shift{position:fixed;min-width:100%;left:85%;top:0;height:100%;overflow:hidden}}@media screen and (min-width: 1100px){.wy-nav-content-wrap{background:rgba(0,0,0,0.05)}.wy-nav-content{margin:0;background:#fcfcfc}}@media print{.rst-versions,footer,.wy-nav-side{display:none}.wy-nav-content-wrap{margin-left:0}}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:\"Lato\",\"proxima-nova\",\"Helvetica Neue\",Arial,sans-serif;z-index:400}.rst-versions a{color:#2980B9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27AE60;*zoom:1}.rst-versions .rst-current-version:before,.rst-versions .rst-current-version:after{display:table;content:\"\"}.rst-versions .rst-current-version:after{clear:both}.rst-versions .rst-current-version .fa,.rst-versions .rst-current-version .wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li .rst-versions .rst-current-version span.toctree-expand,.rst-versions .rst-current-version .rst-content .admonition-title,.rst-content .rst-versions .rst-current-version .admonition-title,.rst-versions .rst-current-version .rst-content h1 .headerlink,.rst-content h1 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h2 .headerlink,.rst-content h2 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h3 .headerlink,.rst-content h3 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h4 .headerlink,.rst-content h4 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h5 .headerlink,.rst-content h5 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h6 .headerlink,.rst-content h6 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content dl dt .headerlink,.rst-content dl dt .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content p.caption .headerlink,.rst-content p.caption .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content table>caption .headerlink,.rst-content table>caption .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content .code-block-caption .headerlink,.rst-content .code-block-caption .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content tt.download span:first-child,.rst-content tt.download .rst-versions .rst-current-version span:first-child,.rst-versions .rst-current-version .rst-content code.download span:first-child,.rst-content code.download .rst-versions .rst-current-version span:first-child,.rst-versions .rst-current-version .icon{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#E74C3C;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#F1C40F;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:gray;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:solid 1px #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .icon-book{float:none}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge .rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width: 768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}}.rst-content img{max-width:100%;height:auto}.rst-content div.figure{margin-bottom:24px}.rst-content div.figure p.caption{font-style:italic}.rst-content div.figure p:last-child.caption{margin-bottom:0px}.rst-content div.figure.align-center{text-align:center}.rst-content .section>img,.rst-content .section>a>img{margin-bottom:24px}.rst-content abbr[title]{text-decoration:none}.rst-content.style-external-links a.reference.external:after{font-family:FontAwesome;content:\"\";color:#b3b3b3;vertical-align:super;font-size:60%;margin:0 .2em}.rst-content blockquote{margin-left:24px;line-height:24px;margin-bottom:24px}.rst-content pre.literal-block{white-space:pre;margin:0;padding:12px 12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,\"Liberation Mono\",\"Courier New\",Courier,monospace;display:block;overflow:auto}.rst-content pre.literal-block,.rst-content div[class^='highlight']{border:1px solid #e1e4e5;overflow-x:auto;margin:1px 0 24px 0}.rst-content pre.literal-block div[class^='highlight'],.rst-content div[class^='highlight'] div[class^='highlight']{padding:0px;border:none;margin:0}.rst-content div[class^='highlight'] td.code{width:100%}.rst-content .linenodiv pre{border-right:solid 1px #e6e9ea;margin:0;padding:12px 12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,\"Liberation Mono\",\"Courier New\",Courier,monospace;user-select:none;pointer-events:none}.rst-content div[class^='highlight'] pre{white-space:pre;margin:0;padding:12px 12px;display:block;overflow:auto}.rst-content div[class^='highlight'] pre .hll{display:block;margin:0 -12px;padding:0 12px}.rst-content pre.literal-block,.rst-content div[class^='highlight'] pre,.rst-content .linenodiv pre{font-family:SFMono-Regular,Menlo,Monaco,Consolas,\"Liberation Mono\",\"Courier New\",Courier,monospace;font-size:12px;line-height:1.4}.rst-content .code-block-caption{font-style:italic;font-size:85%;line-height:1;padding:1em 0;text-align:center}@media print{.rst-content .codeblock,.rst-content div[class^='highlight'],.rst-content div[class^='highlight'] pre{white-space:pre-wrap}}.rst-content .note .last,.rst-content .attention .last,.rst-content .caution .last,.rst-content .danger .last,.rst-content .error .last,.rst-content .hint .last,.rst-content .important .last,.rst-content .tip .last,.rst-content .warning .last,.rst-content .seealso .last,.rst-content .admonition-todo .last,.rst-content .admonition .last{margin-bottom:0}.rst-content .admonition-title:before{margin-right:4px}.rst-content .admonition table{border-color:rgba(0,0,0,0.1)}.rst-content .admonition table td,.rst-content .admonition table th{background:transparent !important;border-color:rgba(0,0,0,0.1) !important}.rst-content .section ol.loweralpha,.rst-content .section ol.loweralpha li{list-style:lower-alpha}.rst-content .section ol.upperalpha,.rst-content .section ol.upperalpha li{list-style:upper-alpha}.rst-content .section ol p,.rst-content .section ul p{margin-bottom:12px}.rst-content .section ol p:last-child,.rst-content .section ul p:last-child{margin-bottom:24px}.rst-content .line-block{margin-left:0px;margin-bottom:24px;line-height:24px}.rst-content .line-block .line-block{margin-left:24px;margin-bottom:0px}.rst-content .topic-title{font-weight:bold;margin-bottom:12px}.rst-content .toc-backref{color:#404040}.rst-content .align-right{float:right;margin:0px 0px 24px 24px}.rst-content .align-left{float:left;margin:0px 24px 24px 0px}.rst-content .align-center{margin:auto}.rst-content .align-center:not(table){display:block}.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content .toctree-wrapper p.caption .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content dl dt .headerlink,.rst-content p.caption .headerlink,.rst-content table>caption .headerlink,.rst-content .code-block-caption .headerlink{visibility:hidden;font-size:14px}.rst-content h1 .headerlink:after,.rst-content h2 .headerlink:after,.rst-content .toctree-wrapper p.caption .headerlink:after,.rst-content h3 .headerlink:after,.rst-content h4 .headerlink:after,.rst-content h5 .headerlink:after,.rst-content h6 .headerlink:after,.rst-content dl dt .headerlink:after,.rst-content p.caption .headerlink:after,.rst-content table>caption .headerlink:after,.rst-content .code-block-caption .headerlink:after{content:\"\";font-family:FontAwesome}.rst-content h1:hover .headerlink:after,.rst-content h2:hover .headerlink:after,.rst-content .toctree-wrapper p.caption:hover .headerlink:after,.rst-content h3:hover .headerlink:after,.rst-content h4:hover .headerlink:after,.rst-content h5:hover .headerlink:after,.rst-content h6:hover .headerlink:after,.rst-content dl dt:hover .headerlink:after,.rst-content p.caption:hover .headerlink:after,.rst-content table>caption:hover .headerlink:after,.rst-content .code-block-caption:hover .headerlink:after{visibility:visible}.rst-content table>caption .headerlink:after{font-size:12px}.rst-content .centered{text-align:center}.rst-content .sidebar{float:right;width:40%;display:block;margin:0 0 24px 24px;padding:24px;background:#f3f6f6;border:solid 1px #e1e4e5}.rst-content .sidebar p,.rst-content .sidebar ul,.rst-content .sidebar dl{font-size:90%}.rst-content .sidebar .last{margin-bottom:0}.rst-content .sidebar .sidebar-title{display:block;font-family:\"Roboto Slab\",\"ff-tisa-web-pro\",\"Georgia\",Arial,sans-serif;font-weight:bold;background:#e1e4e5;padding:6px 12px;margin:-24px;margin-bottom:24px;font-size:100%}.rst-content .highlighted{background:#F1C40F;display:inline-block;font-weight:bold;padding:0 6px}.rst-content .footnote-reference,.rst-content .citation-reference{vertical-align:baseline;position:relative;top:-0.4em;line-height:0;font-size:90%}.rst-content table.docutils.citation,.rst-content table.docutils.footnote{background:none;border:none;color:gray}.rst-content table.docutils.citation td,.rst-content table.docutils.citation tr,.rst-content table.docutils.footnote td,.rst-content table.docutils.footnote tr{border:none;background-color:transparent !important;white-space:normal}.rst-content table.docutils.citation td.label,.rst-content table.docutils.footnote td.label{padding-left:0;padding-right:0;vertical-align:top}.rst-content table.docutils.citation tt,.rst-content table.docutils.citation code,.rst-content table.docutils.footnote tt,.rst-content table.docutils.footnote code{color:#555}.rst-content .wy-table-responsive.citation,.rst-content .wy-table-responsive.footnote{margin-bottom:0}.rst-content .wy-table-responsive.citation+:not(.citation),.rst-content .wy-table-responsive.footnote+:not(.footnote){margin-top:24px}.rst-content .wy-table-responsive.citation:last-child,.rst-content .wy-table-responsive.footnote:last-child{margin-bottom:24px}.rst-content table.docutils th{border-color:#e1e4e5}.rst-content table.docutils td .last,.rst-content table.docutils td .last :last-child{margin-bottom:0}.rst-content table.field-list{border:none}.rst-content table.field-list td{border:none}.rst-content table.field-list td p{font-size:inherit;line-height:inherit}.rst-content table.field-list td>strong{display:inline-block}.rst-content table.field-list .field-name{padding-right:10px;text-align:left;white-space:nowrap}.rst-content table.field-list .field-body{text-align:left}.rst-content tt,.rst-content tt,.rst-content code{color:#000;font-family:SFMono-Regular,Menlo,Monaco,Consolas,\"Liberation Mono\",\"Courier New\",Courier,monospace;padding:2px 5px}.rst-content tt big,.rst-content tt em,.rst-content tt big,.rst-content code big,.rst-content tt em,.rst-content code em{font-size:100% !important;line-height:normal}.rst-content tt.literal,.rst-content tt.literal,.rst-content code.literal{color:#E74C3C}.rst-content tt.xref,a .rst-content tt,.rst-content tt.xref,.rst-content code.xref,a .rst-content tt,a .rst-content code{font-weight:bold;color:#404040}.rst-content pre,.rst-content kbd,.rst-content samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,\"Liberation Mono\",\"Courier New\",Courier,monospace}.rst-content a tt,.rst-content a tt,.rst-content a code{color:#2980B9}.rst-content dl{margin-bottom:24px}.rst-content dl dt{font-weight:bold;margin-bottom:12px}.rst-content dl p,.rst-content dl table,.rst-content dl ul,.rst-content dl ol{margin-bottom:12px !important}.rst-content dl dd{margin:0 0 12px 24px;line-height:24px}.rst-content dl:not(.docutils){margin-bottom:24px}.rst-content dl:not(.docutils) dt{display:table;margin:6px 0;font-size:90%;line-height:normal;background:#e7f2fa;color:#2980B9;border-top:solid 3px #6ab0de;padding:6px;position:relative}.rst-content dl:not(.docutils) dt:before{color:#6ab0de}.rst-content dl:not(.docutils) dt .headerlink{color:#404040;font-size:100% !important}.rst-content dl:not(.docutils) dl dt{margin-bottom:6px;border:none;border-left:solid 3px #ccc;background:#f0f0f0;color:#555}.rst-content dl:not(.docutils) dl dt .headerlink{color:#404040;font-size:100% !important}.rst-content dl:not(.docutils) dt:first-child{margin-top:0}.rst-content dl:not(.docutils) tt,.rst-content dl:not(.docutils) tt,.rst-content dl:not(.docutils) code{font-weight:bold}.rst-content dl:not(.docutils) tt.descname,.rst-content dl:not(.docutils) tt.descclassname,.rst-content dl:not(.docutils) tt.descname,.rst-content dl:not(.docutils) code.descname,.rst-content dl:not(.docutils) tt.descclassname,.rst-content dl:not(.docutils) code.descclassname{background-color:transparent;border:none;padding:0;font-size:100% !important}.rst-content dl:not(.docutils) tt.descname,.rst-content dl:not(.docutils) tt.descname,.rst-content dl:not(.docutils) code.descname{font-weight:bold}.rst-content dl:not(.docutils) .optional{display:inline-block;padding:0 4px;color:#000;font-weight:bold}.rst-content dl:not(.docutils) .property{display:inline-block;padding-right:8px}.rst-content .viewcode-link,.rst-content .viewcode-back{display:inline-block;color:#27AE60;font-size:80%;padding-left:24px}.rst-content .viewcode-back{display:block;float:right}.rst-content p.rubric{margin-bottom:12px;font-weight:bold}.rst-content tt.download,.rst-content code.download{background:inherit;padding:inherit;font-weight:normal;font-family:inherit;font-size:inherit;color:inherit;border:inherit;white-space:inherit}.rst-content tt.download span:first-child,.rst-content code.download span:first-child{-webkit-font-smoothing:subpixel-antialiased}.rst-content tt.download span:first-child:before,.rst-content code.download span:first-child:before{margin-right:4px}.rst-content .guilabel{border:1px solid #7fbbe3;background:#e7f2fa;font-size:80%;font-weight:700;border-radius:4px;padding:2.4px 6px;margin:auto 2px}.rst-content .versionmodified{font-style:italic}@media screen and (max-width: 480px){.rst-content .sidebar{width:100%}}span[id*='MathJax-Span']{color:#404040}.math{text-align:center}@font-face{font-family:\"Lato\";src:url(\"../fonts/Lato/lato-regular.eot\");src:url(\"../fonts/Lato/lato-regular.eot?#iefix\") format(\"embedded-opentype\"),url(\"../fonts/Lato/lato-regular.woff2\") format(\"woff2\"),url(\"../fonts/Lato/lato-regular.woff\") format(\"woff\"),url(\"../fonts/Lato/lato-regular.ttf\") format(\"truetype\");font-weight:400;font-style:normal}@font-face{font-family:\"Lato\";src:url(\"../fonts/Lato/lato-bold.eot\");src:url(\"../fonts/Lato/lato-bold.eot?#iefix\") format(\"embedded-opentype\"),url(\"../fonts/Lato/lato-bold.woff2\") format(\"woff2\"),url(\"../fonts/Lato/lato-bold.woff\") format(\"woff\"),url(\"../fonts/Lato/lato-bold.ttf\") format(\"truetype\");font-weight:700;font-style:normal}@font-face{font-family:\"Lato\";src:url(\"../fonts/Lato/lato-bolditalic.eot\");src:url(\"../fonts/Lato/lato-bolditalic.eot?#iefix\") format(\"embedded-opentype\"),url(\"../fonts/Lato/lato-bolditalic.woff2\") format(\"woff2\"),url(\"../fonts/Lato/lato-bolditalic.woff\") format(\"woff\"),url(\"../fonts/Lato/lato-bolditalic.ttf\") format(\"truetype\");font-weight:700;font-style:italic}@font-face{font-family:\"Lato\";src:url(\"../fonts/Lato/lato-italic.eot\");src:url(\"../fonts/Lato/lato-italic.eot?#iefix\") format(\"embedded-opentype\"),url(\"../fonts/Lato/lato-italic.woff2\") format(\"woff2\"),url(\"../fonts/Lato/lato-italic.woff\") format(\"woff\"),url(\"../fonts/Lato/lato-italic.ttf\") format(\"truetype\");font-weight:400;font-style:italic}@font-face{font-family:\"Roboto Slab\";font-style:normal;font-weight:400;src:url(\"../fonts/RobotoSlab/roboto-slab.eot\");src:url(\"../fonts/RobotoSlab/roboto-slab-v7-regular.eot?#iefix\") format(\"embedded-opentype\"),url(\"../fonts/RobotoSlab/roboto-slab-v7-regular.woff2\") format(\"woff2\"),url(\"../fonts/RobotoSlab/roboto-slab-v7-regular.woff\") format(\"woff\"),url(\"../fonts/RobotoSlab/roboto-slab-v7-regular.ttf\") format(\"truetype\")}@font-face{font-family:\"Roboto Slab\";font-style:normal;font-weight:700;src:url(\"../fonts/RobotoSlab/roboto-slab-v7-bold.eot\");src:url(\"../fonts/RobotoSlab/roboto-slab-v7-bold.eot?#iefix\") format(\"embedded-opentype\"),url(\"../fonts/RobotoSlab/roboto-slab-v7-bold.woff2\") format(\"woff2\"),url(\"../fonts/RobotoSlab/roboto-slab-v7-bold.woff\") format(\"woff\"),url(\"../fonts/RobotoSlab/roboto-slab-v7-bold.ttf\") format(\"truetype\")}\n"
  },
  {
    "path": "docs/_static/custom.css",
    "content": "/* This file intentionally left blank. */\n"
  },
  {
    "path": "docs/_static/doctools.js",
    "content": "/*\n * doctools.js\n * ~~~~~~~~~~~\n *\n * Sphinx JavaScript utilities for all documentation.\n *\n * :copyright: Copyright 2007-2019 by the Sphinx team, see AUTHORS.\n * :license: BSD, see LICENSE for details.\n *\n */\n\n/**\n * select a different prefix for underscore\n */\n$u = _.noConflict();\n\n/**\n * make the code below compatible with browsers without\n * an installed firebug like debugger\nif (!window.console || !console.firebug) {\n  var names = [\"log\", \"debug\", \"info\", \"warn\", \"error\", \"assert\", \"dir\",\n    \"dirxml\", \"group\", \"groupEnd\", \"time\", \"timeEnd\", \"count\", \"trace\",\n    \"profile\", \"profileEnd\"];\n  window.console = {};\n  for (var i = 0; i < names.length; ++i)\n    window.console[names[i]] = function() {};\n}\n */\n\n/**\n * small helper function to urldecode strings\n */\njQuery.urldecode = function(x) {\n  return decodeURIComponent(x).replace(/\\+/g, ' ');\n};\n\n/**\n * small helper function to urlencode strings\n */\njQuery.urlencode = encodeURIComponent;\n\n/**\n * This function returns the parsed url parameters of the\n * current request. Multiple values per key are supported,\n * it will always return arrays of strings for the value parts.\n */\njQuery.getQueryParameters = function(s) {\n  if (typeof s === 'undefined')\n    s = document.location.search;\n  var parts = s.substr(s.indexOf('?') + 1).split('&');\n  var result = {};\n  for (var i = 0; i < parts.length; i++) {\n    var tmp = parts[i].split('=', 2);\n    var key = jQuery.urldecode(tmp[0]);\n    var value = jQuery.urldecode(tmp[1]);\n    if (key in result)\n      result[key].push(value);\n    else\n      result[key] = [value];\n  }\n  return result;\n};\n\n/**\n * highlight a given string on a jquery object by wrapping it in\n * span elements with the given class name.\n */\njQuery.fn.highlightText = function(text, className) {\n  function highlight(node, addItems) {\n    if (node.nodeType === 3) {\n      var val = node.nodeValue;\n      var pos = val.toLowerCase().indexOf(text);\n      if (pos >= 0 &&\n          !jQuery(node.parentNode).hasClass(className) &&\n          !jQuery(node.parentNode).hasClass(\"nohighlight\")) {\n        var span;\n        var isInSVG = jQuery(node).closest(\"body, svg, foreignObject\").is(\"svg\");\n        if (isInSVG) {\n          span = document.createElementNS(\"http://www.w3.org/2000/svg\", \"tspan\");\n        } else {\n          span = document.createElement(\"span\");\n          span.className = className;\n        }\n        span.appendChild(document.createTextNode(val.substr(pos, text.length)));\n        node.parentNode.insertBefore(span, node.parentNode.insertBefore(\n          document.createTextNode(val.substr(pos + text.length)),\n          node.nextSibling));\n        node.nodeValue = val.substr(0, pos);\n        if (isInSVG) {\n          var bbox = span.getBBox();\n          var rect = document.createElementNS(\"http://www.w3.org/2000/svg\", \"rect\");\n       \t  rect.x.baseVal.value = bbox.x;\n          rect.y.baseVal.value = bbox.y;\n          rect.width.baseVal.value = bbox.width;\n          rect.height.baseVal.value = bbox.height;\n          rect.setAttribute('class', className);\n          var parentOfText = node.parentNode.parentNode;\n          addItems.push({\n              \"parent\": node.parentNode,\n              \"target\": rect});\n        }\n      }\n    }\n    else if (!jQuery(node).is(\"button, select, textarea\")) {\n      jQuery.each(node.childNodes, function() {\n        highlight(this, addItems);\n      });\n    }\n  }\n  var addItems = [];\n  var result = this.each(function() {\n    highlight(this, addItems);\n  });\n  for (var i = 0; i < addItems.length; ++i) {\n    jQuery(addItems[i].parent).before(addItems[i].target);\n  }\n  return result;\n};\n\n/*\n * backward compatibility for jQuery.browser\n * This will be supported until firefox bug is fixed.\n */\nif (!jQuery.browser) {\n  jQuery.uaMatch = function(ua) {\n    ua = ua.toLowerCase();\n\n    var match = /(chrome)[ \\/]([\\w.]+)/.exec(ua) ||\n      /(webkit)[ \\/]([\\w.]+)/.exec(ua) ||\n      /(opera)(?:.*version|)[ \\/]([\\w.]+)/.exec(ua) ||\n      /(msie) ([\\w.]+)/.exec(ua) ||\n      ua.indexOf(\"compatible\") < 0 && /(mozilla)(?:.*? rv:([\\w.]+)|)/.exec(ua) ||\n      [];\n\n    return {\n      browser: match[ 1 ] || \"\",\n      version: match[ 2 ] || \"0\"\n    };\n  };\n  jQuery.browser = {};\n  jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true;\n}\n\n/**\n * Small JavaScript module for the documentation.\n */\nvar Documentation = {\n\n  init : function() {\n    this.fixFirefoxAnchorBug();\n    this.highlightSearchWords();\n    this.initIndexTable();\n    if (DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) {\n      this.initOnKeyListeners();\n    }\n  },\n\n  /**\n   * i18n support\n   */\n  TRANSLATIONS : {},\n  PLURAL_EXPR : function(n) { return n === 1 ? 0 : 1; },\n  LOCALE : 'unknown',\n\n  // gettext and ngettext don't access this so that the functions\n  // can safely bound to a different name (_ = Documentation.gettext)\n  gettext : function(string) {\n    var translated = Documentation.TRANSLATIONS[string];\n    if (typeof translated === 'undefined')\n      return string;\n    return (typeof translated === 'string') ? translated : translated[0];\n  },\n\n  ngettext : function(singular, plural, n) {\n    var translated = Documentation.TRANSLATIONS[singular];\n    if (typeof translated === 'undefined')\n      return (n == 1) ? singular : plural;\n    return translated[Documentation.PLURALEXPR(n)];\n  },\n\n  addTranslations : function(catalog) {\n    for (var key in catalog.messages)\n      this.TRANSLATIONS[key] = catalog.messages[key];\n    this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')');\n    this.LOCALE = catalog.locale;\n  },\n\n  /**\n   * add context elements like header anchor links\n   */\n  addContextElements : function() {\n    $('div[id] > :header:first').each(function() {\n      $('<a class=\"headerlink\">\\u00B6</a>').\n      attr('href', '#' + this.id).\n      attr('title', _('Permalink to this headline')).\n      appendTo(this);\n    });\n    $('dt[id]').each(function() {\n      $('<a class=\"headerlink\">\\u00B6</a>').\n      attr('href', '#' + this.id).\n      attr('title', _('Permalink to this definition')).\n      appendTo(this);\n    });\n  },\n\n  /**\n   * workaround a firefox stupidity\n   * see: https://bugzilla.mozilla.org/show_bug.cgi?id=645075\n   */\n  fixFirefoxAnchorBug : function() {\n    if (document.location.hash && $.browser.mozilla)\n      window.setTimeout(function() {\n        document.location.href += '';\n      }, 10);\n  },\n\n  /**\n   * highlight the search words provided in the url in the text\n   */\n  highlightSearchWords : function() {\n    var params = $.getQueryParameters();\n    var terms = (params.highlight) ? params.highlight[0].split(/\\s+/) : [];\n    if (terms.length) {\n      var body = $('div.body');\n      if (!body.length) {\n        body = $('body');\n      }\n      window.setTimeout(function() {\n        $.each(terms, function() {\n          body.highlightText(this.toLowerCase(), 'highlighted');\n        });\n      }, 10);\n      $('<p class=\"highlight-link\"><a href=\"javascript:Documentation.' +\n        'hideSearchWords()\">' + _('Hide Search Matches') + '</a></p>')\n          .appendTo($('#searchbox'));\n    }\n  },\n\n  /**\n   * init the domain index toggle buttons\n   */\n  initIndexTable : function() {\n    var togglers = $('img.toggler').click(function() {\n      var src = $(this).attr('src');\n      var idnum = $(this).attr('id').substr(7);\n      $('tr.cg-' + idnum).toggle();\n      if (src.substr(-9) === 'minus.png')\n        $(this).attr('src', src.substr(0, src.length-9) + 'plus.png');\n      else\n        $(this).attr('src', src.substr(0, src.length-8) + 'minus.png');\n    }).css('display', '');\n    if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) {\n        togglers.click();\n    }\n  },\n\n  /**\n   * helper function to hide the search marks again\n   */\n  hideSearchWords : function() {\n    $('#searchbox .highlight-link').fadeOut(300);\n    $('span.highlighted').removeClass('highlighted');\n  },\n\n  /**\n   * make the url absolute\n   */\n  makeURL : function(relativeURL) {\n    return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL;\n  },\n\n  /**\n   * get the current relative url\n   */\n  getCurrentURL : function() {\n    var path = document.location.pathname;\n    var parts = path.split(/\\//);\n    $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\\//), function() {\n      if (this === '..')\n        parts.pop();\n    });\n    var url = parts.join('/');\n    return path.substring(url.lastIndexOf('/') + 1, path.length - 1);\n  },\n\n  initOnKeyListeners: function() {\n    $(document).keyup(function(event) {\n      var activeElementType = document.activeElement.tagName;\n      // don't navigate when in search box or textarea\n      if (activeElementType !== 'TEXTAREA' && activeElementType !== 'INPUT' && activeElementType !== 'SELECT') {\n        switch (event.keyCode) {\n          case 37: // left\n            var prevHref = $('link[rel=\"prev\"]').prop('href');\n            if (prevHref) {\n              window.location.href = prevHref;\n              return false;\n            }\n          case 39: // right\n            var nextHref = $('link[rel=\"next\"]').prop('href');\n            if (nextHref) {\n              window.location.href = nextHref;\n              return false;\n            }\n        }\n      }\n    });\n  }\n};\n\n// quick alias for translations\n_ = Documentation.gettext;\n\n$(document).ready(function() {\n  Documentation.init();\n});\n"
  },
  {
    "path": "docs/_static/documentation_options.js",
    "content": "var DOCUMENTATION_OPTIONS = {\n    URL_ROOT: document.getElementById(\"documentation_options\").getAttribute('data-url_root'),\n    VERSION: '1.2.0',\n    LANGUAGE: 'zh_CN',\n    COLLAPSE_INDEX: false,\n    FILE_SUFFIX: '.html',\n    HAS_SOURCE: true,\n    SOURCELINK_SUFFIX: '.txt',\n    NAVIGATION_WITH_KEYS: false,\n};"
  },
  {
    "path": "docs/_static/jquery-3.2.1.js",
    "content": "/*!\n * jQuery JavaScript Library v3.2.1\n * https://jquery.com/\n *\n * Includes Sizzle.js\n * https://sizzlejs.com/\n *\n * Copyright JS Foundation and other contributors\n * Released under the MIT license\n * https://jquery.org/license\n *\n * Date: 2017-03-20T18:59Z\n */\n( function( global, factory ) {\n\n\t\"use strict\";\n\n\tif ( typeof module === \"object\" && typeof module.exports === \"object\" ) {\n\n\t\t// For CommonJS and CommonJS-like environments where a proper `window`\n\t\t// is present, execute the factory and get jQuery.\n\t\t// For environments that do not have a `window` with a `document`\n\t\t// (such as Node.js), expose a factory as module.exports.\n\t\t// This accentuates the need for the creation of a real `window`.\n\t\t// e.g. var jQuery = require(\"jquery\")(window);\n\t\t// See ticket #14549 for more info.\n\t\tmodule.exports = global.document ?\n\t\t\tfactory( global, true ) :\n\t\t\tfunction( w ) {\n\t\t\t\tif ( !w.document ) {\n\t\t\t\t\tthrow new Error( \"jQuery requires a window with a document\" );\n\t\t\t\t}\n\t\t\t\treturn factory( w );\n\t\t\t};\n\t} else {\n\t\tfactory( global );\n\t}\n\n// Pass this if window is not defined yet\n} )( typeof window !== \"undefined\" ? window : this, function( window, noGlobal ) {\n\n// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1\n// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode\n// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common\n// enough that all such attempts are guarded in a try block.\n\"use strict\";\n\nvar arr = [];\n\nvar document = window.document;\n\nvar getProto = Object.getPrototypeOf;\n\nvar slice = arr.slice;\n\nvar concat = arr.concat;\n\nvar push = arr.push;\n\nvar indexOf = arr.indexOf;\n\nvar class2type = {};\n\nvar toString = class2type.toString;\n\nvar hasOwn = class2type.hasOwnProperty;\n\nvar fnToString = hasOwn.toString;\n\nvar ObjectFunctionString = fnToString.call( Object );\n\nvar support = {};\n\n\n\n\tfunction DOMEval( code, doc ) {\n\t\tdoc = doc || document;\n\n\t\tvar script = doc.createElement( \"script\" );\n\n\t\tscript.text = code;\n\t\tdoc.head.appendChild( script ).parentNode.removeChild( script );\n\t}\n/* global Symbol */\n// Defining this global in .eslintrc.json would create a danger of using the global\n// unguarded in another place, it seems safer to define global only for this module\n\n\n\nvar\n\tversion = \"3.2.1\",\n\n\t// Define a local copy of jQuery\n\tjQuery = function( selector, context ) {\n\n\t\t// The jQuery object is actually just the init constructor 'enhanced'\n\t\t// Need init if jQuery is called (just allow error to be thrown if not included)\n\t\treturn new jQuery.fn.init( selector, context );\n\t},\n\n\t// Support: Android <=4.0 only\n\t// Make sure we trim BOM and NBSP\n\trtrim = /^[\\s\\uFEFF\\xA0]+|[\\s\\uFEFF\\xA0]+$/g,\n\n\t// Matches dashed string for camelizing\n\trmsPrefix = /^-ms-/,\n\trdashAlpha = /-([a-z])/g,\n\n\t// Used by jQuery.camelCase as callback to replace()\n\tfcamelCase = function( all, letter ) {\n\t\treturn letter.toUpperCase();\n\t};\n\njQuery.fn = jQuery.prototype = {\n\n\t// The current version of jQuery being used\n\tjquery: version,\n\n\tconstructor: jQuery,\n\n\t// The default length of a jQuery object is 0\n\tlength: 0,\n\n\ttoArray: function() {\n\t\treturn slice.call( this );\n\t},\n\n\t// Get the Nth element in the matched element set OR\n\t// Get the whole matched element set as a clean array\n\tget: function( num ) {\n\n\t\t// Return all the elements in a clean array\n\t\tif ( num == null ) {\n\t\t\treturn slice.call( this );\n\t\t}\n\n\t\t// Return just the one element from the set\n\t\treturn num < 0 ? this[ num + this.length ] : this[ num ];\n\t},\n\n\t// Take an array of elements and push it onto the stack\n\t// (returning the new matched element set)\n\tpushStack: function( elems ) {\n\n\t\t// Build a new jQuery matched element set\n\t\tvar ret = jQuery.merge( this.constructor(), elems );\n\n\t\t// Add the old object onto the stack (as a reference)\n\t\tret.prevObject = this;\n\n\t\t// Return the newly-formed element set\n\t\treturn ret;\n\t},\n\n\t// Execute a callback for every element in the matched set.\n\teach: function( callback ) {\n\t\treturn jQuery.each( this, callback );\n\t},\n\n\tmap: function( callback ) {\n\t\treturn this.pushStack( jQuery.map( this, function( elem, i ) {\n\t\t\treturn callback.call( elem, i, elem );\n\t\t} ) );\n\t},\n\n\tslice: function() {\n\t\treturn this.pushStack( slice.apply( this, arguments ) );\n\t},\n\n\tfirst: function() {\n\t\treturn this.eq( 0 );\n\t},\n\n\tlast: function() {\n\t\treturn this.eq( -1 );\n\t},\n\n\teq: function( i ) {\n\t\tvar len = this.length,\n\t\t\tj = +i + ( i < 0 ? len : 0 );\n\t\treturn this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] );\n\t},\n\n\tend: function() {\n\t\treturn this.prevObject || this.constructor();\n\t},\n\n\t// For internal use only.\n\t// Behaves like an Array's method, not like a jQuery method.\n\tpush: push,\n\tsort: arr.sort,\n\tsplice: arr.splice\n};\n\njQuery.extend = jQuery.fn.extend = function() {\n\tvar options, name, src, copy, copyIsArray, clone,\n\t\ttarget = arguments[ 0 ] || {},\n\t\ti = 1,\n\t\tlength = arguments.length,\n\t\tdeep = false;\n\n\t// Handle a deep copy situation\n\tif ( typeof target === \"boolean\" ) {\n\t\tdeep = target;\n\n\t\t// Skip the boolean and the target\n\t\ttarget = arguments[ i ] || {};\n\t\ti++;\n\t}\n\n\t// Handle case when target is a string or something (possible in deep copy)\n\tif ( typeof target !== \"object\" && !jQuery.isFunction( target ) ) {\n\t\ttarget = {};\n\t}\n\n\t// Extend jQuery itself if only one argument is passed\n\tif ( i === length ) {\n\t\ttarget = this;\n\t\ti--;\n\t}\n\n\tfor ( ; i < length; i++ ) {\n\n\t\t// Only deal with non-null/undefined values\n\t\tif ( ( options = arguments[ i ] ) != null ) {\n\n\t\t\t// Extend the base object\n\t\t\tfor ( name in options ) {\n\t\t\t\tsrc = target[ name ];\n\t\t\t\tcopy = options[ name ];\n\n\t\t\t\t// Prevent never-ending loop\n\t\t\t\tif ( target === copy ) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// Recurse if we're merging plain objects or arrays\n\t\t\t\tif ( deep && copy && ( jQuery.isPlainObject( copy ) ||\n\t\t\t\t\t( copyIsArray = Array.isArray( copy ) ) ) ) {\n\n\t\t\t\t\tif ( copyIsArray ) {\n\t\t\t\t\t\tcopyIsArray = false;\n\t\t\t\t\t\tclone = src && Array.isArray( src ) ? src : [];\n\n\t\t\t\t\t} else {\n\t\t\t\t\t\tclone = src && jQuery.isPlainObject( src ) ? src : {};\n\t\t\t\t\t}\n\n\t\t\t\t\t// Never move original objects, clone them\n\t\t\t\t\ttarget[ name ] = jQuery.extend( deep, clone, copy );\n\n\t\t\t\t// Don't bring in undefined values\n\t\t\t\t} else if ( copy !== undefined ) {\n\t\t\t\t\ttarget[ name ] = copy;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Return the modified object\n\treturn target;\n};\n\njQuery.extend( {\n\n\t// Unique for each copy of jQuery on the page\n\texpando: \"jQuery\" + ( version + Math.random() ).replace( /\\D/g, \"\" ),\n\n\t// Assume jQuery is ready without the ready module\n\tisReady: true,\n\n\terror: function( msg ) {\n\t\tthrow new Error( msg );\n\t},\n\n\tnoop: function() {},\n\n\tisFunction: function( obj ) {\n\t\treturn jQuery.type( obj ) === \"function\";\n\t},\n\n\tisWindow: function( obj ) {\n\t\treturn obj != null && obj === obj.window;\n\t},\n\n\tisNumeric: function( obj ) {\n\n\t\t// As of jQuery 3.0, isNumeric is limited to\n\t\t// strings and numbers (primitives or objects)\n\t\t// that can be coerced to finite numbers (gh-2662)\n\t\tvar type = jQuery.type( obj );\n\t\treturn ( type === \"number\" || type === \"string\" ) &&\n\n\t\t\t// parseFloat NaNs numeric-cast false positives (\"\")\n\t\t\t// ...but misinterprets leading-number strings, particularly hex literals (\"0x...\")\n\t\t\t// subtraction forces infinities to NaN\n\t\t\t!isNaN( obj - parseFloat( obj ) );\n\t},\n\n\tisPlainObject: function( obj ) {\n\t\tvar proto, Ctor;\n\n\t\t// Detect obvious negatives\n\t\t// Use toString instead of jQuery.type to catch host objects\n\t\tif ( !obj || toString.call( obj ) !== \"[object Object]\" ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tproto = getProto( obj );\n\n\t\t// Objects with no prototype (e.g., `Object.create( null )`) are plain\n\t\tif ( !proto ) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// Objects with prototype are plain iff they were constructed by a global Object function\n\t\tCtor = hasOwn.call( proto, \"constructor\" ) && proto.constructor;\n\t\treturn typeof Ctor === \"function\" && fnToString.call( Ctor ) === ObjectFunctionString;\n\t},\n\n\tisEmptyObject: function( obj ) {\n\n\t\t/* eslint-disable no-unused-vars */\n\t\t// See https://github.com/eslint/eslint/issues/6125\n\t\tvar name;\n\n\t\tfor ( name in obj ) {\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t},\n\n\ttype: function( obj ) {\n\t\tif ( obj == null ) {\n\t\t\treturn obj + \"\";\n\t\t}\n\n\t\t// Support: Android <=2.3 only (functionish RegExp)\n\t\treturn typeof obj === \"object\" || typeof obj === \"function\" ?\n\t\t\tclass2type[ toString.call( obj ) ] || \"object\" :\n\t\t\ttypeof obj;\n\t},\n\n\t// Evaluates a script in a global context\n\tglobalEval: function( code ) {\n\t\tDOMEval( code );\n\t},\n\n\t// Convert dashed to camelCase; used by the css and data modules\n\t// Support: IE <=9 - 11, Edge 12 - 13\n\t// Microsoft forgot to hump their vendor prefix (#9572)\n\tcamelCase: function( string ) {\n\t\treturn string.replace( rmsPrefix, \"ms-\" ).replace( rdashAlpha, fcamelCase );\n\t},\n\n\teach: function( obj, callback ) {\n\t\tvar length, i = 0;\n\n\t\tif ( isArrayLike( obj ) ) {\n\t\t\tlength = obj.length;\n\t\t\tfor ( ; i < length; i++ ) {\n\t\t\t\tif ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tfor ( i in obj ) {\n\t\t\t\tif ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn obj;\n\t},\n\n\t// Support: Android <=4.0 only\n\ttrim: function( text ) {\n\t\treturn text == null ?\n\t\t\t\"\" :\n\t\t\t( text + \"\" ).replace( rtrim, \"\" );\n\t},\n\n\t// results is for internal usage only\n\tmakeArray: function( arr, results ) {\n\t\tvar ret = results || [];\n\n\t\tif ( arr != null ) {\n\t\t\tif ( isArrayLike( Object( arr ) ) ) {\n\t\t\t\tjQuery.merge( ret,\n\t\t\t\t\ttypeof arr === \"string\" ?\n\t\t\t\t\t[ arr ] : arr\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tpush.call( ret, arr );\n\t\t\t}\n\t\t}\n\n\t\treturn ret;\n\t},\n\n\tinArray: function( elem, arr, i ) {\n\t\treturn arr == null ? -1 : indexOf.call( arr, elem, i );\n\t},\n\n\t// Support: Android <=4.0 only, PhantomJS 1 only\n\t// push.apply(_, arraylike) throws on ancient WebKit\n\tmerge: function( first, second ) {\n\t\tvar len = +second.length,\n\t\t\tj = 0,\n\t\t\ti = first.length;\n\n\t\tfor ( ; j < len; j++ ) {\n\t\t\tfirst[ i++ ] = second[ j ];\n\t\t}\n\n\t\tfirst.length = i;\n\n\t\treturn first;\n\t},\n\n\tgrep: function( elems, callback, invert ) {\n\t\tvar callbackInverse,\n\t\t\tmatches = [],\n\t\t\ti = 0,\n\t\t\tlength = elems.length,\n\t\t\tcallbackExpect = !invert;\n\n\t\t// Go through the array, only saving the items\n\t\t// that pass the validator function\n\t\tfor ( ; i < length; i++ ) {\n\t\t\tcallbackInverse = !callback( elems[ i ], i );\n\t\t\tif ( callbackInverse !== callbackExpect ) {\n\t\t\t\tmatches.push( elems[ i ] );\n\t\t\t}\n\t\t}\n\n\t\treturn matches;\n\t},\n\n\t// arg is for internal usage only\n\tmap: function( elems, callback, arg ) {\n\t\tvar length, value,\n\t\t\ti = 0,\n\t\t\tret = [];\n\n\t\t// Go through the array, translating each of the items to their new values\n\t\tif ( isArrayLike( elems ) ) {\n\t\t\tlength = elems.length;\n\t\t\tfor ( ; i < length; i++ ) {\n\t\t\t\tvalue = callback( elems[ i ], i, arg );\n\n\t\t\t\tif ( value != null ) {\n\t\t\t\t\tret.push( value );\n\t\t\t\t}\n\t\t\t}\n\n\t\t// Go through every key on the object,\n\t\t} else {\n\t\t\tfor ( i in elems ) {\n\t\t\t\tvalue = callback( elems[ i ], i, arg );\n\n\t\t\t\tif ( value != null ) {\n\t\t\t\t\tret.push( value );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Flatten any nested arrays\n\t\treturn concat.apply( [], ret );\n\t},\n\n\t// A global GUID counter for objects\n\tguid: 1,\n\n\t// Bind a function to a context, optionally partially applying any\n\t// arguments.\n\tproxy: function( fn, context ) {\n\t\tvar tmp, args, proxy;\n\n\t\tif ( typeof context === \"string\" ) {\n\t\t\ttmp = fn[ context ];\n\t\t\tcontext = fn;\n\t\t\tfn = tmp;\n\t\t}\n\n\t\t// Quick check to determine if target is callable, in the spec\n\t\t// this throws a TypeError, but we will just return undefined.\n\t\tif ( !jQuery.isFunction( fn ) ) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\t// Simulated bind\n\t\targs = slice.call( arguments, 2 );\n\t\tproxy = function() {\n\t\t\treturn fn.apply( context || this, args.concat( slice.call( arguments ) ) );\n\t\t};\n\n\t\t// Set the guid of unique handler to the same of original handler, so it can be removed\n\t\tproxy.guid = fn.guid = fn.guid || jQuery.guid++;\n\n\t\treturn proxy;\n\t},\n\n\tnow: Date.now,\n\n\t// jQuery.support is not used in Core but other projects attach their\n\t// properties to it so it needs to exist.\n\tsupport: support\n} );\n\nif ( typeof Symbol === \"function\" ) {\n\tjQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ];\n}\n\n// Populate the class2type map\njQuery.each( \"Boolean Number String Function Array Date RegExp Object Error Symbol\".split( \" \" ),\nfunction( i, name ) {\n\tclass2type[ \"[object \" + name + \"]\" ] = name.toLowerCase();\n} );\n\nfunction isArrayLike( obj ) {\n\n\t// Support: real iOS 8.2 only (not reproducible in simulator)\n\t// `in` check used to prevent JIT error (gh-2145)\n\t// hasOwn isn't used here due to false negatives\n\t// regarding Nodelist length in IE\n\tvar length = !!obj && \"length\" in obj && obj.length,\n\t\ttype = jQuery.type( obj );\n\n\tif ( type === \"function\" || jQuery.isWindow( obj ) ) {\n\t\treturn false;\n\t}\n\n\treturn type === \"array\" || length === 0 ||\n\t\ttypeof length === \"number\" && length > 0 && ( length - 1 ) in obj;\n}\nvar Sizzle =\n/*!\n * Sizzle CSS Selector Engine v2.3.3\n * https://sizzlejs.com/\n *\n * Copyright jQuery Foundation and other contributors\n * Released under the MIT license\n * http://jquery.org/license\n *\n * Date: 2016-08-08\n */\n(function( window ) {\n\nvar i,\n\tsupport,\n\tExpr,\n\tgetText,\n\tisXML,\n\ttokenize,\n\tcompile,\n\tselect,\n\toutermostContext,\n\tsortInput,\n\thasDuplicate,\n\n\t// Local document vars\n\tsetDocument,\n\tdocument,\n\tdocElem,\n\tdocumentIsHTML,\n\trbuggyQSA,\n\trbuggyMatches,\n\tmatches,\n\tcontains,\n\n\t// Instance-specific data\n\texpando = \"sizzle\" + 1 * new Date(),\n\tpreferredDoc = window.document,\n\tdirruns = 0,\n\tdone = 0,\n\tclassCache = createCache(),\n\ttokenCache = createCache(),\n\tcompilerCache = createCache(),\n\tsortOrder = function( a, b ) {\n\t\tif ( a === b ) {\n\t\t\thasDuplicate = true;\n\t\t}\n\t\treturn 0;\n\t},\n\n\t// Instance methods\n\thasOwn = ({}).hasOwnProperty,\n\tarr = [],\n\tpop = arr.pop,\n\tpush_native = arr.push,\n\tpush = arr.push,\n\tslice = arr.slice,\n\t// Use a stripped-down indexOf as it's faster than native\n\t// https://jsperf.com/thor-indexof-vs-for/5\n\tindexOf = function( list, elem ) {\n\t\tvar i = 0,\n\t\t\tlen = list.length;\n\t\tfor ( ; i < len; i++ ) {\n\t\t\tif ( list[i] === elem ) {\n\t\t\t\treturn i;\n\t\t\t}\n\t\t}\n\t\treturn -1;\n\t},\n\n\tbooleans = \"checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped\",\n\n\t// Regular expressions\n\n\t// http://www.w3.org/TR/css3-selectors/#whitespace\n\twhitespace = \"[\\\\x20\\\\t\\\\r\\\\n\\\\f]\",\n\n\t// http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier\n\tidentifier = \"(?:\\\\\\\\.|[\\\\w-]|[^\\0-\\\\xa0])+\",\n\n\t// Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors\n\tattributes = \"\\\\[\" + whitespace + \"*(\" + identifier + \")(?:\" + whitespace +\n\t\t// Operator (capture 2)\n\t\t\"*([*^$|!~]?=)\" + whitespace +\n\t\t// \"Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]\"\n\t\t\"*(?:'((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\"|(\" + identifier + \"))|)\" + whitespace +\n\t\t\"*\\\\]\",\n\n\tpseudos = \":(\" + identifier + \")(?:\\\\((\" +\n\t\t// To reduce the number of selectors needing tokenize in the preFilter, prefer arguments:\n\t\t// 1. quoted (capture 3; capture 4 or capture 5)\n\t\t\"('((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\")|\" +\n\t\t// 2. simple (capture 6)\n\t\t\"((?:\\\\\\\\.|[^\\\\\\\\()[\\\\]]|\" + attributes + \")*)|\" +\n\t\t// 3. anything else (capture 2)\n\t\t\".*\" +\n\t\t\")\\\\)|)\",\n\n\t// Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter\n\trwhitespace = new RegExp( whitespace + \"+\", \"g\" ),\n\trtrim = new RegExp( \"^\" + whitespace + \"+|((?:^|[^\\\\\\\\])(?:\\\\\\\\.)*)\" + whitespace + \"+$\", \"g\" ),\n\n\trcomma = new RegExp( \"^\" + whitespace + \"*,\" + whitespace + \"*\" ),\n\trcombinators = new RegExp( \"^\" + whitespace + \"*([>+~]|\" + whitespace + \")\" + whitespace + \"*\" ),\n\n\trattributeQuotes = new RegExp( \"=\" + whitespace + \"*([^\\\\]'\\\"]*?)\" + whitespace + \"*\\\\]\", \"g\" ),\n\n\trpseudo = new RegExp( pseudos ),\n\tridentifier = new RegExp( \"^\" + identifier + \"$\" ),\n\n\tmatchExpr = {\n\t\t\"ID\": new RegExp( \"^#(\" + identifier + \")\" ),\n\t\t\"CLASS\": new RegExp( \"^\\\\.(\" + identifier + \")\" ),\n\t\t\"TAG\": new RegExp( \"^(\" + identifier + \"|[*])\" ),\n\t\t\"ATTR\": new RegExp( \"^\" + attributes ),\n\t\t\"PSEUDO\": new RegExp( \"^\" + pseudos ),\n\t\t\"CHILD\": new RegExp( \"^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\\\(\" + whitespace +\n\t\t\t\"*(even|odd|(([+-]|)(\\\\d*)n|)\" + whitespace + \"*(?:([+-]|)\" + whitespace +\n\t\t\t\"*(\\\\d+)|))\" + whitespace + \"*\\\\)|)\", \"i\" ),\n\t\t\"bool\": new RegExp( \"^(?:\" + booleans + \")$\", \"i\" ),\n\t\t// For use in libraries implementing .is()\n\t\t// We use this for POS matching in `select`\n\t\t\"needsContext\": new RegExp( \"^\" + whitespace + \"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\\\(\" +\n\t\t\twhitespace + \"*((?:-\\\\d)?\\\\d*)\" + whitespace + \"*\\\\)|)(?=[^-]|$)\", \"i\" )\n\t},\n\n\trinputs = /^(?:input|select|textarea|button)$/i,\n\trheader = /^h\\d$/i,\n\n\trnative = /^[^{]+\\{\\s*\\[native \\w/,\n\n\t// Easily-parseable/retrievable ID or TAG or CLASS selectors\n\trquickExpr = /^(?:#([\\w-]+)|(\\w+)|\\.([\\w-]+))$/,\n\n\trsibling = /[+~]/,\n\n\t// CSS escapes\n\t// http://www.w3.org/TR/CSS21/syndata.html#escaped-characters\n\trunescape = new RegExp( \"\\\\\\\\([\\\\da-f]{1,6}\" + whitespace + \"?|(\" + whitespace + \")|.)\", \"ig\" ),\n\tfunescape = function( _, escaped, escapedWhitespace ) {\n\t\tvar high = \"0x\" + escaped - 0x10000;\n\t\t// NaN means non-codepoint\n\t\t// Support: Firefox<24\n\t\t// Workaround erroneous numeric interpretation of +\"0x\"\n\t\treturn high !== high || escapedWhitespace ?\n\t\t\tescaped :\n\t\t\thigh < 0 ?\n\t\t\t\t// BMP codepoint\n\t\t\t\tString.fromCharCode( high + 0x10000 ) :\n\t\t\t\t// Supplemental Plane codepoint (surrogate pair)\n\t\t\t\tString.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );\n\t},\n\n\t// CSS string/identifier serialization\n\t// https://drafts.csswg.org/cssom/#common-serializing-idioms\n\trcssescape = /([\\0-\\x1f\\x7f]|^-?\\d)|^-$|[^\\0-\\x1f\\x7f-\\uFFFF\\w-]/g,\n\tfcssescape = function( ch, asCodePoint ) {\n\t\tif ( asCodePoint ) {\n\n\t\t\t// U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER\n\t\t\tif ( ch === \"\\0\" ) {\n\t\t\t\treturn \"\\uFFFD\";\n\t\t\t}\n\n\t\t\t// Control characters and (dependent upon position) numbers get escaped as code points\n\t\t\treturn ch.slice( 0, -1 ) + \"\\\\\" + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + \" \";\n\t\t}\n\n\t\t// Other potentially-special ASCII characters get backslash-escaped\n\t\treturn \"\\\\\" + ch;\n\t},\n\n\t// Used for iframes\n\t// See setDocument()\n\t// Removing the function wrapper causes a \"Permission Denied\"\n\t// error in IE\n\tunloadHandler = function() {\n\t\tsetDocument();\n\t},\n\n\tdisabledAncestor = addCombinator(\n\t\tfunction( elem ) {\n\t\t\treturn elem.disabled === true && (\"form\" in elem || \"label\" in elem);\n\t\t},\n\t\t{ dir: \"parentNode\", next: \"legend\" }\n\t);\n\n// Optimize for push.apply( _, NodeList )\ntry {\n\tpush.apply(\n\t\t(arr = slice.call( preferredDoc.childNodes )),\n\t\tpreferredDoc.childNodes\n\t);\n\t// Support: Android<4.0\n\t// Detect silently failing push.apply\n\tarr[ preferredDoc.childNodes.length ].nodeType;\n} catch ( e ) {\n\tpush = { apply: arr.length ?\n\n\t\t// Leverage slice if possible\n\t\tfunction( target, els ) {\n\t\t\tpush_native.apply( target, slice.call(els) );\n\t\t} :\n\n\t\t// Support: IE<9\n\t\t// Otherwise append directly\n\t\tfunction( target, els ) {\n\t\t\tvar j = target.length,\n\t\t\t\ti = 0;\n\t\t\t// Can't trust NodeList.length\n\t\t\twhile ( (target[j++] = els[i++]) ) {}\n\t\t\ttarget.length = j - 1;\n\t\t}\n\t};\n}\n\nfunction Sizzle( selector, context, results, seed ) {\n\tvar m, i, elem, nid, match, groups, newSelector,\n\t\tnewContext = context && context.ownerDocument,\n\n\t\t// nodeType defaults to 9, since context defaults to document\n\t\tnodeType = context ? context.nodeType : 9;\n\n\tresults = results || [];\n\n\t// Return early from calls with invalid selector or context\n\tif ( typeof selector !== \"string\" || !selector ||\n\t\tnodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) {\n\n\t\treturn results;\n\t}\n\n\t// Try to shortcut find operations (as opposed to filters) in HTML documents\n\tif ( !seed ) {\n\n\t\tif ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {\n\t\t\tsetDocument( context );\n\t\t}\n\t\tcontext = context || document;\n\n\t\tif ( documentIsHTML ) {\n\n\t\t\t// If the selector is sufficiently simple, try using a \"get*By*\" DOM method\n\t\t\t// (excepting DocumentFragment context, where the methods don't exist)\n\t\t\tif ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) {\n\n\t\t\t\t// ID selector\n\t\t\t\tif ( (m = match[1]) ) {\n\n\t\t\t\t\t// Document context\n\t\t\t\t\tif ( nodeType === 9 ) {\n\t\t\t\t\t\tif ( (elem = context.getElementById( m )) ) {\n\n\t\t\t\t\t\t\t// Support: IE, Opera, Webkit\n\t\t\t\t\t\t\t// TODO: identify versions\n\t\t\t\t\t\t\t// getElementById can match elements by name instead of ID\n\t\t\t\t\t\t\tif ( elem.id === m ) {\n\t\t\t\t\t\t\t\tresults.push( elem );\n\t\t\t\t\t\t\t\treturn results;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\treturn results;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t// Element context\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\t// Support: IE, Opera, Webkit\n\t\t\t\t\t\t// TODO: identify versions\n\t\t\t\t\t\t// getElementById can match elements by name instead of ID\n\t\t\t\t\t\tif ( newContext && (elem = newContext.getElementById( m )) &&\n\t\t\t\t\t\t\tcontains( context, elem ) &&\n\t\t\t\t\t\t\telem.id === m ) {\n\n\t\t\t\t\t\t\tresults.push( elem );\n\t\t\t\t\t\t\treturn results;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t// Type selector\n\t\t\t\t} else if ( match[2] ) {\n\t\t\t\t\tpush.apply( results, context.getElementsByTagName( selector ) );\n\t\t\t\t\treturn results;\n\n\t\t\t\t// Class selector\n\t\t\t\t} else if ( (m = match[3]) && support.getElementsByClassName &&\n\t\t\t\t\tcontext.getElementsByClassName ) {\n\n\t\t\t\t\tpush.apply( results, context.getElementsByClassName( m ) );\n\t\t\t\t\treturn results;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Take advantage of querySelectorAll\n\t\t\tif ( support.qsa &&\n\t\t\t\t!compilerCache[ selector + \" \" ] &&\n\t\t\t\t(!rbuggyQSA || !rbuggyQSA.test( selector )) ) {\n\n\t\t\t\tif ( nodeType !== 1 ) {\n\t\t\t\t\tnewContext = context;\n\t\t\t\t\tnewSelector = selector;\n\n\t\t\t\t// qSA looks outside Element context, which is not what we want\n\t\t\t\t// Thanks to Andrew Dupont for this workaround technique\n\t\t\t\t// Support: IE <=8\n\t\t\t\t// Exclude object elements\n\t\t\t\t} else if ( context.nodeName.toLowerCase() !== \"object\" ) {\n\n\t\t\t\t\t// Capture the context ID, setting it first if necessary\n\t\t\t\t\tif ( (nid = context.getAttribute( \"id\" )) ) {\n\t\t\t\t\t\tnid = nid.replace( rcssescape, fcssescape );\n\t\t\t\t\t} else {\n\t\t\t\t\t\tcontext.setAttribute( \"id\", (nid = expando) );\n\t\t\t\t\t}\n\n\t\t\t\t\t// Prefix every selector in the list\n\t\t\t\t\tgroups = tokenize( selector );\n\t\t\t\t\ti = groups.length;\n\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\tgroups[i] = \"#\" + nid + \" \" + toSelector( groups[i] );\n\t\t\t\t\t}\n\t\t\t\t\tnewSelector = groups.join( \",\" );\n\n\t\t\t\t\t// Expand context for sibling selectors\n\t\t\t\t\tnewContext = rsibling.test( selector ) && testContext( context.parentNode ) ||\n\t\t\t\t\t\tcontext;\n\t\t\t\t}\n\n\t\t\t\tif ( newSelector ) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tpush.apply( results,\n\t\t\t\t\t\t\tnewContext.querySelectorAll( newSelector )\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn results;\n\t\t\t\t\t} catch ( qsaError ) {\n\t\t\t\t\t} finally {\n\t\t\t\t\t\tif ( nid === expando ) {\n\t\t\t\t\t\t\tcontext.removeAttribute( \"id\" );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// All others\n\treturn select( selector.replace( rtrim, \"$1\" ), context, results, seed );\n}\n\n/**\n * Create key-value caches of limited size\n * @returns {function(string, object)} Returns the Object data after storing it on itself with\n *\tproperty name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)\n *\tdeleting the oldest entry\n */\nfunction createCache() {\n\tvar keys = [];\n\n\tfunction cache( key, value ) {\n\t\t// Use (key + \" \") to avoid collision with native prototype properties (see Issue #157)\n\t\tif ( keys.push( key + \" \" ) > Expr.cacheLength ) {\n\t\t\t// Only keep the most recent entries\n\t\t\tdelete cache[ keys.shift() ];\n\t\t}\n\t\treturn (cache[ key + \" \" ] = value);\n\t}\n\treturn cache;\n}\n\n/**\n * Mark a function for special use by Sizzle\n * @param {Function} fn The function to mark\n */\nfunction markFunction( fn ) {\n\tfn[ expando ] = true;\n\treturn fn;\n}\n\n/**\n * Support testing using an element\n * @param {Function} fn Passed the created element and returns a boolean result\n */\nfunction assert( fn ) {\n\tvar el = document.createElement(\"fieldset\");\n\n\ttry {\n\t\treturn !!fn( el );\n\t} catch (e) {\n\t\treturn false;\n\t} finally {\n\t\t// Remove from its parent by default\n\t\tif ( el.parentNode ) {\n\t\t\tel.parentNode.removeChild( el );\n\t\t}\n\t\t// release memory in IE\n\t\tel = null;\n\t}\n}\n\n/**\n * Adds the same handler for all of the specified attrs\n * @param {String} attrs Pipe-separated list of attributes\n * @param {Function} handler The method that will be applied\n */\nfunction addHandle( attrs, handler ) {\n\tvar arr = attrs.split(\"|\"),\n\t\ti = arr.length;\n\n\twhile ( i-- ) {\n\t\tExpr.attrHandle[ arr[i] ] = handler;\n\t}\n}\n\n/**\n * Checks document order of two siblings\n * @param {Element} a\n * @param {Element} b\n * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b\n */\nfunction siblingCheck( a, b ) {\n\tvar cur = b && a,\n\t\tdiff = cur && a.nodeType === 1 && b.nodeType === 1 &&\n\t\t\ta.sourceIndex - b.sourceIndex;\n\n\t// Use IE sourceIndex if available on both nodes\n\tif ( diff ) {\n\t\treturn diff;\n\t}\n\n\t// Check if b follows a\n\tif ( cur ) {\n\t\twhile ( (cur = cur.nextSibling) ) {\n\t\t\tif ( cur === b ) {\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn a ? 1 : -1;\n}\n\n/**\n * Returns a function to use in pseudos for input types\n * @param {String} type\n */\nfunction createInputPseudo( type ) {\n\treturn function( elem ) {\n\t\tvar name = elem.nodeName.toLowerCase();\n\t\treturn name === \"input\" && elem.type === type;\n\t};\n}\n\n/**\n * Returns a function to use in pseudos for buttons\n * @param {String} type\n */\nfunction createButtonPseudo( type ) {\n\treturn function( elem ) {\n\t\tvar name = elem.nodeName.toLowerCase();\n\t\treturn (name === \"input\" || name === \"button\") && elem.type === type;\n\t};\n}\n\n/**\n * Returns a function to use in pseudos for :enabled/:disabled\n * @param {Boolean} disabled true for :disabled; false for :enabled\n */\nfunction createDisabledPseudo( disabled ) {\n\n\t// Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable\n\treturn function( elem ) {\n\n\t\t// Only certain elements can match :enabled or :disabled\n\t\t// https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled\n\t\t// https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled\n\t\tif ( \"form\" in elem ) {\n\n\t\t\t// Check for inherited disabledness on relevant non-disabled elements:\n\t\t\t// * listed form-associated elements in a disabled fieldset\n\t\t\t//   https://html.spec.whatwg.org/multipage/forms.html#category-listed\n\t\t\t//   https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled\n\t\t\t// * option elements in a disabled optgroup\n\t\t\t//   https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled\n\t\t\t// All such elements have a \"form\" property.\n\t\t\tif ( elem.parentNode && elem.disabled === false ) {\n\n\t\t\t\t// Option elements defer to a parent optgroup if present\n\t\t\t\tif ( \"label\" in elem ) {\n\t\t\t\t\tif ( \"label\" in elem.parentNode ) {\n\t\t\t\t\t\treturn elem.parentNode.disabled === disabled;\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn elem.disabled === disabled;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Support: IE 6 - 11\n\t\t\t\t// Use the isDisabled shortcut property to check for disabled fieldset ancestors\n\t\t\t\treturn elem.isDisabled === disabled ||\n\n\t\t\t\t\t// Where there is no isDisabled, check manually\n\t\t\t\t\t/* jshint -W018 */\n\t\t\t\t\telem.isDisabled !== !disabled &&\n\t\t\t\t\t\tdisabledAncestor( elem ) === disabled;\n\t\t\t}\n\n\t\t\treturn elem.disabled === disabled;\n\n\t\t// Try to winnow out elements that can't be disabled before trusting the disabled property.\n\t\t// Some victims get caught in our net (label, legend, menu, track), but it shouldn't\n\t\t// even exist on them, let alone have a boolean value.\n\t\t} else if ( \"label\" in elem ) {\n\t\t\treturn elem.disabled === disabled;\n\t\t}\n\n\t\t// Remaining elements are neither :enabled nor :disabled\n\t\treturn false;\n\t};\n}\n\n/**\n * Returns a function to use in pseudos for positionals\n * @param {Function} fn\n */\nfunction createPositionalPseudo( fn ) {\n\treturn markFunction(function( argument ) {\n\t\targument = +argument;\n\t\treturn markFunction(function( seed, matches ) {\n\t\t\tvar j,\n\t\t\t\tmatchIndexes = fn( [], seed.length, argument ),\n\t\t\t\ti = matchIndexes.length;\n\n\t\t\t// Match elements found at the specified indexes\n\t\t\twhile ( i-- ) {\n\t\t\t\tif ( seed[ (j = matchIndexes[i]) ] ) {\n\t\t\t\t\tseed[j] = !(matches[j] = seed[j]);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t});\n}\n\n/**\n * Checks a node for validity as a Sizzle context\n * @param {Element|Object=} context\n * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value\n */\nfunction testContext( context ) {\n\treturn context && typeof context.getElementsByTagName !== \"undefined\" && context;\n}\n\n// Expose support vars for convenience\nsupport = Sizzle.support = {};\n\n/**\n * Detects XML nodes\n * @param {Element|Object} elem An element or a document\n * @returns {Boolean} True iff elem is a non-HTML XML node\n */\nisXML = Sizzle.isXML = function( elem ) {\n\t// documentElement is verified for cases where it doesn't yet exist\n\t// (such as loading iframes in IE - #4833)\n\tvar documentElement = elem && (elem.ownerDocument || elem).documentElement;\n\treturn documentElement ? documentElement.nodeName !== \"HTML\" : false;\n};\n\n/**\n * Sets document-related variables once based on the current document\n * @param {Element|Object} [doc] An element or document object to use to set the document\n * @returns {Object} Returns the current document\n */\nsetDocument = Sizzle.setDocument = function( node ) {\n\tvar hasCompare, subWindow,\n\t\tdoc = node ? node.ownerDocument || node : preferredDoc;\n\n\t// Return early if doc is invalid or already selected\n\tif ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {\n\t\treturn document;\n\t}\n\n\t// Update global variables\n\tdocument = doc;\n\tdocElem = document.documentElement;\n\tdocumentIsHTML = !isXML( document );\n\n\t// Support: IE 9-11, Edge\n\t// Accessing iframe documents after unload throws \"permission denied\" errors (jQuery #13936)\n\tif ( preferredDoc !== document &&\n\t\t(subWindow = document.defaultView) && subWindow.top !== subWindow ) {\n\n\t\t// Support: IE 11, Edge\n\t\tif ( subWindow.addEventListener ) {\n\t\t\tsubWindow.addEventListener( \"unload\", unloadHandler, false );\n\n\t\t// Support: IE 9 - 10 only\n\t\t} else if ( subWindow.attachEvent ) {\n\t\t\tsubWindow.attachEvent( \"onunload\", unloadHandler );\n\t\t}\n\t}\n\n\t/* Attributes\n\t---------------------------------------------------------------------- */\n\n\t// Support: IE<8\n\t// Verify that getAttribute really returns attributes and not properties\n\t// (excepting IE8 booleans)\n\tsupport.attributes = assert(function( el ) {\n\t\tel.className = \"i\";\n\t\treturn !el.getAttribute(\"className\");\n\t});\n\n\t/* getElement(s)By*\n\t---------------------------------------------------------------------- */\n\n\t// Check if getElementsByTagName(\"*\") returns only elements\n\tsupport.getElementsByTagName = assert(function( el ) {\n\t\tel.appendChild( document.createComment(\"\") );\n\t\treturn !el.getElementsByTagName(\"*\").length;\n\t});\n\n\t// Support: IE<9\n\tsupport.getElementsByClassName = rnative.test( document.getElementsByClassName );\n\n\t// Support: IE<10\n\t// Check if getElementById returns elements by name\n\t// The broken getElementById methods don't pick up programmatically-set names,\n\t// so use a roundabout getElementsByName test\n\tsupport.getById = assert(function( el ) {\n\t\tdocElem.appendChild( el ).id = expando;\n\t\treturn !document.getElementsByName || !document.getElementsByName( expando ).length;\n\t});\n\n\t// ID filter and find\n\tif ( support.getById ) {\n\t\tExpr.filter[\"ID\"] = function( id ) {\n\t\t\tvar attrId = id.replace( runescape, funescape );\n\t\t\treturn function( elem ) {\n\t\t\t\treturn elem.getAttribute(\"id\") === attrId;\n\t\t\t};\n\t\t};\n\t\tExpr.find[\"ID\"] = function( id, context ) {\n\t\t\tif ( typeof context.getElementById !== \"undefined\" && documentIsHTML ) {\n\t\t\t\tvar elem = context.getElementById( id );\n\t\t\t\treturn elem ? [ elem ] : [];\n\t\t\t}\n\t\t};\n\t} else {\n\t\tExpr.filter[\"ID\"] =  function( id ) {\n\t\t\tvar attrId = id.replace( runescape, funescape );\n\t\t\treturn function( elem ) {\n\t\t\t\tvar node = typeof elem.getAttributeNode !== \"undefined\" &&\n\t\t\t\t\telem.getAttributeNode(\"id\");\n\t\t\t\treturn node && node.value === attrId;\n\t\t\t};\n\t\t};\n\n\t\t// Support: IE 6 - 7 only\n\t\t// getElementById is not reliable as a find shortcut\n\t\tExpr.find[\"ID\"] = function( id, context ) {\n\t\t\tif ( typeof context.getElementById !== \"undefined\" && documentIsHTML ) {\n\t\t\t\tvar node, i, elems,\n\t\t\t\t\telem = context.getElementById( id );\n\n\t\t\t\tif ( elem ) {\n\n\t\t\t\t\t// Verify the id attribute\n\t\t\t\t\tnode = elem.getAttributeNode(\"id\");\n\t\t\t\t\tif ( node && node.value === id ) {\n\t\t\t\t\t\treturn [ elem ];\n\t\t\t\t\t}\n\n\t\t\t\t\t// Fall back on getElementsByName\n\t\t\t\t\telems = context.getElementsByName( id );\n\t\t\t\t\ti = 0;\n\t\t\t\t\twhile ( (elem = elems[i++]) ) {\n\t\t\t\t\t\tnode = elem.getAttributeNode(\"id\");\n\t\t\t\t\t\tif ( node && node.value === id ) {\n\t\t\t\t\t\t\treturn [ elem ];\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn [];\n\t\t\t}\n\t\t};\n\t}\n\n\t// Tag\n\tExpr.find[\"TAG\"] = support.getElementsByTagName ?\n\t\tfunction( tag, context ) {\n\t\t\tif ( typeof context.getElementsByTagName !== \"undefined\" ) {\n\t\t\t\treturn context.getElementsByTagName( tag );\n\n\t\t\t// DocumentFragment nodes don't have gEBTN\n\t\t\t} else if ( support.qsa ) {\n\t\t\t\treturn context.querySelectorAll( tag );\n\t\t\t}\n\t\t} :\n\n\t\tfunction( tag, context ) {\n\t\t\tvar elem,\n\t\t\t\ttmp = [],\n\t\t\t\ti = 0,\n\t\t\t\t// By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too\n\t\t\t\tresults = context.getElementsByTagName( tag );\n\n\t\t\t// Filter out possible comments\n\t\t\tif ( tag === \"*\" ) {\n\t\t\t\twhile ( (elem = results[i++]) ) {\n\t\t\t\t\tif ( elem.nodeType === 1 ) {\n\t\t\t\t\t\ttmp.push( elem );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn tmp;\n\t\t\t}\n\t\t\treturn results;\n\t\t};\n\n\t// Class\n\tExpr.find[\"CLASS\"] = support.getElementsByClassName && function( className, context ) {\n\t\tif ( typeof context.getElementsByClassName !== \"undefined\" && documentIsHTML ) {\n\t\t\treturn context.getElementsByClassName( className );\n\t\t}\n\t};\n\n\t/* QSA/matchesSelector\n\t---------------------------------------------------------------------- */\n\n\t// QSA and matchesSelector support\n\n\t// matchesSelector(:active) reports false when true (IE9/Opera 11.5)\n\trbuggyMatches = [];\n\n\t// qSa(:focus) reports false when true (Chrome 21)\n\t// We allow this because of a bug in IE8/9 that throws an error\n\t// whenever `document.activeElement` is accessed on an iframe\n\t// So, we allow :focus to pass through QSA all the time to avoid the IE error\n\t// See https://bugs.jquery.com/ticket/13378\n\trbuggyQSA = [];\n\n\tif ( (support.qsa = rnative.test( document.querySelectorAll )) ) {\n\t\t// Build QSA regex\n\t\t// Regex strategy adopted from Diego Perini\n\t\tassert(function( el ) {\n\t\t\t// Select is set to empty string on purpose\n\t\t\t// This is to test IE's treatment of not explicitly\n\t\t\t// setting a boolean content attribute,\n\t\t\t// since its presence should be enough\n\t\t\t// https://bugs.jquery.com/ticket/12359\n\t\t\tdocElem.appendChild( el ).innerHTML = \"<a id='\" + expando + \"'></a>\" +\n\t\t\t\t\"<select id='\" + expando + \"-\\r\\\\' msallowcapture=''>\" +\n\t\t\t\t\"<option selected=''></option></select>\";\n\n\t\t\t// Support: IE8, Opera 11-12.16\n\t\t\t// Nothing should be selected when empty strings follow ^= or $= or *=\n\t\t\t// The test attribute must be unknown in Opera but \"safe\" for WinRT\n\t\t\t// https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section\n\t\t\tif ( el.querySelectorAll(\"[msallowcapture^='']\").length ) {\n\t\t\t\trbuggyQSA.push( \"[*^$]=\" + whitespace + \"*(?:''|\\\"\\\")\" );\n\t\t\t}\n\n\t\t\t// Support: IE8\n\t\t\t// Boolean attributes and \"value\" are not treated correctly\n\t\t\tif ( !el.querySelectorAll(\"[selected]\").length ) {\n\t\t\t\trbuggyQSA.push( \"\\\\[\" + whitespace + \"*(?:value|\" + booleans + \")\" );\n\t\t\t}\n\n\t\t\t// Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+\n\t\t\tif ( !el.querySelectorAll( \"[id~=\" + expando + \"-]\" ).length ) {\n\t\t\t\trbuggyQSA.push(\"~=\");\n\t\t\t}\n\n\t\t\t// Webkit/Opera - :checked should return selected option elements\n\t\t\t// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked\n\t\t\t// IE8 throws error here and will not see later tests\n\t\t\tif ( !el.querySelectorAll(\":checked\").length ) {\n\t\t\t\trbuggyQSA.push(\":checked\");\n\t\t\t}\n\n\t\t\t// Support: Safari 8+, iOS 8+\n\t\t\t// https://bugs.webkit.org/show_bug.cgi?id=136851\n\t\t\t// In-page `selector#id sibling-combinator selector` fails\n\t\t\tif ( !el.querySelectorAll( \"a#\" + expando + \"+*\" ).length ) {\n\t\t\t\trbuggyQSA.push(\".#.+[+~]\");\n\t\t\t}\n\t\t});\n\n\t\tassert(function( el ) {\n\t\t\tel.innerHTML = \"<a href='' disabled='disabled'></a>\" +\n\t\t\t\t\"<select disabled='disabled'><option/></select>\";\n\n\t\t\t// Support: Windows 8 Native Apps\n\t\t\t// The type and name attributes are restricted during .innerHTML assignment\n\t\t\tvar input = document.createElement(\"input\");\n\t\t\tinput.setAttribute( \"type\", \"hidden\" );\n\t\t\tel.appendChild( input ).setAttribute( \"name\", \"D\" );\n\n\t\t\t// Support: IE8\n\t\t\t// Enforce case-sensitivity of name attribute\n\t\t\tif ( el.querySelectorAll(\"[name=d]\").length ) {\n\t\t\t\trbuggyQSA.push( \"name\" + whitespace + \"*[*^$|!~]?=\" );\n\t\t\t}\n\n\t\t\t// FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)\n\t\t\t// IE8 throws error here and will not see later tests\n\t\t\tif ( el.querySelectorAll(\":enabled\").length !== 2 ) {\n\t\t\t\trbuggyQSA.push( \":enabled\", \":disabled\" );\n\t\t\t}\n\n\t\t\t// Support: IE9-11+\n\t\t\t// IE's :disabled selector does not pick up the children of disabled fieldsets\n\t\t\tdocElem.appendChild( el ).disabled = true;\n\t\t\tif ( el.querySelectorAll(\":disabled\").length !== 2 ) {\n\t\t\t\trbuggyQSA.push( \":enabled\", \":disabled\" );\n\t\t\t}\n\n\t\t\t// Opera 10-11 does not throw on post-comma invalid pseudos\n\t\t\tel.querySelectorAll(\"*,:x\");\n\t\t\trbuggyQSA.push(\",.*:\");\n\t\t});\n\t}\n\n\tif ( (support.matchesSelector = rnative.test( (matches = docElem.matches ||\n\t\tdocElem.webkitMatchesSelector ||\n\t\tdocElem.mozMatchesSelector ||\n\t\tdocElem.oMatchesSelector ||\n\t\tdocElem.msMatchesSelector) )) ) {\n\n\t\tassert(function( el ) {\n\t\t\t// Check to see if it's possible to do matchesSelector\n\t\t\t// on a disconnected node (IE 9)\n\t\t\tsupport.disconnectedMatch = matches.call( el, \"*\" );\n\n\t\t\t// This should fail with an exception\n\t\t\t// Gecko does not error, returns false instead\n\t\t\tmatches.call( el, \"[s!='']:x\" );\n\t\t\trbuggyMatches.push( \"!=\", pseudos );\n\t\t});\n\t}\n\n\trbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join(\"|\") );\n\trbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join(\"|\") );\n\n\t/* Contains\n\t---------------------------------------------------------------------- */\n\thasCompare = rnative.test( docElem.compareDocumentPosition );\n\n\t// Element contains another\n\t// Purposefully self-exclusive\n\t// As in, an element does not contain itself\n\tcontains = hasCompare || rnative.test( docElem.contains ) ?\n\t\tfunction( a, b ) {\n\t\t\tvar adown = a.nodeType === 9 ? a.documentElement : a,\n\t\t\t\tbup = b && b.parentNode;\n\t\t\treturn a === bup || !!( bup && bup.nodeType === 1 && (\n\t\t\t\tadown.contains ?\n\t\t\t\t\tadown.contains( bup ) :\n\t\t\t\t\ta.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16\n\t\t\t));\n\t\t} :\n\t\tfunction( a, b ) {\n\t\t\tif ( b ) {\n\t\t\t\twhile ( (b = b.parentNode) ) {\n\t\t\t\t\tif ( b === a ) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t};\n\n\t/* Sorting\n\t---------------------------------------------------------------------- */\n\n\t// Document order sorting\n\tsortOrder = hasCompare ?\n\tfunction( a, b ) {\n\n\t\t// Flag for duplicate removal\n\t\tif ( a === b ) {\n\t\t\thasDuplicate = true;\n\t\t\treturn 0;\n\t\t}\n\n\t\t// Sort on method existence if only one input has compareDocumentPosition\n\t\tvar compare = !a.compareDocumentPosition - !b.compareDocumentPosition;\n\t\tif ( compare ) {\n\t\t\treturn compare;\n\t\t}\n\n\t\t// Calculate position if both inputs belong to the same document\n\t\tcompare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ?\n\t\t\ta.compareDocumentPosition( b ) :\n\n\t\t\t// Otherwise we know they are disconnected\n\t\t\t1;\n\n\t\t// Disconnected nodes\n\t\tif ( compare & 1 ||\n\t\t\t(!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) {\n\n\t\t\t// Choose the first element that is related to our preferred document\n\t\t\tif ( a === document || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) {\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t\tif ( b === document || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) {\n\t\t\t\treturn 1;\n\t\t\t}\n\n\t\t\t// Maintain original order\n\t\t\treturn sortInput ?\n\t\t\t\t( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :\n\t\t\t\t0;\n\t\t}\n\n\t\treturn compare & 4 ? -1 : 1;\n\t} :\n\tfunction( a, b ) {\n\t\t// Exit early if the nodes are identical\n\t\tif ( a === b ) {\n\t\t\thasDuplicate = true;\n\t\t\treturn 0;\n\t\t}\n\n\t\tvar cur,\n\t\t\ti = 0,\n\t\t\taup = a.parentNode,\n\t\t\tbup = b.parentNode,\n\t\t\tap = [ a ],\n\t\t\tbp = [ b ];\n\n\t\t// Parentless nodes are either documents or disconnected\n\t\tif ( !aup || !bup ) {\n\t\t\treturn a === document ? -1 :\n\t\t\t\tb === document ? 1 :\n\t\t\t\taup ? -1 :\n\t\t\t\tbup ? 1 :\n\t\t\t\tsortInput ?\n\t\t\t\t( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :\n\t\t\t\t0;\n\n\t\t// If the nodes are siblings, we can do a quick check\n\t\t} else if ( aup === bup ) {\n\t\t\treturn siblingCheck( a, b );\n\t\t}\n\n\t\t// Otherwise we need full lists of their ancestors for comparison\n\t\tcur = a;\n\t\twhile ( (cur = cur.parentNode) ) {\n\t\t\tap.unshift( cur );\n\t\t}\n\t\tcur = b;\n\t\twhile ( (cur = cur.parentNode) ) {\n\t\t\tbp.unshift( cur );\n\t\t}\n\n\t\t// Walk down the tree looking for a discrepancy\n\t\twhile ( ap[i] === bp[i] ) {\n\t\t\ti++;\n\t\t}\n\n\t\treturn i ?\n\t\t\t// Do a sibling check if the nodes have a common ancestor\n\t\t\tsiblingCheck( ap[i], bp[i] ) :\n\n\t\t\t// Otherwise nodes in our document sort first\n\t\t\tap[i] === preferredDoc ? -1 :\n\t\t\tbp[i] === preferredDoc ? 1 :\n\t\t\t0;\n\t};\n\n\treturn document;\n};\n\nSizzle.matches = function( expr, elements ) {\n\treturn Sizzle( expr, null, null, elements );\n};\n\nSizzle.matchesSelector = function( elem, expr ) {\n\t// Set document vars if needed\n\tif ( ( elem.ownerDocument || elem ) !== document ) {\n\t\tsetDocument( elem );\n\t}\n\n\t// Make sure that attribute selectors are quoted\n\texpr = expr.replace( rattributeQuotes, \"='$1']\" );\n\n\tif ( support.matchesSelector && documentIsHTML &&\n\t\t!compilerCache[ expr + \" \" ] &&\n\t\t( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&\n\t\t( !rbuggyQSA     || !rbuggyQSA.test( expr ) ) ) {\n\n\t\ttry {\n\t\t\tvar ret = matches.call( elem, expr );\n\n\t\t\t// IE 9's matchesSelector returns false on disconnected nodes\n\t\t\tif ( ret || support.disconnectedMatch ||\n\t\t\t\t\t// As well, disconnected nodes are said to be in a document\n\t\t\t\t\t// fragment in IE 9\n\t\t\t\t\telem.document && elem.document.nodeType !== 11 ) {\n\t\t\t\treturn ret;\n\t\t\t}\n\t\t} catch (e) {}\n\t}\n\n\treturn Sizzle( expr, document, null, [ elem ] ).length > 0;\n};\n\nSizzle.contains = function( context, elem ) {\n\t// Set document vars if needed\n\tif ( ( context.ownerDocument || context ) !== document ) {\n\t\tsetDocument( context );\n\t}\n\treturn contains( context, elem );\n};\n\nSizzle.attr = function( elem, name ) {\n\t// Set document vars if needed\n\tif ( ( elem.ownerDocument || elem ) !== document ) {\n\t\tsetDocument( elem );\n\t}\n\n\tvar fn = Expr.attrHandle[ name.toLowerCase() ],\n\t\t// Don't get fooled by Object.prototype properties (jQuery #13807)\n\t\tval = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?\n\t\t\tfn( elem, name, !documentIsHTML ) :\n\t\t\tundefined;\n\n\treturn val !== undefined ?\n\t\tval :\n\t\tsupport.attributes || !documentIsHTML ?\n\t\t\telem.getAttribute( name ) :\n\t\t\t(val = elem.getAttributeNode(name)) && val.specified ?\n\t\t\t\tval.value :\n\t\t\t\tnull;\n};\n\nSizzle.escape = function( sel ) {\n\treturn (sel + \"\").replace( rcssescape, fcssescape );\n};\n\nSizzle.error = function( msg ) {\n\tthrow new Error( \"Syntax error, unrecognized expression: \" + msg );\n};\n\n/**\n * Document sorting and removing duplicates\n * @param {ArrayLike} results\n */\nSizzle.uniqueSort = function( results ) {\n\tvar elem,\n\t\tduplicates = [],\n\t\tj = 0,\n\t\ti = 0;\n\n\t// Unless we *know* we can detect duplicates, assume their presence\n\thasDuplicate = !support.detectDuplicates;\n\tsortInput = !support.sortStable && results.slice( 0 );\n\tresults.sort( sortOrder );\n\n\tif ( hasDuplicate ) {\n\t\twhile ( (elem = results[i++]) ) {\n\t\t\tif ( elem === results[ i ] ) {\n\t\t\t\tj = duplicates.push( i );\n\t\t\t}\n\t\t}\n\t\twhile ( j-- ) {\n\t\t\tresults.splice( duplicates[ j ], 1 );\n\t\t}\n\t}\n\n\t// Clear input after sorting to release objects\n\t// See https://github.com/jquery/sizzle/pull/225\n\tsortInput = null;\n\n\treturn results;\n};\n\n/**\n * Utility function for retrieving the text value of an array of DOM nodes\n * @param {Array|Element} elem\n */\ngetText = Sizzle.getText = function( elem ) {\n\tvar node,\n\t\tret = \"\",\n\t\ti = 0,\n\t\tnodeType = elem.nodeType;\n\n\tif ( !nodeType ) {\n\t\t// If no nodeType, this is expected to be an array\n\t\twhile ( (node = elem[i++]) ) {\n\t\t\t// Do not traverse comment nodes\n\t\t\tret += getText( node );\n\t\t}\n\t} else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {\n\t\t// Use textContent for elements\n\t\t// innerText usage removed for consistency of new lines (jQuery #11153)\n\t\tif ( typeof elem.textContent === \"string\" ) {\n\t\t\treturn elem.textContent;\n\t\t} else {\n\t\t\t// Traverse its children\n\t\t\tfor ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {\n\t\t\t\tret += getText( elem );\n\t\t\t}\n\t\t}\n\t} else if ( nodeType === 3 || nodeType === 4 ) {\n\t\treturn elem.nodeValue;\n\t}\n\t// Do not include comment or processing instruction nodes\n\n\treturn ret;\n};\n\nExpr = Sizzle.selectors = {\n\n\t// Can be adjusted by the user\n\tcacheLength: 50,\n\n\tcreatePseudo: markFunction,\n\n\tmatch: matchExpr,\n\n\tattrHandle: {},\n\n\tfind: {},\n\n\trelative: {\n\t\t\">\": { dir: \"parentNode\", first: true },\n\t\t\" \": { dir: \"parentNode\" },\n\t\t\"+\": { dir: \"previousSibling\", first: true },\n\t\t\"~\": { dir: \"previousSibling\" }\n\t},\n\n\tpreFilter: {\n\t\t\"ATTR\": function( match ) {\n\t\t\tmatch[1] = match[1].replace( runescape, funescape );\n\n\t\t\t// Move the given value to match[3] whether quoted or unquoted\n\t\t\tmatch[3] = ( match[3] || match[4] || match[5] || \"\" ).replace( runescape, funescape );\n\n\t\t\tif ( match[2] === \"~=\" ) {\n\t\t\t\tmatch[3] = \" \" + match[3] + \" \";\n\t\t\t}\n\n\t\t\treturn match.slice( 0, 4 );\n\t\t},\n\n\t\t\"CHILD\": function( match ) {\n\t\t\t/* matches from matchExpr[\"CHILD\"]\n\t\t\t\t1 type (only|nth|...)\n\t\t\t\t2 what (child|of-type)\n\t\t\t\t3 argument (even|odd|\\d*|\\d*n([+-]\\d+)?|...)\n\t\t\t\t4 xn-component of xn+y argument ([+-]?\\d*n|)\n\t\t\t\t5 sign of xn-component\n\t\t\t\t6 x of xn-component\n\t\t\t\t7 sign of y-component\n\t\t\t\t8 y of y-component\n\t\t\t*/\n\t\t\tmatch[1] = match[1].toLowerCase();\n\n\t\t\tif ( match[1].slice( 0, 3 ) === \"nth\" ) {\n\t\t\t\t// nth-* requires argument\n\t\t\t\tif ( !match[3] ) {\n\t\t\t\t\tSizzle.error( match[0] );\n\t\t\t\t}\n\n\t\t\t\t// numeric x and y parameters for Expr.filter.CHILD\n\t\t\t\t// remember that false/true cast respectively to 0/1\n\t\t\t\tmatch[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === \"even\" || match[3] === \"odd\" ) );\n\t\t\t\tmatch[5] = +( ( match[7] + match[8] ) || match[3] === \"odd\" );\n\n\t\t\t// other types prohibit arguments\n\t\t\t} else if ( match[3] ) {\n\t\t\t\tSizzle.error( match[0] );\n\t\t\t}\n\n\t\t\treturn match;\n\t\t},\n\n\t\t\"PSEUDO\": function( match ) {\n\t\t\tvar excess,\n\t\t\t\tunquoted = !match[6] && match[2];\n\n\t\t\tif ( matchExpr[\"CHILD\"].test( match[0] ) ) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\t// Accept quoted arguments as-is\n\t\t\tif ( match[3] ) {\n\t\t\t\tmatch[2] = match[4] || match[5] || \"\";\n\n\t\t\t// Strip excess characters from unquoted arguments\n\t\t\t} else if ( unquoted && rpseudo.test( unquoted ) &&\n\t\t\t\t// Get excess from tokenize (recursively)\n\t\t\t\t(excess = tokenize( unquoted, true )) &&\n\t\t\t\t// advance to the next closing parenthesis\n\t\t\t\t(excess = unquoted.indexOf( \")\", unquoted.length - excess ) - unquoted.length) ) {\n\n\t\t\t\t// excess is a negative index\n\t\t\t\tmatch[0] = match[0].slice( 0, excess );\n\t\t\t\tmatch[2] = unquoted.slice( 0, excess );\n\t\t\t}\n\n\t\t\t// Return only captures needed by the pseudo filter method (type and argument)\n\t\t\treturn match.slice( 0, 3 );\n\t\t}\n\t},\n\n\tfilter: {\n\n\t\t\"TAG\": function( nodeNameSelector ) {\n\t\t\tvar nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();\n\t\t\treturn nodeNameSelector === \"*\" ?\n\t\t\t\tfunction() { return true; } :\n\t\t\t\tfunction( elem ) {\n\t\t\t\t\treturn elem.nodeName && elem.nodeName.toLowerCase() === nodeName;\n\t\t\t\t};\n\t\t},\n\n\t\t\"CLASS\": function( className ) {\n\t\t\tvar pattern = classCache[ className + \" \" ];\n\n\t\t\treturn pattern ||\n\t\t\t\t(pattern = new RegExp( \"(^|\" + whitespace + \")\" + className + \"(\" + whitespace + \"|$)\" )) &&\n\t\t\t\tclassCache( className, function( elem ) {\n\t\t\t\t\treturn pattern.test( typeof elem.className === \"string\" && elem.className || typeof elem.getAttribute !== \"undefined\" && elem.getAttribute(\"class\") || \"\" );\n\t\t\t\t});\n\t\t},\n\n\t\t\"ATTR\": function( name, operator, check ) {\n\t\t\treturn function( elem ) {\n\t\t\t\tvar result = Sizzle.attr( elem, name );\n\n\t\t\t\tif ( result == null ) {\n\t\t\t\t\treturn operator === \"!=\";\n\t\t\t\t}\n\t\t\t\tif ( !operator ) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\tresult += \"\";\n\n\t\t\t\treturn operator === \"=\" ? result === check :\n\t\t\t\t\toperator === \"!=\" ? result !== check :\n\t\t\t\t\toperator === \"^=\" ? check && result.indexOf( check ) === 0 :\n\t\t\t\t\toperator === \"*=\" ? check && result.indexOf( check ) > -1 :\n\t\t\t\t\toperator === \"$=\" ? check && result.slice( -check.length ) === check :\n\t\t\t\t\toperator === \"~=\" ? ( \" \" + result.replace( rwhitespace, \" \" ) + \" \" ).indexOf( check ) > -1 :\n\t\t\t\t\toperator === \"|=\" ? result === check || result.slice( 0, check.length + 1 ) === check + \"-\" :\n\t\t\t\t\tfalse;\n\t\t\t};\n\t\t},\n\n\t\t\"CHILD\": function( type, what, argument, first, last ) {\n\t\t\tvar simple = type.slice( 0, 3 ) !== \"nth\",\n\t\t\t\tforward = type.slice( -4 ) !== \"last\",\n\t\t\t\tofType = what === \"of-type\";\n\n\t\t\treturn first === 1 && last === 0 ?\n\n\t\t\t\t// Shortcut for :nth-*(n)\n\t\t\t\tfunction( elem ) {\n\t\t\t\t\treturn !!elem.parentNode;\n\t\t\t\t} :\n\n\t\t\t\tfunction( elem, context, xml ) {\n\t\t\t\t\tvar cache, uniqueCache, outerCache, node, nodeIndex, start,\n\t\t\t\t\t\tdir = simple !== forward ? \"nextSibling\" : \"previousSibling\",\n\t\t\t\t\t\tparent = elem.parentNode,\n\t\t\t\t\t\tname = ofType && elem.nodeName.toLowerCase(),\n\t\t\t\t\t\tuseCache = !xml && !ofType,\n\t\t\t\t\t\tdiff = false;\n\n\t\t\t\t\tif ( parent ) {\n\n\t\t\t\t\t\t// :(first|last|only)-(child|of-type)\n\t\t\t\t\t\tif ( simple ) {\n\t\t\t\t\t\t\twhile ( dir ) {\n\t\t\t\t\t\t\t\tnode = elem;\n\t\t\t\t\t\t\t\twhile ( (node = node[ dir ]) ) {\n\t\t\t\t\t\t\t\t\tif ( ofType ?\n\t\t\t\t\t\t\t\t\t\tnode.nodeName.toLowerCase() === name :\n\t\t\t\t\t\t\t\t\t\tnode.nodeType === 1 ) {\n\n\t\t\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t// Reverse direction for :only-* (if we haven't yet done so)\n\t\t\t\t\t\t\t\tstart = dir = type === \"only\" && !start && \"nextSibling\";\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tstart = [ forward ? parent.firstChild : parent.lastChild ];\n\n\t\t\t\t\t\t// non-xml :nth-child(...) stores cache data on `parent`\n\t\t\t\t\t\tif ( forward && useCache ) {\n\n\t\t\t\t\t\t\t// Seek `elem` from a previously-cached index\n\n\t\t\t\t\t\t\t// ...in a gzip-friendly way\n\t\t\t\t\t\t\tnode = parent;\n\t\t\t\t\t\t\touterCache = node[ expando ] || (node[ expando ] = {});\n\n\t\t\t\t\t\t\t// Support: IE <9 only\n\t\t\t\t\t\t\t// Defend against cloned attroperties (jQuery gh-1709)\n\t\t\t\t\t\t\tuniqueCache = outerCache[ node.uniqueID ] ||\n\t\t\t\t\t\t\t\t(outerCache[ node.uniqueID ] = {});\n\n\t\t\t\t\t\t\tcache = uniqueCache[ type ] || [];\n\t\t\t\t\t\t\tnodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];\n\t\t\t\t\t\t\tdiff = nodeIndex && cache[ 2 ];\n\t\t\t\t\t\t\tnode = nodeIndex && parent.childNodes[ nodeIndex ];\n\n\t\t\t\t\t\t\twhile ( (node = ++nodeIndex && node && node[ dir ] ||\n\n\t\t\t\t\t\t\t\t// Fallback to seeking `elem` from the start\n\t\t\t\t\t\t\t\t(diff = nodeIndex = 0) || start.pop()) ) {\n\n\t\t\t\t\t\t\t\t// When found, cache indexes on `parent` and break\n\t\t\t\t\t\t\t\tif ( node.nodeType === 1 && ++diff && node === elem ) {\n\t\t\t\t\t\t\t\t\tuniqueCache[ type ] = [ dirruns, nodeIndex, diff ];\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Use previously-cached element index if available\n\t\t\t\t\t\t\tif ( useCache ) {\n\t\t\t\t\t\t\t\t// ...in a gzip-friendly way\n\t\t\t\t\t\t\t\tnode = elem;\n\t\t\t\t\t\t\t\touterCache = node[ expando ] || (node[ expando ] = {});\n\n\t\t\t\t\t\t\t\t// Support: IE <9 only\n\t\t\t\t\t\t\t\t// Defend against cloned attroperties (jQuery gh-1709)\n\t\t\t\t\t\t\t\tuniqueCache = outerCache[ node.uniqueID ] ||\n\t\t\t\t\t\t\t\t\t(outerCache[ node.uniqueID ] = {});\n\n\t\t\t\t\t\t\t\tcache = uniqueCache[ type ] || [];\n\t\t\t\t\t\t\t\tnodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];\n\t\t\t\t\t\t\t\tdiff = nodeIndex;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// xml :nth-child(...)\n\t\t\t\t\t\t\t// or :nth-last-child(...) or :nth(-last)?-of-type(...)\n\t\t\t\t\t\t\tif ( diff === false ) {\n\t\t\t\t\t\t\t\t// Use the same loop as above to seek `elem` from the start\n\t\t\t\t\t\t\t\twhile ( (node = ++nodeIndex && node && node[ dir ] ||\n\t\t\t\t\t\t\t\t\t(diff = nodeIndex = 0) || start.pop()) ) {\n\n\t\t\t\t\t\t\t\t\tif ( ( ofType ?\n\t\t\t\t\t\t\t\t\t\tnode.nodeName.toLowerCase() === name :\n\t\t\t\t\t\t\t\t\t\tnode.nodeType === 1 ) &&\n\t\t\t\t\t\t\t\t\t\t++diff ) {\n\n\t\t\t\t\t\t\t\t\t\t// Cache the index of each encountered element\n\t\t\t\t\t\t\t\t\t\tif ( useCache ) {\n\t\t\t\t\t\t\t\t\t\t\touterCache = node[ expando ] || (node[ expando ] = {});\n\n\t\t\t\t\t\t\t\t\t\t\t// Support: IE <9 only\n\t\t\t\t\t\t\t\t\t\t\t// Defend against cloned attroperties (jQuery gh-1709)\n\t\t\t\t\t\t\t\t\t\t\tuniqueCache = outerCache[ node.uniqueID ] ||\n\t\t\t\t\t\t\t\t\t\t\t\t(outerCache[ node.uniqueID ] = {});\n\n\t\t\t\t\t\t\t\t\t\t\tuniqueCache[ type ] = [ dirruns, diff ];\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\tif ( node === elem ) {\n\t\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Incorporate the offset, then check against cycle size\n\t\t\t\t\t\tdiff -= last;\n\t\t\t\t\t\treturn diff === first || ( diff % first === 0 && diff / first >= 0 );\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t},\n\n\t\t\"PSEUDO\": function( pseudo, argument ) {\n\t\t\t// pseudo-class names are case-insensitive\n\t\t\t// http://www.w3.org/TR/selectors/#pseudo-classes\n\t\t\t// Prioritize by case sensitivity in case custom pseudos are added with uppercase letters\n\t\t\t// Remember that setFilters inherits from pseudos\n\t\t\tvar args,\n\t\t\t\tfn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||\n\t\t\t\t\tSizzle.error( \"unsupported pseudo: \" + pseudo );\n\n\t\t\t// The user may use createPseudo to indicate that\n\t\t\t// arguments are needed to create the filter function\n\t\t\t// just as Sizzle does\n\t\t\tif ( fn[ expando ] ) {\n\t\t\t\treturn fn( argument );\n\t\t\t}\n\n\t\t\t// But maintain support for old signatures\n\t\t\tif ( fn.length > 1 ) {\n\t\t\t\targs = [ pseudo, pseudo, \"\", argument ];\n\t\t\t\treturn Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?\n\t\t\t\t\tmarkFunction(function( seed, matches ) {\n\t\t\t\t\t\tvar idx,\n\t\t\t\t\t\t\tmatched = fn( seed, argument ),\n\t\t\t\t\t\t\ti = matched.length;\n\t\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\t\tidx = indexOf( seed, matched[i] );\n\t\t\t\t\t\t\tseed[ idx ] = !( matches[ idx ] = matched[i] );\n\t\t\t\t\t\t}\n\t\t\t\t\t}) :\n\t\t\t\t\tfunction( elem ) {\n\t\t\t\t\t\treturn fn( elem, 0, args );\n\t\t\t\t\t};\n\t\t\t}\n\n\t\t\treturn fn;\n\t\t}\n\t},\n\n\tpseudos: {\n\t\t// Potentially complex pseudos\n\t\t\"not\": markFunction(function( selector ) {\n\t\t\t// Trim the selector passed to compile\n\t\t\t// to avoid treating leading and trailing\n\t\t\t// spaces as combinators\n\t\t\tvar input = [],\n\t\t\t\tresults = [],\n\t\t\t\tmatcher = compile( selector.replace( rtrim, \"$1\" ) );\n\n\t\t\treturn matcher[ expando ] ?\n\t\t\t\tmarkFunction(function( seed, matches, context, xml ) {\n\t\t\t\t\tvar elem,\n\t\t\t\t\t\tunmatched = matcher( seed, null, xml, [] ),\n\t\t\t\t\t\ti = seed.length;\n\n\t\t\t\t\t// Match elements unmatched by `matcher`\n\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\tif ( (elem = unmatched[i]) ) {\n\t\t\t\t\t\t\tseed[i] = !(matches[i] = elem);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}) :\n\t\t\t\tfunction( elem, context, xml ) {\n\t\t\t\t\tinput[0] = elem;\n\t\t\t\t\tmatcher( input, null, xml, results );\n\t\t\t\t\t// Don't keep the element (issue #299)\n\t\t\t\t\tinput[0] = null;\n\t\t\t\t\treturn !results.pop();\n\t\t\t\t};\n\t\t}),\n\n\t\t\"has\": markFunction(function( selector ) {\n\t\t\treturn function( elem ) {\n\t\t\t\treturn Sizzle( selector, elem ).length > 0;\n\t\t\t};\n\t\t}),\n\n\t\t\"contains\": markFunction(function( text ) {\n\t\t\ttext = text.replace( runescape, funescape );\n\t\t\treturn function( elem ) {\n\t\t\t\treturn ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;\n\t\t\t};\n\t\t}),\n\n\t\t// \"Whether an element is represented by a :lang() selector\n\t\t// is based solely on the element's language value\n\t\t// being equal to the identifier C,\n\t\t// or beginning with the identifier C immediately followed by \"-\".\n\t\t// The matching of C against the element's language value is performed case-insensitively.\n\t\t// The identifier C does not have to be a valid language name.\"\n\t\t// http://www.w3.org/TR/selectors/#lang-pseudo\n\t\t\"lang\": markFunction( function( lang ) {\n\t\t\t// lang value must be a valid identifier\n\t\t\tif ( !ridentifier.test(lang || \"\") ) {\n\t\t\t\tSizzle.error( \"unsupported lang: \" + lang );\n\t\t\t}\n\t\t\tlang = lang.replace( runescape, funescape ).toLowerCase();\n\t\t\treturn function( elem ) {\n\t\t\t\tvar elemLang;\n\t\t\t\tdo {\n\t\t\t\t\tif ( (elemLang = documentIsHTML ?\n\t\t\t\t\t\telem.lang :\n\t\t\t\t\t\telem.getAttribute(\"xml:lang\") || elem.getAttribute(\"lang\")) ) {\n\n\t\t\t\t\t\telemLang = elemLang.toLowerCase();\n\t\t\t\t\t\treturn elemLang === lang || elemLang.indexOf( lang + \"-\" ) === 0;\n\t\t\t\t\t}\n\t\t\t\t} while ( (elem = elem.parentNode) && elem.nodeType === 1 );\n\t\t\t\treturn false;\n\t\t\t};\n\t\t}),\n\n\t\t// Miscellaneous\n\t\t\"target\": function( elem ) {\n\t\t\tvar hash = window.location && window.location.hash;\n\t\t\treturn hash && hash.slice( 1 ) === elem.id;\n\t\t},\n\n\t\t\"root\": function( elem ) {\n\t\t\treturn elem === docElem;\n\t\t},\n\n\t\t\"focus\": function( elem ) {\n\t\t\treturn elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);\n\t\t},\n\n\t\t// Boolean properties\n\t\t\"enabled\": createDisabledPseudo( false ),\n\t\t\"disabled\": createDisabledPseudo( true ),\n\n\t\t\"checked\": function( elem ) {\n\t\t\t// In CSS3, :checked should return both checked and selected elements\n\t\t\t// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked\n\t\t\tvar nodeName = elem.nodeName.toLowerCase();\n\t\t\treturn (nodeName === \"input\" && !!elem.checked) || (nodeName === \"option\" && !!elem.selected);\n\t\t},\n\n\t\t\"selected\": function( elem ) {\n\t\t\t// Accessing this property makes selected-by-default\n\t\t\t// options in Safari work properly\n\t\t\tif ( elem.parentNode ) {\n\t\t\t\telem.parentNode.selectedIndex;\n\t\t\t}\n\n\t\t\treturn elem.selected === true;\n\t\t},\n\n\t\t// Contents\n\t\t\"empty\": function( elem ) {\n\t\t\t// http://www.w3.org/TR/selectors/#empty-pseudo\n\t\t\t// :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5),\n\t\t\t//   but not by others (comment: 8; processing instruction: 7; etc.)\n\t\t\t// nodeType < 6 works because attributes (2) do not appear as children\n\t\t\tfor ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {\n\t\t\t\tif ( elem.nodeType < 6 ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t},\n\n\t\t\"parent\": function( elem ) {\n\t\t\treturn !Expr.pseudos[\"empty\"]( elem );\n\t\t},\n\n\t\t// Element/input types\n\t\t\"header\": function( elem ) {\n\t\t\treturn rheader.test( elem.nodeName );\n\t\t},\n\n\t\t\"input\": function( elem ) {\n\t\t\treturn rinputs.test( elem.nodeName );\n\t\t},\n\n\t\t\"button\": function( elem ) {\n\t\t\tvar name = elem.nodeName.toLowerCase();\n\t\t\treturn name === \"input\" && elem.type === \"button\" || name === \"button\";\n\t\t},\n\n\t\t\"text\": function( elem ) {\n\t\t\tvar attr;\n\t\t\treturn elem.nodeName.toLowerCase() === \"input\" &&\n\t\t\t\telem.type === \"text\" &&\n\n\t\t\t\t// Support: IE<8\n\t\t\t\t// New HTML5 attribute values (e.g., \"search\") appear with elem.type === \"text\"\n\t\t\t\t( (attr = elem.getAttribute(\"type\")) == null || attr.toLowerCase() === \"text\" );\n\t\t},\n\n\t\t// Position-in-collection\n\t\t\"first\": createPositionalPseudo(function() {\n\t\t\treturn [ 0 ];\n\t\t}),\n\n\t\t\"last\": createPositionalPseudo(function( matchIndexes, length ) {\n\t\t\treturn [ length - 1 ];\n\t\t}),\n\n\t\t\"eq\": createPositionalPseudo(function( matchIndexes, length, argument ) {\n\t\t\treturn [ argument < 0 ? argument + length : argument ];\n\t\t}),\n\n\t\t\"even\": createPositionalPseudo(function( matchIndexes, length ) {\n\t\t\tvar i = 0;\n\t\t\tfor ( ; i < length; i += 2 ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t}),\n\n\t\t\"odd\": createPositionalPseudo(function( matchIndexes, length ) {\n\t\t\tvar i = 1;\n\t\t\tfor ( ; i < length; i += 2 ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t}),\n\n\t\t\"lt\": createPositionalPseudo(function( matchIndexes, length, argument ) {\n\t\t\tvar i = argument < 0 ? argument + length : argument;\n\t\t\tfor ( ; --i >= 0; ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t}),\n\n\t\t\"gt\": createPositionalPseudo(function( matchIndexes, length, argument ) {\n\t\t\tvar i = argument < 0 ? argument + length : argument;\n\t\t\tfor ( ; ++i < length; ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t})\n\t}\n};\n\nExpr.pseudos[\"nth\"] = Expr.pseudos[\"eq\"];\n\n// Add button/input type pseudos\nfor ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {\n\tExpr.pseudos[ i ] = createInputPseudo( i );\n}\nfor ( i in { submit: true, reset: true } ) {\n\tExpr.pseudos[ i ] = createButtonPseudo( i );\n}\n\n// Easy API for creating new setFilters\nfunction setFilters() {}\nsetFilters.prototype = Expr.filters = Expr.pseudos;\nExpr.setFilters = new setFilters();\n\ntokenize = Sizzle.tokenize = function( selector, parseOnly ) {\n\tvar matched, match, tokens, type,\n\t\tsoFar, groups, preFilters,\n\t\tcached = tokenCache[ selector + \" \" ];\n\n\tif ( cached ) {\n\t\treturn parseOnly ? 0 : cached.slice( 0 );\n\t}\n\n\tsoFar = selector;\n\tgroups = [];\n\tpreFilters = Expr.preFilter;\n\n\twhile ( soFar ) {\n\n\t\t// Comma and first run\n\t\tif ( !matched || (match = rcomma.exec( soFar )) ) {\n\t\t\tif ( match ) {\n\t\t\t\t// Don't consume trailing commas as valid\n\t\t\t\tsoFar = soFar.slice( match[0].length ) || soFar;\n\t\t\t}\n\t\t\tgroups.push( (tokens = []) );\n\t\t}\n\n\t\tmatched = false;\n\n\t\t// Combinators\n\t\tif ( (match = rcombinators.exec( soFar )) ) {\n\t\t\tmatched = match.shift();\n\t\t\ttokens.push({\n\t\t\t\tvalue: matched,\n\t\t\t\t// Cast descendant combinators to space\n\t\t\t\ttype: match[0].replace( rtrim, \" \" )\n\t\t\t});\n\t\t\tsoFar = soFar.slice( matched.length );\n\t\t}\n\n\t\t// Filters\n\t\tfor ( type in Expr.filter ) {\n\t\t\tif ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||\n\t\t\t\t(match = preFilters[ type ]( match ))) ) {\n\t\t\t\tmatched = match.shift();\n\t\t\t\ttokens.push({\n\t\t\t\t\tvalue: matched,\n\t\t\t\t\ttype: type,\n\t\t\t\t\tmatches: match\n\t\t\t\t});\n\t\t\t\tsoFar = soFar.slice( matched.length );\n\t\t\t}\n\t\t}\n\n\t\tif ( !matched ) {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t// Return the length of the invalid excess\n\t// if we're just parsing\n\t// Otherwise, throw an error or return tokens\n\treturn parseOnly ?\n\t\tsoFar.length :\n\t\tsoFar ?\n\t\t\tSizzle.error( selector ) :\n\t\t\t// Cache the tokens\n\t\t\ttokenCache( selector, groups ).slice( 0 );\n};\n\nfunction toSelector( tokens ) {\n\tvar i = 0,\n\t\tlen = tokens.length,\n\t\tselector = \"\";\n\tfor ( ; i < len; i++ ) {\n\t\tselector += tokens[i].value;\n\t}\n\treturn selector;\n}\n\nfunction addCombinator( matcher, combinator, base ) {\n\tvar dir = combinator.dir,\n\t\tskip = combinator.next,\n\t\tkey = skip || dir,\n\t\tcheckNonElements = base && key === \"parentNode\",\n\t\tdoneName = done++;\n\n\treturn combinator.first ?\n\t\t// Check against closest ancestor/preceding element\n\t\tfunction( elem, context, xml ) {\n\t\t\twhile ( (elem = elem[ dir ]) ) {\n\t\t\t\tif ( elem.nodeType === 1 || checkNonElements ) {\n\t\t\t\t\treturn matcher( elem, context, xml );\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t} :\n\n\t\t// Check against all ancestor/preceding elements\n\t\tfunction( elem, context, xml ) {\n\t\t\tvar oldCache, uniqueCache, outerCache,\n\t\t\t\tnewCache = [ dirruns, doneName ];\n\n\t\t\t// We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching\n\t\t\tif ( xml ) {\n\t\t\t\twhile ( (elem = elem[ dir ]) ) {\n\t\t\t\t\tif ( elem.nodeType === 1 || checkNonElements ) {\n\t\t\t\t\t\tif ( matcher( elem, context, xml ) ) {\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\twhile ( (elem = elem[ dir ]) ) {\n\t\t\t\t\tif ( elem.nodeType === 1 || checkNonElements ) {\n\t\t\t\t\t\touterCache = elem[ expando ] || (elem[ expando ] = {});\n\n\t\t\t\t\t\t// Support: IE <9 only\n\t\t\t\t\t\t// Defend against cloned attroperties (jQuery gh-1709)\n\t\t\t\t\t\tuniqueCache = outerCache[ elem.uniqueID ] || (outerCache[ elem.uniqueID ] = {});\n\n\t\t\t\t\t\tif ( skip && skip === elem.nodeName.toLowerCase() ) {\n\t\t\t\t\t\t\telem = elem[ dir ] || elem;\n\t\t\t\t\t\t} else if ( (oldCache = uniqueCache[ key ]) &&\n\t\t\t\t\t\t\toldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) {\n\n\t\t\t\t\t\t\t// Assign to newCache so results back-propagate to previous elements\n\t\t\t\t\t\t\treturn (newCache[ 2 ] = oldCache[ 2 ]);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Reuse newcache so results back-propagate to previous elements\n\t\t\t\t\t\t\tuniqueCache[ key ] = newCache;\n\n\t\t\t\t\t\t\t// A match means we're done; a fail means we have to keep checking\n\t\t\t\t\t\t\tif ( (newCache[ 2 ] = matcher( elem, context, xml )) ) {\n\t\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t};\n}\n\nfunction elementMatcher( matchers ) {\n\treturn matchers.length > 1 ?\n\t\tfunction( elem, context, xml ) {\n\t\t\tvar i = matchers.length;\n\t\t\twhile ( i-- ) {\n\t\t\t\tif ( !matchers[i]( elem, context, xml ) ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t} :\n\t\tmatchers[0];\n}\n\nfunction multipleContexts( selector, contexts, results ) {\n\tvar i = 0,\n\t\tlen = contexts.length;\n\tfor ( ; i < len; i++ ) {\n\t\tSizzle( selector, contexts[i], results );\n\t}\n\treturn results;\n}\n\nfunction condense( unmatched, map, filter, context, xml ) {\n\tvar elem,\n\t\tnewUnmatched = [],\n\t\ti = 0,\n\t\tlen = unmatched.length,\n\t\tmapped = map != null;\n\n\tfor ( ; i < len; i++ ) {\n\t\tif ( (elem = unmatched[i]) ) {\n\t\t\tif ( !filter || filter( elem, context, xml ) ) {\n\t\t\t\tnewUnmatched.push( elem );\n\t\t\t\tif ( mapped ) {\n\t\t\t\t\tmap.push( i );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn newUnmatched;\n}\n\nfunction setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {\n\tif ( postFilter && !postFilter[ expando ] ) {\n\t\tpostFilter = setMatcher( postFilter );\n\t}\n\tif ( postFinder && !postFinder[ expando ] ) {\n\t\tpostFinder = setMatcher( postFinder, postSelector );\n\t}\n\treturn markFunction(function( seed, results, context, xml ) {\n\t\tvar temp, i, elem,\n\t\t\tpreMap = [],\n\t\t\tpostMap = [],\n\t\t\tpreexisting = results.length,\n\n\t\t\t// Get initial elements from seed or context\n\t\t\telems = seed || multipleContexts( selector || \"*\", context.nodeType ? [ context ] : context, [] ),\n\n\t\t\t// Prefilter to get matcher input, preserving a map for seed-results synchronization\n\t\t\tmatcherIn = preFilter && ( seed || !selector ) ?\n\t\t\t\tcondense( elems, preMap, preFilter, context, xml ) :\n\t\t\t\telems,\n\n\t\t\tmatcherOut = matcher ?\n\t\t\t\t// If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,\n\t\t\t\tpostFinder || ( seed ? preFilter : preexisting || postFilter ) ?\n\n\t\t\t\t\t// ...intermediate processing is necessary\n\t\t\t\t\t[] :\n\n\t\t\t\t\t// ...otherwise use results directly\n\t\t\t\t\tresults :\n\t\t\t\tmatcherIn;\n\n\t\t// Find primary matches\n\t\tif ( matcher ) {\n\t\t\tmatcher( matcherIn, matcherOut, context, xml );\n\t\t}\n\n\t\t// Apply postFilter\n\t\tif ( postFilter ) {\n\t\t\ttemp = condense( matcherOut, postMap );\n\t\t\tpostFilter( temp, [], context, xml );\n\n\t\t\t// Un-match failing elements by moving them back to matcherIn\n\t\t\ti = temp.length;\n\t\t\twhile ( i-- ) {\n\t\t\t\tif ( (elem = temp[i]) ) {\n\t\t\t\t\tmatcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif ( seed ) {\n\t\t\tif ( postFinder || preFilter ) {\n\t\t\t\tif ( postFinder ) {\n\t\t\t\t\t// Get the final matcherOut by condensing this intermediate into postFinder contexts\n\t\t\t\t\ttemp = [];\n\t\t\t\t\ti = matcherOut.length;\n\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\tif ( (elem = matcherOut[i]) ) {\n\t\t\t\t\t\t\t// Restore matcherIn since elem is not yet a final match\n\t\t\t\t\t\t\ttemp.push( (matcherIn[i] = elem) );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tpostFinder( null, (matcherOut = []), temp, xml );\n\t\t\t\t}\n\n\t\t\t\t// Move matched elements from seed to results to keep them synchronized\n\t\t\t\ti = matcherOut.length;\n\t\t\t\twhile ( i-- ) {\n\t\t\t\t\tif ( (elem = matcherOut[i]) &&\n\t\t\t\t\t\t(temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) {\n\n\t\t\t\t\t\tseed[temp] = !(results[temp] = elem);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t// Add elements to results, through postFinder if defined\n\t\t} else {\n\t\t\tmatcherOut = condense(\n\t\t\t\tmatcherOut === results ?\n\t\t\t\t\tmatcherOut.splice( preexisting, matcherOut.length ) :\n\t\t\t\t\tmatcherOut\n\t\t\t);\n\t\t\tif ( postFinder ) {\n\t\t\t\tpostFinder( null, results, matcherOut, xml );\n\t\t\t} else {\n\t\t\t\tpush.apply( results, matcherOut );\n\t\t\t}\n\t\t}\n\t});\n}\n\nfunction matcherFromTokens( tokens ) {\n\tvar checkContext, matcher, j,\n\t\tlen = tokens.length,\n\t\tleadingRelative = Expr.relative[ tokens[0].type ],\n\t\timplicitRelative = leadingRelative || Expr.relative[\" \"],\n\t\ti = leadingRelative ? 1 : 0,\n\n\t\t// The foundational matcher ensures that elements are reachable from top-level context(s)\n\t\tmatchContext = addCombinator( function( elem ) {\n\t\t\treturn elem === checkContext;\n\t\t}, implicitRelative, true ),\n\t\tmatchAnyContext = addCombinator( function( elem ) {\n\t\t\treturn indexOf( checkContext, elem ) > -1;\n\t\t}, implicitRelative, true ),\n\t\tmatchers = [ function( elem, context, xml ) {\n\t\t\tvar ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || (\n\t\t\t\t(checkContext = context).nodeType ?\n\t\t\t\t\tmatchContext( elem, context, xml ) :\n\t\t\t\t\tmatchAnyContext( elem, context, xml ) );\n\t\t\t// Avoid hanging onto element (issue #299)\n\t\t\tcheckContext = null;\n\t\t\treturn ret;\n\t\t} ];\n\n\tfor ( ; i < len; i++ ) {\n\t\tif ( (matcher = Expr.relative[ tokens[i].type ]) ) {\n\t\t\tmatchers = [ addCombinator(elementMatcher( matchers ), matcher) ];\n\t\t} else {\n\t\t\tmatcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );\n\n\t\t\t// Return special upon seeing a positional matcher\n\t\t\tif ( matcher[ expando ] ) {\n\t\t\t\t// Find the next relative operator (if any) for proper handling\n\t\t\t\tj = ++i;\n\t\t\t\tfor ( ; j < len; j++ ) {\n\t\t\t\t\tif ( Expr.relative[ tokens[j].type ] ) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn setMatcher(\n\t\t\t\t\ti > 1 && elementMatcher( matchers ),\n\t\t\t\t\ti > 1 && toSelector(\n\t\t\t\t\t\t// If the preceding token was a descendant combinator, insert an implicit any-element `*`\n\t\t\t\t\t\ttokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === \" \" ? \"*\" : \"\" })\n\t\t\t\t\t).replace( rtrim, \"$1\" ),\n\t\t\t\t\tmatcher,\n\t\t\t\t\ti < j && matcherFromTokens( tokens.slice( i, j ) ),\n\t\t\t\t\tj < len && matcherFromTokens( (tokens = tokens.slice( j )) ),\n\t\t\t\t\tj < len && toSelector( tokens )\n\t\t\t\t);\n\t\t\t}\n\t\t\tmatchers.push( matcher );\n\t\t}\n\t}\n\n\treturn elementMatcher( matchers );\n}\n\nfunction matcherFromGroupMatchers( elementMatchers, setMatchers ) {\n\tvar bySet = setMatchers.length > 0,\n\t\tbyElement = elementMatchers.length > 0,\n\t\tsuperMatcher = function( seed, context, xml, results, outermost ) {\n\t\t\tvar elem, j, matcher,\n\t\t\t\tmatchedCount = 0,\n\t\t\t\ti = \"0\",\n\t\t\t\tunmatched = seed && [],\n\t\t\t\tsetMatched = [],\n\t\t\t\tcontextBackup = outermostContext,\n\t\t\t\t// We must always have either seed elements or outermost context\n\t\t\t\telems = seed || byElement && Expr.find[\"TAG\"]( \"*\", outermost ),\n\t\t\t\t// Use integer dirruns iff this is the outermost matcher\n\t\t\t\tdirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1),\n\t\t\t\tlen = elems.length;\n\n\t\t\tif ( outermost ) {\n\t\t\t\toutermostContext = context === document || context || outermost;\n\t\t\t}\n\n\t\t\t// Add elements passing elementMatchers directly to results\n\t\t\t// Support: IE<9, Safari\n\t\t\t// Tolerate NodeList properties (IE: \"length\"; Safari: <number>) matching elements by id\n\t\t\tfor ( ; i !== len && (elem = elems[i]) != null; i++ ) {\n\t\t\t\tif ( byElement && elem ) {\n\t\t\t\t\tj = 0;\n\t\t\t\t\tif ( !context && elem.ownerDocument !== document ) {\n\t\t\t\t\t\tsetDocument( elem );\n\t\t\t\t\t\txml = !documentIsHTML;\n\t\t\t\t\t}\n\t\t\t\t\twhile ( (matcher = elementMatchers[j++]) ) {\n\t\t\t\t\t\tif ( matcher( elem, context || document, xml) ) {\n\t\t\t\t\t\t\tresults.push( elem );\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif ( outermost ) {\n\t\t\t\t\t\tdirruns = dirrunsUnique;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Track unmatched elements for set filters\n\t\t\t\tif ( bySet ) {\n\t\t\t\t\t// They will have gone through all possible matchers\n\t\t\t\t\tif ( (elem = !matcher && elem) ) {\n\t\t\t\t\t\tmatchedCount--;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Lengthen the array for every element, matched or not\n\t\t\t\t\tif ( seed ) {\n\t\t\t\t\t\tunmatched.push( elem );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// `i` is now the count of elements visited above, and adding it to `matchedCount`\n\t\t\t// makes the latter nonnegative.\n\t\t\tmatchedCount += i;\n\n\t\t\t// Apply set filters to unmatched elements\n\t\t\t// NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount`\n\t\t\t// equals `i`), unless we didn't visit _any_ elements in the above loop because we have\n\t\t\t// no element matchers and no seed.\n\t\t\t// Incrementing an initially-string \"0\" `i` allows `i` to remain a string only in that\n\t\t\t// case, which will result in a \"00\" `matchedCount` that differs from `i` but is also\n\t\t\t// numerically zero.\n\t\t\tif ( bySet && i !== matchedCount ) {\n\t\t\t\tj = 0;\n\t\t\t\twhile ( (matcher = setMatchers[j++]) ) {\n\t\t\t\t\tmatcher( unmatched, setMatched, context, xml );\n\t\t\t\t}\n\n\t\t\t\tif ( seed ) {\n\t\t\t\t\t// Reintegrate element matches to eliminate the need for sorting\n\t\t\t\t\tif ( matchedCount > 0 ) {\n\t\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\t\tif ( !(unmatched[i] || setMatched[i]) ) {\n\t\t\t\t\t\t\t\tsetMatched[i] = pop.call( results );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Discard index placeholder values to get only actual matches\n\t\t\t\t\tsetMatched = condense( setMatched );\n\t\t\t\t}\n\n\t\t\t\t// Add matches to results\n\t\t\t\tpush.apply( results, setMatched );\n\n\t\t\t\t// Seedless set matches succeeding multiple successful matchers stipulate sorting\n\t\t\t\tif ( outermost && !seed && setMatched.length > 0 &&\n\t\t\t\t\t( matchedCount + setMatchers.length ) > 1 ) {\n\n\t\t\t\t\tSizzle.uniqueSort( results );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Override manipulation of globals by nested matchers\n\t\t\tif ( outermost ) {\n\t\t\t\tdirruns = dirrunsUnique;\n\t\t\t\toutermostContext = contextBackup;\n\t\t\t}\n\n\t\t\treturn unmatched;\n\t\t};\n\n\treturn bySet ?\n\t\tmarkFunction( superMatcher ) :\n\t\tsuperMatcher;\n}\n\ncompile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) {\n\tvar i,\n\t\tsetMatchers = [],\n\t\telementMatchers = [],\n\t\tcached = compilerCache[ selector + \" \" ];\n\n\tif ( !cached ) {\n\t\t// Generate a function of recursive functions that can be used to check each element\n\t\tif ( !match ) {\n\t\t\tmatch = tokenize( selector );\n\t\t}\n\t\ti = match.length;\n\t\twhile ( i-- ) {\n\t\t\tcached = matcherFromTokens( match[i] );\n\t\t\tif ( cached[ expando ] ) {\n\t\t\t\tsetMatchers.push( cached );\n\t\t\t} else {\n\t\t\t\telementMatchers.push( cached );\n\t\t\t}\n\t\t}\n\n\t\t// Cache the compiled function\n\t\tcached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );\n\n\t\t// Save selector and tokenization\n\t\tcached.selector = selector;\n\t}\n\treturn cached;\n};\n\n/**\n * A low-level selection function that works with Sizzle's compiled\n *  selector functions\n * @param {String|Function} selector A selector or a pre-compiled\n *  selector function built with Sizzle.compile\n * @param {Element} context\n * @param {Array} [results]\n * @param {Array} [seed] A set of elements to match against\n */\nselect = Sizzle.select = function( selector, context, results, seed ) {\n\tvar i, tokens, token, type, find,\n\t\tcompiled = typeof selector === \"function\" && selector,\n\t\tmatch = !seed && tokenize( (selector = compiled.selector || selector) );\n\n\tresults = results || [];\n\n\t// Try to minimize operations if there is only one selector in the list and no seed\n\t// (the latter of which guarantees us context)\n\tif ( match.length === 1 ) {\n\n\t\t// Reduce context if the leading compound selector is an ID\n\t\ttokens = match[0] = match[0].slice( 0 );\n\t\tif ( tokens.length > 2 && (token = tokens[0]).type === \"ID\" &&\n\t\t\t\tcontext.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[1].type ] ) {\n\n\t\t\tcontext = ( Expr.find[\"ID\"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0];\n\t\t\tif ( !context ) {\n\t\t\t\treturn results;\n\n\t\t\t// Precompiled matchers will still verify ancestry, so step up a level\n\t\t\t} else if ( compiled ) {\n\t\t\t\tcontext = context.parentNode;\n\t\t\t}\n\n\t\t\tselector = selector.slice( tokens.shift().value.length );\n\t\t}\n\n\t\t// Fetch a seed set for right-to-left matching\n\t\ti = matchExpr[\"needsContext\"].test( selector ) ? 0 : tokens.length;\n\t\twhile ( i-- ) {\n\t\t\ttoken = tokens[i];\n\n\t\t\t// Abort if we hit a combinator\n\t\t\tif ( Expr.relative[ (type = token.type) ] ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif ( (find = Expr.find[ type ]) ) {\n\t\t\t\t// Search, expanding context for leading sibling combinators\n\t\t\t\tif ( (seed = find(\n\t\t\t\t\ttoken.matches[0].replace( runescape, funescape ),\n\t\t\t\t\trsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context\n\t\t\t\t)) ) {\n\n\t\t\t\t\t// If seed is empty or no tokens remain, we can return early\n\t\t\t\t\ttokens.splice( i, 1 );\n\t\t\t\t\tselector = seed.length && toSelector( tokens );\n\t\t\t\t\tif ( !selector ) {\n\t\t\t\t\t\tpush.apply( results, seed );\n\t\t\t\t\t\treturn results;\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Compile and execute a filtering function if one is not provided\n\t// Provide `match` to avoid retokenization if we modified the selector above\n\t( compiled || compile( selector, match ) )(\n\t\tseed,\n\t\tcontext,\n\t\t!documentIsHTML,\n\t\tresults,\n\t\t!context || rsibling.test( selector ) && testContext( context.parentNode ) || context\n\t);\n\treturn results;\n};\n\n// One-time assignments\n\n// Sort stability\nsupport.sortStable = expando.split(\"\").sort( sortOrder ).join(\"\") === expando;\n\n// Support: Chrome 14-35+\n// Always assume duplicates if they aren't passed to the comparison function\nsupport.detectDuplicates = !!hasDuplicate;\n\n// Initialize against the default document\nsetDocument();\n\n// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27)\n// Detached nodes confoundingly follow *each other*\nsupport.sortDetached = assert(function( el ) {\n\t// Should return 1, but returns 4 (following)\n\treturn el.compareDocumentPosition( document.createElement(\"fieldset\") ) & 1;\n});\n\n// Support: IE<8\n// Prevent attribute/property \"interpolation\"\n// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx\nif ( !assert(function( el ) {\n\tel.innerHTML = \"<a href='#'></a>\";\n\treturn el.firstChild.getAttribute(\"href\") === \"#\" ;\n}) ) {\n\taddHandle( \"type|href|height|width\", function( elem, name, isXML ) {\n\t\tif ( !isXML ) {\n\t\t\treturn elem.getAttribute( name, name.toLowerCase() === \"type\" ? 1 : 2 );\n\t\t}\n\t});\n}\n\n// Support: IE<9\n// Use defaultValue in place of getAttribute(\"value\")\nif ( !support.attributes || !assert(function( el ) {\n\tel.innerHTML = \"<input/>\";\n\tel.firstChild.setAttribute( \"value\", \"\" );\n\treturn el.firstChild.getAttribute( \"value\" ) === \"\";\n}) ) {\n\taddHandle( \"value\", function( elem, name, isXML ) {\n\t\tif ( !isXML && elem.nodeName.toLowerCase() === \"input\" ) {\n\t\t\treturn elem.defaultValue;\n\t\t}\n\t});\n}\n\n// Support: IE<9\n// Use getAttributeNode to fetch booleans when getAttribute lies\nif ( !assert(function( el ) {\n\treturn el.getAttribute(\"disabled\") == null;\n}) ) {\n\taddHandle( booleans, function( elem, name, isXML ) {\n\t\tvar val;\n\t\tif ( !isXML ) {\n\t\t\treturn elem[ name ] === true ? name.toLowerCase() :\n\t\t\t\t\t(val = elem.getAttributeNode( name )) && val.specified ?\n\t\t\t\t\tval.value :\n\t\t\t\tnull;\n\t\t}\n\t});\n}\n\nreturn Sizzle;\n\n})( window );\n\n\n\njQuery.find = Sizzle;\njQuery.expr = Sizzle.selectors;\n\n// Deprecated\njQuery.expr[ \":\" ] = jQuery.expr.pseudos;\njQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort;\njQuery.text = Sizzle.getText;\njQuery.isXMLDoc = Sizzle.isXML;\njQuery.contains = Sizzle.contains;\njQuery.escapeSelector = Sizzle.escape;\n\n\n\n\nvar dir = function( elem, dir, until ) {\n\tvar matched = [],\n\t\ttruncate = until !== undefined;\n\n\twhile ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) {\n\t\tif ( elem.nodeType === 1 ) {\n\t\t\tif ( truncate && jQuery( elem ).is( until ) ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tmatched.push( elem );\n\t\t}\n\t}\n\treturn matched;\n};\n\n\nvar siblings = function( n, elem ) {\n\tvar matched = [];\n\n\tfor ( ; n; n = n.nextSibling ) {\n\t\tif ( n.nodeType === 1 && n !== elem ) {\n\t\t\tmatched.push( n );\n\t\t}\n\t}\n\n\treturn matched;\n};\n\n\nvar rneedsContext = jQuery.expr.match.needsContext;\n\n\n\nfunction nodeName( elem, name ) {\n\n  return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();\n\n};\nvar rsingleTag = ( /^<([a-z][^\\/\\0>:\\x20\\t\\r\\n\\f]*)[\\x20\\t\\r\\n\\f]*\\/?>(?:<\\/\\1>|)$/i );\n\n\n\nvar risSimple = /^.[^:#\\[\\.,]*$/;\n\n// Implement the identical functionality for filter and not\nfunction winnow( elements, qualifier, not ) {\n\tif ( jQuery.isFunction( qualifier ) ) {\n\t\treturn jQuery.grep( elements, function( elem, i ) {\n\t\t\treturn !!qualifier.call( elem, i, elem ) !== not;\n\t\t} );\n\t}\n\n\t// Single element\n\tif ( qualifier.nodeType ) {\n\t\treturn jQuery.grep( elements, function( elem ) {\n\t\t\treturn ( elem === qualifier ) !== not;\n\t\t} );\n\t}\n\n\t// Arraylike of elements (jQuery, arguments, Array)\n\tif ( typeof qualifier !== \"string\" ) {\n\t\treturn jQuery.grep( elements, function( elem ) {\n\t\t\treturn ( indexOf.call( qualifier, elem ) > -1 ) !== not;\n\t\t} );\n\t}\n\n\t// Simple selector that can be filtered directly, removing non-Elements\n\tif ( risSimple.test( qualifier ) ) {\n\t\treturn jQuery.filter( qualifier, elements, not );\n\t}\n\n\t// Complex selector, compare the two sets, removing non-Elements\n\tqualifier = jQuery.filter( qualifier, elements );\n\treturn jQuery.grep( elements, function( elem ) {\n\t\treturn ( indexOf.call( qualifier, elem ) > -1 ) !== not && elem.nodeType === 1;\n\t} );\n}\n\njQuery.filter = function( expr, elems, not ) {\n\tvar elem = elems[ 0 ];\n\n\tif ( not ) {\n\t\texpr = \":not(\" + expr + \")\";\n\t}\n\n\tif ( elems.length === 1 && elem.nodeType === 1 ) {\n\t\treturn jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [];\n\t}\n\n\treturn jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) {\n\t\treturn elem.nodeType === 1;\n\t} ) );\n};\n\njQuery.fn.extend( {\n\tfind: function( selector ) {\n\t\tvar i, ret,\n\t\t\tlen = this.length,\n\t\t\tself = this;\n\n\t\tif ( typeof selector !== \"string\" ) {\n\t\t\treturn this.pushStack( jQuery( selector ).filter( function() {\n\t\t\t\tfor ( i = 0; i < len; i++ ) {\n\t\t\t\t\tif ( jQuery.contains( self[ i ], this ) ) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} ) );\n\t\t}\n\n\t\tret = this.pushStack( [] );\n\n\t\tfor ( i = 0; i < len; i++ ) {\n\t\t\tjQuery.find( selector, self[ i ], ret );\n\t\t}\n\n\t\treturn len > 1 ? jQuery.uniqueSort( ret ) : ret;\n\t},\n\tfilter: function( selector ) {\n\t\treturn this.pushStack( winnow( this, selector || [], false ) );\n\t},\n\tnot: function( selector ) {\n\t\treturn this.pushStack( winnow( this, selector || [], true ) );\n\t},\n\tis: function( selector ) {\n\t\treturn !!winnow(\n\t\t\tthis,\n\n\t\t\t// If this is a positional/relative selector, check membership in the returned set\n\t\t\t// so $(\"p:first\").is(\"p:last\") won't return true for a doc with two \"p\".\n\t\t\ttypeof selector === \"string\" && rneedsContext.test( selector ) ?\n\t\t\t\tjQuery( selector ) :\n\t\t\t\tselector || [],\n\t\t\tfalse\n\t\t).length;\n\t}\n} );\n\n\n// Initialize a jQuery object\n\n\n// A central reference to the root jQuery(document)\nvar rootjQuery,\n\n\t// A simple way to check for HTML strings\n\t// Prioritize #id over <tag> to avoid XSS via location.hash (#9521)\n\t// Strict HTML recognition (#11290: must start with <)\n\t// Shortcut simple #id case for speed\n\trquickExpr = /^(?:\\s*(<[\\w\\W]+>)[^>]*|#([\\w-]+))$/,\n\n\tinit = jQuery.fn.init = function( selector, context, root ) {\n\t\tvar match, elem;\n\n\t\t// HANDLE: $(\"\"), $(null), $(undefined), $(false)\n\t\tif ( !selector ) {\n\t\t\treturn this;\n\t\t}\n\n\t\t// Method init() accepts an alternate rootjQuery\n\t\t// so migrate can support jQuery.sub (gh-2101)\n\t\troot = root || rootjQuery;\n\n\t\t// Handle HTML strings\n\t\tif ( typeof selector === \"string\" ) {\n\t\t\tif ( selector[ 0 ] === \"<\" &&\n\t\t\t\tselector[ selector.length - 1 ] === \">\" &&\n\t\t\t\tselector.length >= 3 ) {\n\n\t\t\t\t// Assume that strings that start and end with <> are HTML and skip the regex check\n\t\t\t\tmatch = [ null, selector, null ];\n\n\t\t\t} else {\n\t\t\t\tmatch = rquickExpr.exec( selector );\n\t\t\t}\n\n\t\t\t// Match html or make sure no context is specified for #id\n\t\t\tif ( match && ( match[ 1 ] || !context ) ) {\n\n\t\t\t\t// HANDLE: $(html) -> $(array)\n\t\t\t\tif ( match[ 1 ] ) {\n\t\t\t\t\tcontext = context instanceof jQuery ? context[ 0 ] : context;\n\n\t\t\t\t\t// Option to run scripts is true for back-compat\n\t\t\t\t\t// Intentionally let the error be thrown if parseHTML is not present\n\t\t\t\t\tjQuery.merge( this, jQuery.parseHTML(\n\t\t\t\t\t\tmatch[ 1 ],\n\t\t\t\t\t\tcontext && context.nodeType ? context.ownerDocument || context : document,\n\t\t\t\t\t\ttrue\n\t\t\t\t\t) );\n\n\t\t\t\t\t// HANDLE: $(html, props)\n\t\t\t\t\tif ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) {\n\t\t\t\t\t\tfor ( match in context ) {\n\n\t\t\t\t\t\t\t// Properties of context are called as methods if possible\n\t\t\t\t\t\t\tif ( jQuery.isFunction( this[ match ] ) ) {\n\t\t\t\t\t\t\t\tthis[ match ]( context[ match ] );\n\n\t\t\t\t\t\t\t// ...and otherwise set as attributes\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tthis.attr( match, context[ match ] );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\treturn this;\n\n\t\t\t\t// HANDLE: $(#id)\n\t\t\t\t} else {\n\t\t\t\t\telem = document.getElementById( match[ 2 ] );\n\n\t\t\t\t\tif ( elem ) {\n\n\t\t\t\t\t\t// Inject the element directly into the jQuery object\n\t\t\t\t\t\tthis[ 0 ] = elem;\n\t\t\t\t\t\tthis.length = 1;\n\t\t\t\t\t}\n\t\t\t\t\treturn this;\n\t\t\t\t}\n\n\t\t\t// HANDLE: $(expr, $(...))\n\t\t\t} else if ( !context || context.jquery ) {\n\t\t\t\treturn ( context || root ).find( selector );\n\n\t\t\t// HANDLE: $(expr, context)\n\t\t\t// (which is just equivalent to: $(context).find(expr)\n\t\t\t} else {\n\t\t\t\treturn this.constructor( context ).find( selector );\n\t\t\t}\n\n\t\t// HANDLE: $(DOMElement)\n\t\t} else if ( selector.nodeType ) {\n\t\t\tthis[ 0 ] = selector;\n\t\t\tthis.length = 1;\n\t\t\treturn this;\n\n\t\t// HANDLE: $(function)\n\t\t// Shortcut for document ready\n\t\t} else if ( jQuery.isFunction( selector ) ) {\n\t\t\treturn root.ready !== undefined ?\n\t\t\t\troot.ready( selector ) :\n\n\t\t\t\t// Execute immediately if ready is not present\n\t\t\t\tselector( jQuery );\n\t\t}\n\n\t\treturn jQuery.makeArray( selector, this );\n\t};\n\n// Give the init function the jQuery prototype for later instantiation\ninit.prototype = jQuery.fn;\n\n// Initialize central reference\nrootjQuery = jQuery( document );\n\n\nvar rparentsprev = /^(?:parents|prev(?:Until|All))/,\n\n\t// Methods guaranteed to produce a unique set when starting from a unique set\n\tguaranteedUnique = {\n\t\tchildren: true,\n\t\tcontents: true,\n\t\tnext: true,\n\t\tprev: true\n\t};\n\njQuery.fn.extend( {\n\thas: function( target ) {\n\t\tvar targets = jQuery( target, this ),\n\t\t\tl = targets.length;\n\n\t\treturn this.filter( function() {\n\t\t\tvar i = 0;\n\t\t\tfor ( ; i < l; i++ ) {\n\t\t\t\tif ( jQuery.contains( this, targets[ i ] ) ) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t},\n\n\tclosest: function( selectors, context ) {\n\t\tvar cur,\n\t\t\ti = 0,\n\t\t\tl = this.length,\n\t\t\tmatched = [],\n\t\t\ttargets = typeof selectors !== \"string\" && jQuery( selectors );\n\n\t\t// Positional selectors never match, since there's no _selection_ context\n\t\tif ( !rneedsContext.test( selectors ) ) {\n\t\t\tfor ( ; i < l; i++ ) {\n\t\t\t\tfor ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) {\n\n\t\t\t\t\t// Always skip document fragments\n\t\t\t\t\tif ( cur.nodeType < 11 && ( targets ?\n\t\t\t\t\t\ttargets.index( cur ) > -1 :\n\n\t\t\t\t\t\t// Don't pass non-elements to Sizzle\n\t\t\t\t\t\tcur.nodeType === 1 &&\n\t\t\t\t\t\t\tjQuery.find.matchesSelector( cur, selectors ) ) ) {\n\n\t\t\t\t\t\tmatched.push( cur );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched );\n\t},\n\n\t// Determine the position of an element within the set\n\tindex: function( elem ) {\n\n\t\t// No argument, return index in parent\n\t\tif ( !elem ) {\n\t\t\treturn ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1;\n\t\t}\n\n\t\t// Index in selector\n\t\tif ( typeof elem === \"string\" ) {\n\t\t\treturn indexOf.call( jQuery( elem ), this[ 0 ] );\n\t\t}\n\n\t\t// Locate the position of the desired element\n\t\treturn indexOf.call( this,\n\n\t\t\t// If it receives a jQuery object, the first element is used\n\t\t\telem.jquery ? elem[ 0 ] : elem\n\t\t);\n\t},\n\n\tadd: function( selector, context ) {\n\t\treturn this.pushStack(\n\t\t\tjQuery.uniqueSort(\n\t\t\t\tjQuery.merge( this.get(), jQuery( selector, context ) )\n\t\t\t)\n\t\t);\n\t},\n\n\taddBack: function( selector ) {\n\t\treturn this.add( selector == null ?\n\t\t\tthis.prevObject : this.prevObject.filter( selector )\n\t\t);\n\t}\n} );\n\nfunction sibling( cur, dir ) {\n\twhile ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {}\n\treturn cur;\n}\n\njQuery.each( {\n\tparent: function( elem ) {\n\t\tvar parent = elem.parentNode;\n\t\treturn parent && parent.nodeType !== 11 ? parent : null;\n\t},\n\tparents: function( elem ) {\n\t\treturn dir( elem, \"parentNode\" );\n\t},\n\tparentsUntil: function( elem, i, until ) {\n\t\treturn dir( elem, \"parentNode\", until );\n\t},\n\tnext: function( elem ) {\n\t\treturn sibling( elem, \"nextSibling\" );\n\t},\n\tprev: function( elem ) {\n\t\treturn sibling( elem, \"previousSibling\" );\n\t},\n\tnextAll: function( elem ) {\n\t\treturn dir( elem, \"nextSibling\" );\n\t},\n\tprevAll: function( elem ) {\n\t\treturn dir( elem, \"previousSibling\" );\n\t},\n\tnextUntil: function( elem, i, until ) {\n\t\treturn dir( elem, \"nextSibling\", until );\n\t},\n\tprevUntil: function( elem, i, until ) {\n\t\treturn dir( elem, \"previousSibling\", until );\n\t},\n\tsiblings: function( elem ) {\n\t\treturn siblings( ( elem.parentNode || {} ).firstChild, elem );\n\t},\n\tchildren: function( elem ) {\n\t\treturn siblings( elem.firstChild );\n\t},\n\tcontents: function( elem ) {\n        if ( nodeName( elem, \"iframe\" ) ) {\n            return elem.contentDocument;\n        }\n\n        // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only\n        // Treat the template element as a regular one in browsers that\n        // don't support it.\n        if ( nodeName( elem, \"template\" ) ) {\n            elem = elem.content || elem;\n        }\n\n        return jQuery.merge( [], elem.childNodes );\n\t}\n}, function( name, fn ) {\n\tjQuery.fn[ name ] = function( until, selector ) {\n\t\tvar matched = jQuery.map( this, fn, until );\n\n\t\tif ( name.slice( -5 ) !== \"Until\" ) {\n\t\t\tselector = until;\n\t\t}\n\n\t\tif ( selector && typeof selector === \"string\" ) {\n\t\t\tmatched = jQuery.filter( selector, matched );\n\t\t}\n\n\t\tif ( this.length > 1 ) {\n\n\t\t\t// Remove duplicates\n\t\t\tif ( !guaranteedUnique[ name ] ) {\n\t\t\t\tjQuery.uniqueSort( matched );\n\t\t\t}\n\n\t\t\t// Reverse order for parents* and prev-derivatives\n\t\t\tif ( rparentsprev.test( name ) ) {\n\t\t\t\tmatched.reverse();\n\t\t\t}\n\t\t}\n\n\t\treturn this.pushStack( matched );\n\t};\n} );\nvar rnothtmlwhite = ( /[^\\x20\\t\\r\\n\\f]+/g );\n\n\n\n// Convert String-formatted options into Object-formatted ones\nfunction createOptions( options ) {\n\tvar object = {};\n\tjQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) {\n\t\tobject[ flag ] = true;\n\t} );\n\treturn object;\n}\n\n/*\n * Create a callback list using the following parameters:\n *\n *\toptions: an optional list of space-separated options that will change how\n *\t\t\tthe callback list behaves or a more traditional option object\n *\n * By default a callback list will act like an event callback list and can be\n * \"fired\" multiple times.\n *\n * Possible options:\n *\n *\tonce:\t\t\twill ensure the callback list can only be fired once (like a Deferred)\n *\n *\tmemory:\t\t\twill keep track of previous values and will call any callback added\n *\t\t\t\t\tafter the list has been fired right away with the latest \"memorized\"\n *\t\t\t\t\tvalues (like a Deferred)\n *\n *\tunique:\t\t\twill ensure a callback can only be added once (no duplicate in the list)\n *\n *\tstopOnFalse:\tinterrupt callings when a callback returns false\n *\n */\njQuery.Callbacks = function( options ) {\n\n\t// Convert options from String-formatted to Object-formatted if needed\n\t// (we check in cache first)\n\toptions = typeof options === \"string\" ?\n\t\tcreateOptions( options ) :\n\t\tjQuery.extend( {}, options );\n\n\tvar // Flag to know if list is currently firing\n\t\tfiring,\n\n\t\t// Last fire value for non-forgettable lists\n\t\tmemory,\n\n\t\t// Flag to know if list was already fired\n\t\tfired,\n\n\t\t// Flag to prevent firing\n\t\tlocked,\n\n\t\t// Actual callback list\n\t\tlist = [],\n\n\t\t// Queue of execution data for repeatable lists\n\t\tqueue = [],\n\n\t\t// Index of currently firing callback (modified by add/remove as needed)\n\t\tfiringIndex = -1,\n\n\t\t// Fire callbacks\n\t\tfire = function() {\n\n\t\t\t// Enforce single-firing\n\t\t\tlocked = locked || options.once;\n\n\t\t\t// Execute callbacks for all pending executions,\n\t\t\t// respecting firingIndex overrides and runtime changes\n\t\t\tfired = firing = true;\n\t\t\tfor ( ; queue.length; firingIndex = -1 ) {\n\t\t\t\tmemory = queue.shift();\n\t\t\t\twhile ( ++firingIndex < list.length ) {\n\n\t\t\t\t\t// Run callback and check for early termination\n\t\t\t\t\tif ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false &&\n\t\t\t\t\t\toptions.stopOnFalse ) {\n\n\t\t\t\t\t\t// Jump to end and forget the data so .add doesn't re-fire\n\t\t\t\t\t\tfiringIndex = list.length;\n\t\t\t\t\t\tmemory = false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Forget the data if we're done with it\n\t\t\tif ( !options.memory ) {\n\t\t\t\tmemory = false;\n\t\t\t}\n\n\t\t\tfiring = false;\n\n\t\t\t// Clean up if we're done firing for good\n\t\t\tif ( locked ) {\n\n\t\t\t\t// Keep an empty list if we have data for future add calls\n\t\t\t\tif ( memory ) {\n\t\t\t\t\tlist = [];\n\n\t\t\t\t// Otherwise, this object is spent\n\t\t\t\t} else {\n\t\t\t\t\tlist = \"\";\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\t// Actual Callbacks object\n\t\tself = {\n\n\t\t\t// Add a callback or a collection of callbacks to the list\n\t\t\tadd: function() {\n\t\t\t\tif ( list ) {\n\n\t\t\t\t\t// If we have memory from a past run, we should fire after adding\n\t\t\t\t\tif ( memory && !firing ) {\n\t\t\t\t\t\tfiringIndex = list.length - 1;\n\t\t\t\t\t\tqueue.push( memory );\n\t\t\t\t\t}\n\n\t\t\t\t\t( function add( args ) {\n\t\t\t\t\t\tjQuery.each( args, function( _, arg ) {\n\t\t\t\t\t\t\tif ( jQuery.isFunction( arg ) ) {\n\t\t\t\t\t\t\t\tif ( !options.unique || !self.has( arg ) ) {\n\t\t\t\t\t\t\t\t\tlist.push( arg );\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else if ( arg && arg.length && jQuery.type( arg ) !== \"string\" ) {\n\n\t\t\t\t\t\t\t\t// Inspect recursively\n\t\t\t\t\t\t\t\tadd( arg );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} );\n\t\t\t\t\t} )( arguments );\n\n\t\t\t\t\tif ( memory && !firing ) {\n\t\t\t\t\t\tfire();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\t// Remove a callback from the list\n\t\t\tremove: function() {\n\t\t\t\tjQuery.each( arguments, function( _, arg ) {\n\t\t\t\t\tvar index;\n\t\t\t\t\twhile ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {\n\t\t\t\t\t\tlist.splice( index, 1 );\n\n\t\t\t\t\t\t// Handle firing indexes\n\t\t\t\t\t\tif ( index <= firingIndex ) {\n\t\t\t\t\t\t\tfiringIndex--;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\t// Check if a given callback is in the list.\n\t\t\t// If no argument is given, return whether or not list has callbacks attached.\n\t\t\thas: function( fn ) {\n\t\t\t\treturn fn ?\n\t\t\t\t\tjQuery.inArray( fn, list ) > -1 :\n\t\t\t\t\tlist.length > 0;\n\t\t\t},\n\n\t\t\t// Remove all callbacks from the list\n\t\t\tempty: function() {\n\t\t\t\tif ( list ) {\n\t\t\t\t\tlist = [];\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\t// Disable .fire and .add\n\t\t\t// Abort any current/pending executions\n\t\t\t// Clear all callbacks and values\n\t\t\tdisable: function() {\n\t\t\t\tlocked = queue = [];\n\t\t\t\tlist = memory = \"\";\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\tdisabled: function() {\n\t\t\t\treturn !list;\n\t\t\t},\n\n\t\t\t// Disable .fire\n\t\t\t// Also disable .add unless we have memory (since it would have no effect)\n\t\t\t// Abort any pending executions\n\t\t\tlock: function() {\n\t\t\t\tlocked = queue = [];\n\t\t\t\tif ( !memory && !firing ) {\n\t\t\t\t\tlist = memory = \"\";\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\tlocked: function() {\n\t\t\t\treturn !!locked;\n\t\t\t},\n\n\t\t\t// Call all callbacks with the given context and arguments\n\t\t\tfireWith: function( context, args ) {\n\t\t\t\tif ( !locked ) {\n\t\t\t\t\targs = args || [];\n\t\t\t\t\targs = [ context, args.slice ? args.slice() : args ];\n\t\t\t\t\tqueue.push( args );\n\t\t\t\t\tif ( !firing ) {\n\t\t\t\t\t\tfire();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\t// Call all the callbacks with the given arguments\n\t\t\tfire: function() {\n\t\t\t\tself.fireWith( this, arguments );\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\t// To know if the callbacks have already been called at least once\n\t\t\tfired: function() {\n\t\t\t\treturn !!fired;\n\t\t\t}\n\t\t};\n\n\treturn self;\n};\n\n\nfunction Identity( v ) {\n\treturn v;\n}\nfunction Thrower( ex ) {\n\tthrow ex;\n}\n\nfunction adoptValue( value, resolve, reject, noValue ) {\n\tvar method;\n\n\ttry {\n\n\t\t// Check for promise aspect first to privilege synchronous behavior\n\t\tif ( value && jQuery.isFunction( ( method = value.promise ) ) ) {\n\t\t\tmethod.call( value ).done( resolve ).fail( reject );\n\n\t\t// Other thenables\n\t\t} else if ( value && jQuery.isFunction( ( method = value.then ) ) ) {\n\t\t\tmethod.call( value, resolve, reject );\n\n\t\t// Other non-thenables\n\t\t} else {\n\n\t\t\t// Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer:\n\t\t\t// * false: [ value ].slice( 0 ) => resolve( value )\n\t\t\t// * true: [ value ].slice( 1 ) => resolve()\n\t\t\tresolve.apply( undefined, [ value ].slice( noValue ) );\n\t\t}\n\n\t// For Promises/A+, convert exceptions into rejections\n\t// Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in\n\t// Deferred#then to conditionally suppress rejection.\n\t} catch ( value ) {\n\n\t\t// Support: Android 4.0 only\n\t\t// Strict mode functions invoked without .call/.apply get global-object context\n\t\treject.apply( undefined, [ value ] );\n\t}\n}\n\njQuery.extend( {\n\n\tDeferred: function( func ) {\n\t\tvar tuples = [\n\n\t\t\t\t// action, add listener, callbacks,\n\t\t\t\t// ... .then handlers, argument index, [final state]\n\t\t\t\t[ \"notify\", \"progress\", jQuery.Callbacks( \"memory\" ),\n\t\t\t\t\tjQuery.Callbacks( \"memory\" ), 2 ],\n\t\t\t\t[ \"resolve\", \"done\", jQuery.Callbacks( \"once memory\" ),\n\t\t\t\t\tjQuery.Callbacks( \"once memory\" ), 0, \"resolved\" ],\n\t\t\t\t[ \"reject\", \"fail\", jQuery.Callbacks( \"once memory\" ),\n\t\t\t\t\tjQuery.Callbacks( \"once memory\" ), 1, \"rejected\" ]\n\t\t\t],\n\t\t\tstate = \"pending\",\n\t\t\tpromise = {\n\t\t\t\tstate: function() {\n\t\t\t\t\treturn state;\n\t\t\t\t},\n\t\t\t\talways: function() {\n\t\t\t\t\tdeferred.done( arguments ).fail( arguments );\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\t\t\t\t\"catch\": function( fn ) {\n\t\t\t\t\treturn promise.then( null, fn );\n\t\t\t\t},\n\n\t\t\t\t// Keep pipe for back-compat\n\t\t\t\tpipe: function( /* fnDone, fnFail, fnProgress */ ) {\n\t\t\t\t\tvar fns = arguments;\n\n\t\t\t\t\treturn jQuery.Deferred( function( newDefer ) {\n\t\t\t\t\t\tjQuery.each( tuples, function( i, tuple ) {\n\n\t\t\t\t\t\t\t// Map tuples (progress, done, fail) to arguments (done, fail, progress)\n\t\t\t\t\t\t\tvar fn = jQuery.isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ];\n\n\t\t\t\t\t\t\t// deferred.progress(function() { bind to newDefer or newDefer.notify })\n\t\t\t\t\t\t\t// deferred.done(function() { bind to newDefer or newDefer.resolve })\n\t\t\t\t\t\t\t// deferred.fail(function() { bind to newDefer or newDefer.reject })\n\t\t\t\t\t\t\tdeferred[ tuple[ 1 ] ]( function() {\n\t\t\t\t\t\t\t\tvar returned = fn && fn.apply( this, arguments );\n\t\t\t\t\t\t\t\tif ( returned && jQuery.isFunction( returned.promise ) ) {\n\t\t\t\t\t\t\t\t\treturned.promise()\n\t\t\t\t\t\t\t\t\t\t.progress( newDefer.notify )\n\t\t\t\t\t\t\t\t\t\t.done( newDefer.resolve )\n\t\t\t\t\t\t\t\t\t\t.fail( newDefer.reject );\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tnewDefer[ tuple[ 0 ] + \"With\" ](\n\t\t\t\t\t\t\t\t\t\tthis,\n\t\t\t\t\t\t\t\t\t\tfn ? [ returned ] : arguments\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t} );\n\t\t\t\t\t\tfns = null;\n\t\t\t\t\t} ).promise();\n\t\t\t\t},\n\t\t\t\tthen: function( onFulfilled, onRejected, onProgress ) {\n\t\t\t\t\tvar maxDepth = 0;\n\t\t\t\t\tfunction resolve( depth, deferred, handler, special ) {\n\t\t\t\t\t\treturn function() {\n\t\t\t\t\t\t\tvar that = this,\n\t\t\t\t\t\t\t\targs = arguments,\n\t\t\t\t\t\t\t\tmightThrow = function() {\n\t\t\t\t\t\t\t\t\tvar returned, then;\n\n\t\t\t\t\t\t\t\t\t// Support: Promises/A+ section 2.3.3.3.3\n\t\t\t\t\t\t\t\t\t// https://promisesaplus.com/#point-59\n\t\t\t\t\t\t\t\t\t// Ignore double-resolution attempts\n\t\t\t\t\t\t\t\t\tif ( depth < maxDepth ) {\n\t\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\treturned = handler.apply( that, args );\n\n\t\t\t\t\t\t\t\t\t// Support: Promises/A+ section 2.3.1\n\t\t\t\t\t\t\t\t\t// https://promisesaplus.com/#point-48\n\t\t\t\t\t\t\t\t\tif ( returned === deferred.promise() ) {\n\t\t\t\t\t\t\t\t\t\tthrow new TypeError( \"Thenable self-resolution\" );\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t// Support: Promises/A+ sections 2.3.3.1, 3.5\n\t\t\t\t\t\t\t\t\t// https://promisesaplus.com/#point-54\n\t\t\t\t\t\t\t\t\t// https://promisesaplus.com/#point-75\n\t\t\t\t\t\t\t\t\t// Retrieve `then` only once\n\t\t\t\t\t\t\t\t\tthen = returned &&\n\n\t\t\t\t\t\t\t\t\t\t// Support: Promises/A+ section 2.3.4\n\t\t\t\t\t\t\t\t\t\t// https://promisesaplus.com/#point-64\n\t\t\t\t\t\t\t\t\t\t// Only check objects and functions for thenability\n\t\t\t\t\t\t\t\t\t\t( typeof returned === \"object\" ||\n\t\t\t\t\t\t\t\t\t\t\ttypeof returned === \"function\" ) &&\n\t\t\t\t\t\t\t\t\t\treturned.then;\n\n\t\t\t\t\t\t\t\t\t// Handle a returned thenable\n\t\t\t\t\t\t\t\t\tif ( jQuery.isFunction( then ) ) {\n\n\t\t\t\t\t\t\t\t\t\t// Special processors (notify) just wait for resolution\n\t\t\t\t\t\t\t\t\t\tif ( special ) {\n\t\t\t\t\t\t\t\t\t\t\tthen.call(\n\t\t\t\t\t\t\t\t\t\t\t\treturned,\n\t\t\t\t\t\t\t\t\t\t\t\tresolve( maxDepth, deferred, Identity, special ),\n\t\t\t\t\t\t\t\t\t\t\t\tresolve( maxDepth, deferred, Thrower, special )\n\t\t\t\t\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t\t\t\t// Normal processors (resolve) also hook into progress\n\t\t\t\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\t\t\t\t// ...and disregard older resolution values\n\t\t\t\t\t\t\t\t\t\t\tmaxDepth++;\n\n\t\t\t\t\t\t\t\t\t\t\tthen.call(\n\t\t\t\t\t\t\t\t\t\t\t\treturned,\n\t\t\t\t\t\t\t\t\t\t\t\tresolve( maxDepth, deferred, Identity, special ),\n\t\t\t\t\t\t\t\t\t\t\t\tresolve( maxDepth, deferred, Thrower, special ),\n\t\t\t\t\t\t\t\t\t\t\t\tresolve( maxDepth, deferred, Identity,\n\t\t\t\t\t\t\t\t\t\t\t\t\tdeferred.notifyWith )\n\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t// Handle all other returned values\n\t\t\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\t\t\t// Only substitute handlers pass on context\n\t\t\t\t\t\t\t\t\t\t// and multiple values (non-spec behavior)\n\t\t\t\t\t\t\t\t\t\tif ( handler !== Identity ) {\n\t\t\t\t\t\t\t\t\t\t\tthat = undefined;\n\t\t\t\t\t\t\t\t\t\t\targs = [ returned ];\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t// Process the value(s)\n\t\t\t\t\t\t\t\t\t\t// Default process is resolve\n\t\t\t\t\t\t\t\t\t\t( special || deferred.resolveWith )( that, args );\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t},\n\n\t\t\t\t\t\t\t\t// Only normal processors (resolve) catch and reject exceptions\n\t\t\t\t\t\t\t\tprocess = special ?\n\t\t\t\t\t\t\t\t\tmightThrow :\n\t\t\t\t\t\t\t\t\tfunction() {\n\t\t\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\t\t\tmightThrow();\n\t\t\t\t\t\t\t\t\t\t} catch ( e ) {\n\n\t\t\t\t\t\t\t\t\t\t\tif ( jQuery.Deferred.exceptionHook ) {\n\t\t\t\t\t\t\t\t\t\t\t\tjQuery.Deferred.exceptionHook( e,\n\t\t\t\t\t\t\t\t\t\t\t\t\tprocess.stackTrace );\n\t\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t\t// Support: Promises/A+ section 2.3.3.3.4.1\n\t\t\t\t\t\t\t\t\t\t\t// https://promisesaplus.com/#point-61\n\t\t\t\t\t\t\t\t\t\t\t// Ignore post-resolution exceptions\n\t\t\t\t\t\t\t\t\t\t\tif ( depth + 1 >= maxDepth ) {\n\n\t\t\t\t\t\t\t\t\t\t\t\t// Only substitute handlers pass on context\n\t\t\t\t\t\t\t\t\t\t\t\t// and multiple values (non-spec behavior)\n\t\t\t\t\t\t\t\t\t\t\t\tif ( handler !== Thrower ) {\n\t\t\t\t\t\t\t\t\t\t\t\t\tthat = undefined;\n\t\t\t\t\t\t\t\t\t\t\t\t\targs = [ e ];\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t\t\tdeferred.rejectWith( that, args );\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\t// Support: Promises/A+ section 2.3.3.3.1\n\t\t\t\t\t\t\t// https://promisesaplus.com/#point-57\n\t\t\t\t\t\t\t// Re-resolve promises immediately to dodge false rejection from\n\t\t\t\t\t\t\t// subsequent errors\n\t\t\t\t\t\t\tif ( depth ) {\n\t\t\t\t\t\t\t\tprocess();\n\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\t// Call an optional hook to record the stack, in case of exception\n\t\t\t\t\t\t\t\t// since it's otherwise lost when execution goes async\n\t\t\t\t\t\t\t\tif ( jQuery.Deferred.getStackHook ) {\n\t\t\t\t\t\t\t\t\tprocess.stackTrace = jQuery.Deferred.getStackHook();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\twindow.setTimeout( process );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\n\t\t\t\t\treturn jQuery.Deferred( function( newDefer ) {\n\n\t\t\t\t\t\t// progress_handlers.add( ... )\n\t\t\t\t\t\ttuples[ 0 ][ 3 ].add(\n\t\t\t\t\t\t\tresolve(\n\t\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t\tnewDefer,\n\t\t\t\t\t\t\t\tjQuery.isFunction( onProgress ) ?\n\t\t\t\t\t\t\t\t\tonProgress :\n\t\t\t\t\t\t\t\t\tIdentity,\n\t\t\t\t\t\t\t\tnewDefer.notifyWith\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\t// fulfilled_handlers.add( ... )\n\t\t\t\t\t\ttuples[ 1 ][ 3 ].add(\n\t\t\t\t\t\t\tresolve(\n\t\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t\tnewDefer,\n\t\t\t\t\t\t\t\tjQuery.isFunction( onFulfilled ) ?\n\t\t\t\t\t\t\t\t\tonFulfilled :\n\t\t\t\t\t\t\t\t\tIdentity\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\t// rejected_handlers.add( ... )\n\t\t\t\t\t\ttuples[ 2 ][ 3 ].add(\n\t\t\t\t\t\t\tresolve(\n\t\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t\tnewDefer,\n\t\t\t\t\t\t\t\tjQuery.isFunction( onRejected ) ?\n\t\t\t\t\t\t\t\t\tonRejected :\n\t\t\t\t\t\t\t\t\tThrower\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t);\n\t\t\t\t\t} ).promise();\n\t\t\t\t},\n\n\t\t\t\t// Get a promise for this deferred\n\t\t\t\t// If obj is provided, the promise aspect is added to the object\n\t\t\t\tpromise: function( obj ) {\n\t\t\t\t\treturn obj != null ? jQuery.extend( obj, promise ) : promise;\n\t\t\t\t}\n\t\t\t},\n\t\t\tdeferred = {};\n\n\t\t// Add list-specific methods\n\t\tjQuery.each( tuples, function( i, tuple ) {\n\t\t\tvar list = tuple[ 2 ],\n\t\t\t\tstateString = tuple[ 5 ];\n\n\t\t\t// promise.progress = list.add\n\t\t\t// promise.done = list.add\n\t\t\t// promise.fail = list.add\n\t\t\tpromise[ tuple[ 1 ] ] = list.add;\n\n\t\t\t// Handle state\n\t\t\tif ( stateString ) {\n\t\t\t\tlist.add(\n\t\t\t\t\tfunction() {\n\n\t\t\t\t\t\t// state = \"resolved\" (i.e., fulfilled)\n\t\t\t\t\t\t// state = \"rejected\"\n\t\t\t\t\t\tstate = stateString;\n\t\t\t\t\t},\n\n\t\t\t\t\t// rejected_callbacks.disable\n\t\t\t\t\t// fulfilled_callbacks.disable\n\t\t\t\t\ttuples[ 3 - i ][ 2 ].disable,\n\n\t\t\t\t\t// progress_callbacks.lock\n\t\t\t\t\ttuples[ 0 ][ 2 ].lock\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// progress_handlers.fire\n\t\t\t// fulfilled_handlers.fire\n\t\t\t// rejected_handlers.fire\n\t\t\tlist.add( tuple[ 3 ].fire );\n\n\t\t\t// deferred.notify = function() { deferred.notifyWith(...) }\n\t\t\t// deferred.resolve = function() { deferred.resolveWith(...) }\n\t\t\t// deferred.reject = function() { deferred.rejectWith(...) }\n\t\t\tdeferred[ tuple[ 0 ] ] = function() {\n\t\t\t\tdeferred[ tuple[ 0 ] + \"With\" ]( this === deferred ? undefined : this, arguments );\n\t\t\t\treturn this;\n\t\t\t};\n\n\t\t\t// deferred.notifyWith = list.fireWith\n\t\t\t// deferred.resolveWith = list.fireWith\n\t\t\t// deferred.rejectWith = list.fireWith\n\t\t\tdeferred[ tuple[ 0 ] + \"With\" ] = list.fireWith;\n\t\t} );\n\n\t\t// Make the deferred a promise\n\t\tpromise.promise( deferred );\n\n\t\t// Call given func if any\n\t\tif ( func ) {\n\t\t\tfunc.call( deferred, deferred );\n\t\t}\n\n\t\t// All done!\n\t\treturn deferred;\n\t},\n\n\t// Deferred helper\n\twhen: function( singleValue ) {\n\t\tvar\n\n\t\t\t// count of uncompleted subordinates\n\t\t\tremaining = arguments.length,\n\n\t\t\t// count of unprocessed arguments\n\t\t\ti = remaining,\n\n\t\t\t// subordinate fulfillment data\n\t\t\tresolveContexts = Array( i ),\n\t\t\tresolveValues = slice.call( arguments ),\n\n\t\t\t// the master Deferred\n\t\t\tmaster = jQuery.Deferred(),\n\n\t\t\t// subordinate callback factory\n\t\t\tupdateFunc = function( i ) {\n\t\t\t\treturn function( value ) {\n\t\t\t\t\tresolveContexts[ i ] = this;\n\t\t\t\t\tresolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value;\n\t\t\t\t\tif ( !( --remaining ) ) {\n\t\t\t\t\t\tmaster.resolveWith( resolveContexts, resolveValues );\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t};\n\n\t\t// Single- and empty arguments are adopted like Promise.resolve\n\t\tif ( remaining <= 1 ) {\n\t\t\tadoptValue( singleValue, master.done( updateFunc( i ) ).resolve, master.reject,\n\t\t\t\t!remaining );\n\n\t\t\t// Use .then() to unwrap secondary thenables (cf. gh-3000)\n\t\t\tif ( master.state() === \"pending\" ||\n\t\t\t\tjQuery.isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) {\n\n\t\t\t\treturn master.then();\n\t\t\t}\n\t\t}\n\n\t\t// Multiple arguments are aggregated like Promise.all array elements\n\t\twhile ( i-- ) {\n\t\t\tadoptValue( resolveValues[ i ], updateFunc( i ), master.reject );\n\t\t}\n\n\t\treturn master.promise();\n\t}\n} );\n\n\n// These usually indicate a programmer mistake during development,\n// warn about them ASAP rather than swallowing them by default.\nvar rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;\n\njQuery.Deferred.exceptionHook = function( error, stack ) {\n\n\t// Support: IE 8 - 9 only\n\t// Console exists when dev tools are open, which can happen at any time\n\tif ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) {\n\t\twindow.console.warn( \"jQuery.Deferred exception: \" + error.message, error.stack, stack );\n\t}\n};\n\n\n\n\njQuery.readyException = function( error ) {\n\twindow.setTimeout( function() {\n\t\tthrow error;\n\t} );\n};\n\n\n\n\n// The deferred used on DOM ready\nvar readyList = jQuery.Deferred();\n\njQuery.fn.ready = function( fn ) {\n\n\treadyList\n\t\t.then( fn )\n\n\t\t// Wrap jQuery.readyException in a function so that the lookup\n\t\t// happens at the time of error handling instead of callback\n\t\t// registration.\n\t\t.catch( function( error ) {\n\t\t\tjQuery.readyException( error );\n\t\t} );\n\n\treturn this;\n};\n\njQuery.extend( {\n\n\t// Is the DOM ready to be used? Set to true once it occurs.\n\tisReady: false,\n\n\t// A counter to track how many items to wait for before\n\t// the ready event fires. See #6781\n\treadyWait: 1,\n\n\t// Handle when the DOM is ready\n\tready: function( wait ) {\n\n\t\t// Abort if there are pending holds or we're already ready\n\t\tif ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Remember that the DOM is ready\n\t\tjQuery.isReady = true;\n\n\t\t// If a normal DOM Ready event fired, decrement, and wait if need be\n\t\tif ( wait !== true && --jQuery.readyWait > 0 ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// If there are functions bound, to execute\n\t\treadyList.resolveWith( document, [ jQuery ] );\n\t}\n} );\n\njQuery.ready.then = readyList.then;\n\n// The ready event handler and self cleanup method\nfunction completed() {\n\tdocument.removeEventListener( \"DOMContentLoaded\", completed );\n\twindow.removeEventListener( \"load\", completed );\n\tjQuery.ready();\n}\n\n// Catch cases where $(document).ready() is called\n// after the browser event has already occurred.\n// Support: IE <=9 - 10 only\n// Older IE sometimes signals \"interactive\" too soon\nif ( document.readyState === \"complete\" ||\n\t( document.readyState !== \"loading\" && !document.documentElement.doScroll ) ) {\n\n\t// Handle it asynchronously to allow scripts the opportunity to delay ready\n\twindow.setTimeout( jQuery.ready );\n\n} else {\n\n\t// Use the handy event callback\n\tdocument.addEventListener( \"DOMContentLoaded\", completed );\n\n\t// A fallback to window.onload, that will always work\n\twindow.addEventListener( \"load\", completed );\n}\n\n\n\n\n// Multifunctional method to get and set values of a collection\n// The value/s can optionally be executed if it's a function\nvar access = function( elems, fn, key, value, chainable, emptyGet, raw ) {\n\tvar i = 0,\n\t\tlen = elems.length,\n\t\tbulk = key == null;\n\n\t// Sets many values\n\tif ( jQuery.type( key ) === \"object\" ) {\n\t\tchainable = true;\n\t\tfor ( i in key ) {\n\t\t\taccess( elems, fn, i, key[ i ], true, emptyGet, raw );\n\t\t}\n\n\t// Sets one value\n\t} else if ( value !== undefined ) {\n\t\tchainable = true;\n\n\t\tif ( !jQuery.isFunction( value ) ) {\n\t\t\traw = true;\n\t\t}\n\n\t\tif ( bulk ) {\n\n\t\t\t// Bulk operations run against the entire set\n\t\t\tif ( raw ) {\n\t\t\t\tfn.call( elems, value );\n\t\t\t\tfn = null;\n\n\t\t\t// ...except when executing function values\n\t\t\t} else {\n\t\t\t\tbulk = fn;\n\t\t\t\tfn = function( elem, key, value ) {\n\t\t\t\t\treturn bulk.call( jQuery( elem ), value );\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\tif ( fn ) {\n\t\t\tfor ( ; i < len; i++ ) {\n\t\t\t\tfn(\n\t\t\t\t\telems[ i ], key, raw ?\n\t\t\t\t\tvalue :\n\t\t\t\t\tvalue.call( elems[ i ], i, fn( elems[ i ], key ) )\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\tif ( chainable ) {\n\t\treturn elems;\n\t}\n\n\t// Gets\n\tif ( bulk ) {\n\t\treturn fn.call( elems );\n\t}\n\n\treturn len ? fn( elems[ 0 ], key ) : emptyGet;\n};\nvar acceptData = function( owner ) {\n\n\t// Accepts only:\n\t//  - Node\n\t//    - Node.ELEMENT_NODE\n\t//    - Node.DOCUMENT_NODE\n\t//  - Object\n\t//    - Any\n\treturn owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType );\n};\n\n\n\n\nfunction Data() {\n\tthis.expando = jQuery.expando + Data.uid++;\n}\n\nData.uid = 1;\n\nData.prototype = {\n\n\tcache: function( owner ) {\n\n\t\t// Check if the owner object already has a cache\n\t\tvar value = owner[ this.expando ];\n\n\t\t// If not, create one\n\t\tif ( !value ) {\n\t\t\tvalue = {};\n\n\t\t\t// We can accept data for non-element nodes in modern browsers,\n\t\t\t// but we should not, see #8335.\n\t\t\t// Always return an empty object.\n\t\t\tif ( acceptData( owner ) ) {\n\n\t\t\t\t// If it is a node unlikely to be stringify-ed or looped over\n\t\t\t\t// use plain assignment\n\t\t\t\tif ( owner.nodeType ) {\n\t\t\t\t\towner[ this.expando ] = value;\n\n\t\t\t\t// Otherwise secure it in a non-enumerable property\n\t\t\t\t// configurable must be true to allow the property to be\n\t\t\t\t// deleted when data is removed\n\t\t\t\t} else {\n\t\t\t\t\tObject.defineProperty( owner, this.expando, {\n\t\t\t\t\t\tvalue: value,\n\t\t\t\t\t\tconfigurable: true\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn value;\n\t},\n\tset: function( owner, data, value ) {\n\t\tvar prop,\n\t\t\tcache = this.cache( owner );\n\n\t\t// Handle: [ owner, key, value ] args\n\t\t// Always use camelCase key (gh-2257)\n\t\tif ( typeof data === \"string\" ) {\n\t\t\tcache[ jQuery.camelCase( data ) ] = value;\n\n\t\t// Handle: [ owner, { properties } ] args\n\t\t} else {\n\n\t\t\t// Copy the properties one-by-one to the cache object\n\t\t\tfor ( prop in data ) {\n\t\t\t\tcache[ jQuery.camelCase( prop ) ] = data[ prop ];\n\t\t\t}\n\t\t}\n\t\treturn cache;\n\t},\n\tget: function( owner, key ) {\n\t\treturn key === undefined ?\n\t\t\tthis.cache( owner ) :\n\n\t\t\t// Always use camelCase key (gh-2257)\n\t\t\towner[ this.expando ] && owner[ this.expando ][ jQuery.camelCase( key ) ];\n\t},\n\taccess: function( owner, key, value ) {\n\n\t\t// In cases where either:\n\t\t//\n\t\t//   1. No key was specified\n\t\t//   2. A string key was specified, but no value provided\n\t\t//\n\t\t// Take the \"read\" path and allow the get method to determine\n\t\t// which value to return, respectively either:\n\t\t//\n\t\t//   1. The entire cache object\n\t\t//   2. The data stored at the key\n\t\t//\n\t\tif ( key === undefined ||\n\t\t\t\t( ( key && typeof key === \"string\" ) && value === undefined ) ) {\n\n\t\t\treturn this.get( owner, key );\n\t\t}\n\n\t\t// When the key is not a string, or both a key and value\n\t\t// are specified, set or extend (existing objects) with either:\n\t\t//\n\t\t//   1. An object of properties\n\t\t//   2. A key and value\n\t\t//\n\t\tthis.set( owner, key, value );\n\n\t\t// Since the \"set\" path can have two possible entry points\n\t\t// return the expected data based on which path was taken[*]\n\t\treturn value !== undefined ? value : key;\n\t},\n\tremove: function( owner, key ) {\n\t\tvar i,\n\t\t\tcache = owner[ this.expando ];\n\n\t\tif ( cache === undefined ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( key !== undefined ) {\n\n\t\t\t// Support array or space separated string of keys\n\t\t\tif ( Array.isArray( key ) ) {\n\n\t\t\t\t// If key is an array of keys...\n\t\t\t\t// We always set camelCase keys, so remove that.\n\t\t\t\tkey = key.map( jQuery.camelCase );\n\t\t\t} else {\n\t\t\t\tkey = jQuery.camelCase( key );\n\n\t\t\t\t// If a key with the spaces exists, use it.\n\t\t\t\t// Otherwise, create an array by matching non-whitespace\n\t\t\t\tkey = key in cache ?\n\t\t\t\t\t[ key ] :\n\t\t\t\t\t( key.match( rnothtmlwhite ) || [] );\n\t\t\t}\n\n\t\t\ti = key.length;\n\n\t\t\twhile ( i-- ) {\n\t\t\t\tdelete cache[ key[ i ] ];\n\t\t\t}\n\t\t}\n\n\t\t// Remove the expando if there's no more data\n\t\tif ( key === undefined || jQuery.isEmptyObject( cache ) ) {\n\n\t\t\t// Support: Chrome <=35 - 45\n\t\t\t// Webkit & Blink performance suffers when deleting properties\n\t\t\t// from DOM nodes, so set to undefined instead\n\t\t\t// https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted)\n\t\t\tif ( owner.nodeType ) {\n\t\t\t\towner[ this.expando ] = undefined;\n\t\t\t} else {\n\t\t\t\tdelete owner[ this.expando ];\n\t\t\t}\n\t\t}\n\t},\n\thasData: function( owner ) {\n\t\tvar cache = owner[ this.expando ];\n\t\treturn cache !== undefined && !jQuery.isEmptyObject( cache );\n\t}\n};\nvar dataPriv = new Data();\n\nvar dataUser = new Data();\n\n\n\n//\tImplementation Summary\n//\n//\t1. Enforce API surface and semantic compatibility with 1.9.x branch\n//\t2. Improve the module's maintainability by reducing the storage\n//\t\tpaths to a single mechanism.\n//\t3. Use the same single mechanism to support \"private\" and \"user\" data.\n//\t4. _Never_ expose \"private\" data to user code (TODO: Drop _data, _removeData)\n//\t5. Avoid exposing implementation details on user objects (eg. expando properties)\n//\t6. Provide a clear path for implementation upgrade to WeakMap in 2014\n\nvar rbrace = /^(?:\\{[\\w\\W]*\\}|\\[[\\w\\W]*\\])$/,\n\trmultiDash = /[A-Z]/g;\n\nfunction getData( data ) {\n\tif ( data === \"true\" ) {\n\t\treturn true;\n\t}\n\n\tif ( data === \"false\" ) {\n\t\treturn false;\n\t}\n\n\tif ( data === \"null\" ) {\n\t\treturn null;\n\t}\n\n\t// Only convert to a number if it doesn't change the string\n\tif ( data === +data + \"\" ) {\n\t\treturn +data;\n\t}\n\n\tif ( rbrace.test( data ) ) {\n\t\treturn JSON.parse( data );\n\t}\n\n\treturn data;\n}\n\nfunction dataAttr( elem, key, data ) {\n\tvar name;\n\n\t// If nothing was found internally, try to fetch any\n\t// data from the HTML5 data-* attribute\n\tif ( data === undefined && elem.nodeType === 1 ) {\n\t\tname = \"data-\" + key.replace( rmultiDash, \"-$&\" ).toLowerCase();\n\t\tdata = elem.getAttribute( name );\n\n\t\tif ( typeof data === \"string\" ) {\n\t\t\ttry {\n\t\t\t\tdata = getData( data );\n\t\t\t} catch ( e ) {}\n\n\t\t\t// Make sure we set the data so it isn't changed later\n\t\t\tdataUser.set( elem, key, data );\n\t\t} else {\n\t\t\tdata = undefined;\n\t\t}\n\t}\n\treturn data;\n}\n\njQuery.extend( {\n\thasData: function( elem ) {\n\t\treturn dataUser.hasData( elem ) || dataPriv.hasData( elem );\n\t},\n\n\tdata: function( elem, name, data ) {\n\t\treturn dataUser.access( elem, name, data );\n\t},\n\n\tremoveData: function( elem, name ) {\n\t\tdataUser.remove( elem, name );\n\t},\n\n\t// TODO: Now that all calls to _data and _removeData have been replaced\n\t// with direct calls to dataPriv methods, these can be deprecated.\n\t_data: function( elem, name, data ) {\n\t\treturn dataPriv.access( elem, name, data );\n\t},\n\n\t_removeData: function( elem, name ) {\n\t\tdataPriv.remove( elem, name );\n\t}\n} );\n\njQuery.fn.extend( {\n\tdata: function( key, value ) {\n\t\tvar i, name, data,\n\t\t\telem = this[ 0 ],\n\t\t\tattrs = elem && elem.attributes;\n\n\t\t// Gets all values\n\t\tif ( key === undefined ) {\n\t\t\tif ( this.length ) {\n\t\t\t\tdata = dataUser.get( elem );\n\n\t\t\t\tif ( elem.nodeType === 1 && !dataPriv.get( elem, \"hasDataAttrs\" ) ) {\n\t\t\t\t\ti = attrs.length;\n\t\t\t\t\twhile ( i-- ) {\n\n\t\t\t\t\t\t// Support: IE 11 only\n\t\t\t\t\t\t// The attrs elements can be null (#14894)\n\t\t\t\t\t\tif ( attrs[ i ] ) {\n\t\t\t\t\t\t\tname = attrs[ i ].name;\n\t\t\t\t\t\t\tif ( name.indexOf( \"data-\" ) === 0 ) {\n\t\t\t\t\t\t\t\tname = jQuery.camelCase( name.slice( 5 ) );\n\t\t\t\t\t\t\t\tdataAttr( elem, name, data[ name ] );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tdataPriv.set( elem, \"hasDataAttrs\", true );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn data;\n\t\t}\n\n\t\t// Sets multiple values\n\t\tif ( typeof key === \"object\" ) {\n\t\t\treturn this.each( function() {\n\t\t\t\tdataUser.set( this, key );\n\t\t\t} );\n\t\t}\n\n\t\treturn access( this, function( value ) {\n\t\t\tvar data;\n\n\t\t\t// The calling jQuery object (element matches) is not empty\n\t\t\t// (and therefore has an element appears at this[ 0 ]) and the\n\t\t\t// `value` parameter was not undefined. An empty jQuery object\n\t\t\t// will result in `undefined` for elem = this[ 0 ] which will\n\t\t\t// throw an exception if an attempt to read a data cache is made.\n\t\t\tif ( elem && value === undefined ) {\n\n\t\t\t\t// Attempt to get data from the cache\n\t\t\t\t// The key will always be camelCased in Data\n\t\t\t\tdata = dataUser.get( elem, key );\n\t\t\t\tif ( data !== undefined ) {\n\t\t\t\t\treturn data;\n\t\t\t\t}\n\n\t\t\t\t// Attempt to \"discover\" the data in\n\t\t\t\t// HTML5 custom data-* attrs\n\t\t\t\tdata = dataAttr( elem, key );\n\t\t\t\tif ( data !== undefined ) {\n\t\t\t\t\treturn data;\n\t\t\t\t}\n\n\t\t\t\t// We tried really hard, but the data doesn't exist.\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Set the data...\n\t\t\tthis.each( function() {\n\n\t\t\t\t// We always store the camelCased key\n\t\t\t\tdataUser.set( this, key, value );\n\t\t\t} );\n\t\t}, null, value, arguments.length > 1, null, true );\n\t},\n\n\tremoveData: function( key ) {\n\t\treturn this.each( function() {\n\t\t\tdataUser.remove( this, key );\n\t\t} );\n\t}\n} );\n\n\njQuery.extend( {\n\tqueue: function( elem, type, data ) {\n\t\tvar queue;\n\n\t\tif ( elem ) {\n\t\t\ttype = ( type || \"fx\" ) + \"queue\";\n\t\t\tqueue = dataPriv.get( elem, type );\n\n\t\t\t// Speed up dequeue by getting out quickly if this is just a lookup\n\t\t\tif ( data ) {\n\t\t\t\tif ( !queue || Array.isArray( data ) ) {\n\t\t\t\t\tqueue = dataPriv.access( elem, type, jQuery.makeArray( data ) );\n\t\t\t\t} else {\n\t\t\t\t\tqueue.push( data );\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn queue || [];\n\t\t}\n\t},\n\n\tdequeue: function( elem, type ) {\n\t\ttype = type || \"fx\";\n\n\t\tvar queue = jQuery.queue( elem, type ),\n\t\t\tstartLength = queue.length,\n\t\t\tfn = queue.shift(),\n\t\t\thooks = jQuery._queueHooks( elem, type ),\n\t\t\tnext = function() {\n\t\t\t\tjQuery.dequeue( elem, type );\n\t\t\t};\n\n\t\t// If the fx queue is dequeued, always remove the progress sentinel\n\t\tif ( fn === \"inprogress\" ) {\n\t\t\tfn = queue.shift();\n\t\t\tstartLength--;\n\t\t}\n\n\t\tif ( fn ) {\n\n\t\t\t// Add a progress sentinel to prevent the fx queue from being\n\t\t\t// automatically dequeued\n\t\t\tif ( type === \"fx\" ) {\n\t\t\t\tqueue.unshift( \"inprogress\" );\n\t\t\t}\n\n\t\t\t// Clear up the last queue stop function\n\t\t\tdelete hooks.stop;\n\t\t\tfn.call( elem, next, hooks );\n\t\t}\n\n\t\tif ( !startLength && hooks ) {\n\t\t\thooks.empty.fire();\n\t\t}\n\t},\n\n\t// Not public - generate a queueHooks object, or return the current one\n\t_queueHooks: function( elem, type ) {\n\t\tvar key = type + \"queueHooks\";\n\t\treturn dataPriv.get( elem, key ) || dataPriv.access( elem, key, {\n\t\t\tempty: jQuery.Callbacks( \"once memory\" ).add( function() {\n\t\t\t\tdataPriv.remove( elem, [ type + \"queue\", key ] );\n\t\t\t} )\n\t\t} );\n\t}\n} );\n\njQuery.fn.extend( {\n\tqueue: function( type, data ) {\n\t\tvar setter = 2;\n\n\t\tif ( typeof type !== \"string\" ) {\n\t\t\tdata = type;\n\t\t\ttype = \"fx\";\n\t\t\tsetter--;\n\t\t}\n\n\t\tif ( arguments.length < setter ) {\n\t\t\treturn jQuery.queue( this[ 0 ], type );\n\t\t}\n\n\t\treturn data === undefined ?\n\t\t\tthis :\n\t\t\tthis.each( function() {\n\t\t\t\tvar queue = jQuery.queue( this, type, data );\n\n\t\t\t\t// Ensure a hooks for this queue\n\t\t\t\tjQuery._queueHooks( this, type );\n\n\t\t\t\tif ( type === \"fx\" && queue[ 0 ] !== \"inprogress\" ) {\n\t\t\t\t\tjQuery.dequeue( this, type );\n\t\t\t\t}\n\t\t\t} );\n\t},\n\tdequeue: function( type ) {\n\t\treturn this.each( function() {\n\t\t\tjQuery.dequeue( this, type );\n\t\t} );\n\t},\n\tclearQueue: function( type ) {\n\t\treturn this.queue( type || \"fx\", [] );\n\t},\n\n\t// Get a promise resolved when queues of a certain type\n\t// are emptied (fx is the type by default)\n\tpromise: function( type, obj ) {\n\t\tvar tmp,\n\t\t\tcount = 1,\n\t\t\tdefer = jQuery.Deferred(),\n\t\t\telements = this,\n\t\t\ti = this.length,\n\t\t\tresolve = function() {\n\t\t\t\tif ( !( --count ) ) {\n\t\t\t\t\tdefer.resolveWith( elements, [ elements ] );\n\t\t\t\t}\n\t\t\t};\n\n\t\tif ( typeof type !== \"string\" ) {\n\t\t\tobj = type;\n\t\t\ttype = undefined;\n\t\t}\n\t\ttype = type || \"fx\";\n\n\t\twhile ( i-- ) {\n\t\t\ttmp = dataPriv.get( elements[ i ], type + \"queueHooks\" );\n\t\t\tif ( tmp && tmp.empty ) {\n\t\t\t\tcount++;\n\t\t\t\ttmp.empty.add( resolve );\n\t\t\t}\n\t\t}\n\t\tresolve();\n\t\treturn defer.promise( obj );\n\t}\n} );\nvar pnum = ( /[+-]?(?:\\d*\\.|)\\d+(?:[eE][+-]?\\d+|)/ ).source;\n\nvar rcssNum = new RegExp( \"^(?:([+-])=|)(\" + pnum + \")([a-z%]*)$\", \"i\" );\n\n\nvar cssExpand = [ \"Top\", \"Right\", \"Bottom\", \"Left\" ];\n\nvar isHiddenWithinTree = function( elem, el ) {\n\n\t\t// isHiddenWithinTree might be called from jQuery#filter function;\n\t\t// in that case, element will be second argument\n\t\telem = el || elem;\n\n\t\t// Inline style trumps all\n\t\treturn elem.style.display === \"none\" ||\n\t\t\telem.style.display === \"\" &&\n\n\t\t\t// Otherwise, check computed style\n\t\t\t// Support: Firefox <=43 - 45\n\t\t\t// Disconnected elements can have computed display: none, so first confirm that elem is\n\t\t\t// in the document.\n\t\t\tjQuery.contains( elem.ownerDocument, elem ) &&\n\n\t\t\tjQuery.css( elem, \"display\" ) === \"none\";\n\t};\n\nvar swap = function( elem, options, callback, args ) {\n\tvar ret, name,\n\t\told = {};\n\n\t// Remember the old values, and insert the new ones\n\tfor ( name in options ) {\n\t\told[ name ] = elem.style[ name ];\n\t\telem.style[ name ] = options[ name ];\n\t}\n\n\tret = callback.apply( elem, args || [] );\n\n\t// Revert the old values\n\tfor ( name in options ) {\n\t\telem.style[ name ] = old[ name ];\n\t}\n\n\treturn ret;\n};\n\n\n\n\nfunction adjustCSS( elem, prop, valueParts, tween ) {\n\tvar adjusted,\n\t\tscale = 1,\n\t\tmaxIterations = 20,\n\t\tcurrentValue = tween ?\n\t\t\tfunction() {\n\t\t\t\treturn tween.cur();\n\t\t\t} :\n\t\t\tfunction() {\n\t\t\t\treturn jQuery.css( elem, prop, \"\" );\n\t\t\t},\n\t\tinitial = currentValue(),\n\t\tunit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? \"\" : \"px\" ),\n\n\t\t// Starting value computation is required for potential unit mismatches\n\t\tinitialInUnit = ( jQuery.cssNumber[ prop ] || unit !== \"px\" && +initial ) &&\n\t\t\trcssNum.exec( jQuery.css( elem, prop ) );\n\n\tif ( initialInUnit && initialInUnit[ 3 ] !== unit ) {\n\n\t\t// Trust units reported by jQuery.css\n\t\tunit = unit || initialInUnit[ 3 ];\n\n\t\t// Make sure we update the tween properties later on\n\t\tvalueParts = valueParts || [];\n\n\t\t// Iteratively approximate from a nonzero starting point\n\t\tinitialInUnit = +initial || 1;\n\n\t\tdo {\n\n\t\t\t// If previous iteration zeroed out, double until we get *something*.\n\t\t\t// Use string for doubling so we don't accidentally see scale as unchanged below\n\t\t\tscale = scale || \".5\";\n\n\t\t\t// Adjust and apply\n\t\t\tinitialInUnit = initialInUnit / scale;\n\t\t\tjQuery.style( elem, prop, initialInUnit + unit );\n\n\t\t// Update scale, tolerating zero or NaN from tween.cur()\n\t\t// Break the loop if scale is unchanged or perfect, or if we've just had enough.\n\t\t} while (\n\t\t\tscale !== ( scale = currentValue() / initial ) && scale !== 1 && --maxIterations\n\t\t);\n\t}\n\n\tif ( valueParts ) {\n\t\tinitialInUnit = +initialInUnit || +initial || 0;\n\n\t\t// Apply relative offset (+=/-=) if specified\n\t\tadjusted = valueParts[ 1 ] ?\n\t\t\tinitialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] :\n\t\t\t+valueParts[ 2 ];\n\t\tif ( tween ) {\n\t\t\ttween.unit = unit;\n\t\t\ttween.start = initialInUnit;\n\t\t\ttween.end = adjusted;\n\t\t}\n\t}\n\treturn adjusted;\n}\n\n\nvar defaultDisplayMap = {};\n\nfunction getDefaultDisplay( elem ) {\n\tvar temp,\n\t\tdoc = elem.ownerDocument,\n\t\tnodeName = elem.nodeName,\n\t\tdisplay = defaultDisplayMap[ nodeName ];\n\n\tif ( display ) {\n\t\treturn display;\n\t}\n\n\ttemp = doc.body.appendChild( doc.createElement( nodeName ) );\n\tdisplay = jQuery.css( temp, \"display\" );\n\n\ttemp.parentNode.removeChild( temp );\n\n\tif ( display === \"none\" ) {\n\t\tdisplay = \"block\";\n\t}\n\tdefaultDisplayMap[ nodeName ] = display;\n\n\treturn display;\n}\n\nfunction showHide( elements, show ) {\n\tvar display, elem,\n\t\tvalues = [],\n\t\tindex = 0,\n\t\tlength = elements.length;\n\n\t// Determine new display value for elements that need to change\n\tfor ( ; index < length; index++ ) {\n\t\telem = elements[ index ];\n\t\tif ( !elem.style ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tdisplay = elem.style.display;\n\t\tif ( show ) {\n\n\t\t\t// Since we force visibility upon cascade-hidden elements, an immediate (and slow)\n\t\t\t// check is required in this first loop unless we have a nonempty display value (either\n\t\t\t// inline or about-to-be-restored)\n\t\t\tif ( display === \"none\" ) {\n\t\t\t\tvalues[ index ] = dataPriv.get( elem, \"display\" ) || null;\n\t\t\t\tif ( !values[ index ] ) {\n\t\t\t\t\telem.style.display = \"\";\n\t\t\t\t}\n\t\t\t}\n\t\t\tif ( elem.style.display === \"\" && isHiddenWithinTree( elem ) ) {\n\t\t\t\tvalues[ index ] = getDefaultDisplay( elem );\n\t\t\t}\n\t\t} else {\n\t\t\tif ( display !== \"none\" ) {\n\t\t\t\tvalues[ index ] = \"none\";\n\n\t\t\t\t// Remember what we're overwriting\n\t\t\t\tdataPriv.set( elem, \"display\", display );\n\t\t\t}\n\t\t}\n\t}\n\n\t// Set the display of the elements in a second loop to avoid constant reflow\n\tfor ( index = 0; index < length; index++ ) {\n\t\tif ( values[ index ] != null ) {\n\t\t\telements[ index ].style.display = values[ index ];\n\t\t}\n\t}\n\n\treturn elements;\n}\n\njQuery.fn.extend( {\n\tshow: function() {\n\t\treturn showHide( this, true );\n\t},\n\thide: function() {\n\t\treturn showHide( this );\n\t},\n\ttoggle: function( state ) {\n\t\tif ( typeof state === \"boolean\" ) {\n\t\t\treturn state ? this.show() : this.hide();\n\t\t}\n\n\t\treturn this.each( function() {\n\t\t\tif ( isHiddenWithinTree( this ) ) {\n\t\t\t\tjQuery( this ).show();\n\t\t\t} else {\n\t\t\t\tjQuery( this ).hide();\n\t\t\t}\n\t\t} );\n\t}\n} );\nvar rcheckableType = ( /^(?:checkbox|radio)$/i );\n\nvar rtagName = ( /<([a-z][^\\/\\0>\\x20\\t\\r\\n\\f]+)/i );\n\nvar rscriptType = ( /^$|\\/(?:java|ecma)script/i );\n\n\n\n// We have to close these tags to support XHTML (#13200)\nvar wrapMap = {\n\n\t// Support: IE <=9 only\n\toption: [ 1, \"<select multiple='multiple'>\", \"</select>\" ],\n\n\t// XHTML parsers do not magically insert elements in the\n\t// same way that tag soup parsers do. So we cannot shorten\n\t// this by omitting <tbody> or other required elements.\n\tthead: [ 1, \"<table>\", \"</table>\" ],\n\tcol: [ 2, \"<table><colgroup>\", \"</colgroup></table>\" ],\n\ttr: [ 2, \"<table><tbody>\", \"</tbody></table>\" ],\n\ttd: [ 3, \"<table><tbody><tr>\", \"</tr></tbody></table>\" ],\n\n\t_default: [ 0, \"\", \"\" ]\n};\n\n// Support: IE <=9 only\nwrapMap.optgroup = wrapMap.option;\n\nwrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;\nwrapMap.th = wrapMap.td;\n\n\nfunction getAll( context, tag ) {\n\n\t// Support: IE <=9 - 11 only\n\t// Use typeof to avoid zero-argument method invocation on host objects (#15151)\n\tvar ret;\n\n\tif ( typeof context.getElementsByTagName !== \"undefined\" ) {\n\t\tret = context.getElementsByTagName( tag || \"*\" );\n\n\t} else if ( typeof context.querySelectorAll !== \"undefined\" ) {\n\t\tret = context.querySelectorAll( tag || \"*\" );\n\n\t} else {\n\t\tret = [];\n\t}\n\n\tif ( tag === undefined || tag && nodeName( context, tag ) ) {\n\t\treturn jQuery.merge( [ context ], ret );\n\t}\n\n\treturn ret;\n}\n\n\n// Mark scripts as having already been evaluated\nfunction setGlobalEval( elems, refElements ) {\n\tvar i = 0,\n\t\tl = elems.length;\n\n\tfor ( ; i < l; i++ ) {\n\t\tdataPriv.set(\n\t\t\telems[ i ],\n\t\t\t\"globalEval\",\n\t\t\t!refElements || dataPriv.get( refElements[ i ], \"globalEval\" )\n\t\t);\n\t}\n}\n\n\nvar rhtml = /<|&#?\\w+;/;\n\nfunction buildFragment( elems, context, scripts, selection, ignored ) {\n\tvar elem, tmp, tag, wrap, contains, j,\n\t\tfragment = context.createDocumentFragment(),\n\t\tnodes = [],\n\t\ti = 0,\n\t\tl = elems.length;\n\n\tfor ( ; i < l; i++ ) {\n\t\telem = elems[ i ];\n\n\t\tif ( elem || elem === 0 ) {\n\n\t\t\t// Add nodes directly\n\t\t\tif ( jQuery.type( elem ) === \"object\" ) {\n\n\t\t\t\t// Support: Android <=4.0 only, PhantomJS 1 only\n\t\t\t\t// push.apply(_, arraylike) throws on ancient WebKit\n\t\t\t\tjQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );\n\n\t\t\t// Convert non-html into a text node\n\t\t\t} else if ( !rhtml.test( elem ) ) {\n\t\t\t\tnodes.push( context.createTextNode( elem ) );\n\n\t\t\t// Convert html into DOM nodes\n\t\t\t} else {\n\t\t\t\ttmp = tmp || fragment.appendChild( context.createElement( \"div\" ) );\n\n\t\t\t\t// Deserialize a standard representation\n\t\t\t\ttag = ( rtagName.exec( elem ) || [ \"\", \"\" ] )[ 1 ].toLowerCase();\n\t\t\t\twrap = wrapMap[ tag ] || wrapMap._default;\n\t\t\t\ttmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ];\n\n\t\t\t\t// Descend through wrappers to the right content\n\t\t\t\tj = wrap[ 0 ];\n\t\t\t\twhile ( j-- ) {\n\t\t\t\t\ttmp = tmp.lastChild;\n\t\t\t\t}\n\n\t\t\t\t// Support: Android <=4.0 only, PhantomJS 1 only\n\t\t\t\t// push.apply(_, arraylike) throws on ancient WebKit\n\t\t\t\tjQuery.merge( nodes, tmp.childNodes );\n\n\t\t\t\t// Remember the top-level container\n\t\t\t\ttmp = fragment.firstChild;\n\n\t\t\t\t// Ensure the created nodes are orphaned (#12392)\n\t\t\t\ttmp.textContent = \"\";\n\t\t\t}\n\t\t}\n\t}\n\n\t// Remove wrapper from fragment\n\tfragment.textContent = \"\";\n\n\ti = 0;\n\twhile ( ( elem = nodes[ i++ ] ) ) {\n\n\t\t// Skip elements already in the context collection (trac-4087)\n\t\tif ( selection && jQuery.inArray( elem, selection ) > -1 ) {\n\t\t\tif ( ignored ) {\n\t\t\t\tignored.push( elem );\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tcontains = jQuery.contains( elem.ownerDocument, elem );\n\n\t\t// Append to fragment\n\t\ttmp = getAll( fragment.appendChild( elem ), \"script\" );\n\n\t\t// Preserve script evaluation history\n\t\tif ( contains ) {\n\t\t\tsetGlobalEval( tmp );\n\t\t}\n\n\t\t// Capture executables\n\t\tif ( scripts ) {\n\t\t\tj = 0;\n\t\t\twhile ( ( elem = tmp[ j++ ] ) ) {\n\t\t\t\tif ( rscriptType.test( elem.type || \"\" ) ) {\n\t\t\t\t\tscripts.push( elem );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn fragment;\n}\n\n\n( function() {\n\tvar fragment = document.createDocumentFragment(),\n\t\tdiv = fragment.appendChild( document.createElement( \"div\" ) ),\n\t\tinput = document.createElement( \"input\" );\n\n\t// Support: Android 4.0 - 4.3 only\n\t// Check state lost if the name is set (#11217)\n\t// Support: Windows Web Apps (WWA)\n\t// `name` and `type` must use .setAttribute for WWA (#14901)\n\tinput.setAttribute( \"type\", \"radio\" );\n\tinput.setAttribute( \"checked\", \"checked\" );\n\tinput.setAttribute( \"name\", \"t\" );\n\n\tdiv.appendChild( input );\n\n\t// Support: Android <=4.1 only\n\t// Older WebKit doesn't clone checked state correctly in fragments\n\tsupport.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked;\n\n\t// Support: IE <=11 only\n\t// Make sure textarea (and checkbox) defaultValue is properly cloned\n\tdiv.innerHTML = \"<textarea>x</textarea>\";\n\tsupport.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue;\n} )();\nvar documentElement = document.documentElement;\n\n\n\nvar\n\trkeyEvent = /^key/,\n\trmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/,\n\trtypenamespace = /^([^.]*)(?:\\.(.+)|)/;\n\nfunction returnTrue() {\n\treturn true;\n}\n\nfunction returnFalse() {\n\treturn false;\n}\n\n// Support: IE <=9 only\n// See #13393 for more info\nfunction safeActiveElement() {\n\ttry {\n\t\treturn document.activeElement;\n\t} catch ( err ) { }\n}\n\nfunction on( elem, types, selector, data, fn, one ) {\n\tvar origFn, type;\n\n\t// Types can be a map of types/handlers\n\tif ( typeof types === \"object\" ) {\n\n\t\t// ( types-Object, selector, data )\n\t\tif ( typeof selector !== \"string\" ) {\n\n\t\t\t// ( types-Object, data )\n\t\t\tdata = data || selector;\n\t\t\tselector = undefined;\n\t\t}\n\t\tfor ( type in types ) {\n\t\t\ton( elem, type, selector, data, types[ type ], one );\n\t\t}\n\t\treturn elem;\n\t}\n\n\tif ( data == null && fn == null ) {\n\n\t\t// ( types, fn )\n\t\tfn = selector;\n\t\tdata = selector = undefined;\n\t} else if ( fn == null ) {\n\t\tif ( typeof selector === \"string\" ) {\n\n\t\t\t// ( types, selector, fn )\n\t\t\tfn = data;\n\t\t\tdata = undefined;\n\t\t} else {\n\n\t\t\t// ( types, data, fn )\n\t\t\tfn = data;\n\t\t\tdata = selector;\n\t\t\tselector = undefined;\n\t\t}\n\t}\n\tif ( fn === false ) {\n\t\tfn = returnFalse;\n\t} else if ( !fn ) {\n\t\treturn elem;\n\t}\n\n\tif ( one === 1 ) {\n\t\torigFn = fn;\n\t\tfn = function( event ) {\n\n\t\t\t// Can use an empty set, since event contains the info\n\t\t\tjQuery().off( event );\n\t\t\treturn origFn.apply( this, arguments );\n\t\t};\n\n\t\t// Use same guid so caller can remove using origFn\n\t\tfn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );\n\t}\n\treturn elem.each( function() {\n\t\tjQuery.event.add( this, types, fn, data, selector );\n\t} );\n}\n\n/*\n * Helper functions for managing events -- not part of the public interface.\n * Props to Dean Edwards' addEvent library for many of the ideas.\n */\njQuery.event = {\n\n\tglobal: {},\n\n\tadd: function( elem, types, handler, data, selector ) {\n\n\t\tvar handleObjIn, eventHandle, tmp,\n\t\t\tevents, t, handleObj,\n\t\t\tspecial, handlers, type, namespaces, origType,\n\t\t\telemData = dataPriv.get( elem );\n\n\t\t// Don't attach events to noData or text/comment nodes (but allow plain objects)\n\t\tif ( !elemData ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Caller can pass in an object of custom data in lieu of the handler\n\t\tif ( handler.handler ) {\n\t\t\thandleObjIn = handler;\n\t\t\thandler = handleObjIn.handler;\n\t\t\tselector = handleObjIn.selector;\n\t\t}\n\n\t\t// Ensure that invalid selectors throw exceptions at attach time\n\t\t// Evaluate against documentElement in case elem is a non-element node (e.g., document)\n\t\tif ( selector ) {\n\t\t\tjQuery.find.matchesSelector( documentElement, selector );\n\t\t}\n\n\t\t// Make sure that the handler has a unique ID, used to find/remove it later\n\t\tif ( !handler.guid ) {\n\t\t\thandler.guid = jQuery.guid++;\n\t\t}\n\n\t\t// Init the element's event structure and main handler, if this is the first\n\t\tif ( !( events = elemData.events ) ) {\n\t\t\tevents = elemData.events = {};\n\t\t}\n\t\tif ( !( eventHandle = elemData.handle ) ) {\n\t\t\teventHandle = elemData.handle = function( e ) {\n\n\t\t\t\t// Discard the second event of a jQuery.event.trigger() and\n\t\t\t\t// when an event is called after a page has unloaded\n\t\t\t\treturn typeof jQuery !== \"undefined\" && jQuery.event.triggered !== e.type ?\n\t\t\t\t\tjQuery.event.dispatch.apply( elem, arguments ) : undefined;\n\t\t\t};\n\t\t}\n\n\t\t// Handle multiple events separated by a space\n\t\ttypes = ( types || \"\" ).match( rnothtmlwhite ) || [ \"\" ];\n\t\tt = types.length;\n\t\twhile ( t-- ) {\n\t\t\ttmp = rtypenamespace.exec( types[ t ] ) || [];\n\t\t\ttype = origType = tmp[ 1 ];\n\t\t\tnamespaces = ( tmp[ 2 ] || \"\" ).split( \".\" ).sort();\n\n\t\t\t// There *must* be a type, no attaching namespace-only handlers\n\t\t\tif ( !type ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// If event changes its type, use the special event handlers for the changed type\n\t\t\tspecial = jQuery.event.special[ type ] || {};\n\n\t\t\t// If selector defined, determine special event api type, otherwise given type\n\t\t\ttype = ( selector ? special.delegateType : special.bindType ) || type;\n\n\t\t\t// Update special based on newly reset type\n\t\t\tspecial = jQuery.event.special[ type ] || {};\n\n\t\t\t// handleObj is passed to all event handlers\n\t\t\thandleObj = jQuery.extend( {\n\t\t\t\ttype: type,\n\t\t\t\torigType: origType,\n\t\t\t\tdata: data,\n\t\t\t\thandler: handler,\n\t\t\t\tguid: handler.guid,\n\t\t\t\tselector: selector,\n\t\t\t\tneedsContext: selector && jQuery.expr.match.needsContext.test( selector ),\n\t\t\t\tnamespace: namespaces.join( \".\" )\n\t\t\t}, handleObjIn );\n\n\t\t\t// Init the event handler queue if we're the first\n\t\t\tif ( !( handlers = events[ type ] ) ) {\n\t\t\t\thandlers = events[ type ] = [];\n\t\t\t\thandlers.delegateCount = 0;\n\n\t\t\t\t// Only use addEventListener if the special events handler returns false\n\t\t\t\tif ( !special.setup ||\n\t\t\t\t\tspecial.setup.call( elem, data, namespaces, eventHandle ) === false ) {\n\n\t\t\t\t\tif ( elem.addEventListener ) {\n\t\t\t\t\t\telem.addEventListener( type, eventHandle );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( special.add ) {\n\t\t\t\tspecial.add.call( elem, handleObj );\n\n\t\t\t\tif ( !handleObj.handler.guid ) {\n\t\t\t\t\thandleObj.handler.guid = handler.guid;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Add to the element's handler list, delegates in front\n\t\t\tif ( selector ) {\n\t\t\t\thandlers.splice( handlers.delegateCount++, 0, handleObj );\n\t\t\t} else {\n\t\t\t\thandlers.push( handleObj );\n\t\t\t}\n\n\t\t\t// Keep track of which events have ever been used, for event optimization\n\t\t\tjQuery.event.global[ type ] = true;\n\t\t}\n\n\t},\n\n\t// Detach an event or set of events from an element\n\tremove: function( elem, types, handler, selector, mappedTypes ) {\n\n\t\tvar j, origCount, tmp,\n\t\t\tevents, t, handleObj,\n\t\t\tspecial, handlers, type, namespaces, origType,\n\t\t\telemData = dataPriv.hasData( elem ) && dataPriv.get( elem );\n\n\t\tif ( !elemData || !( events = elemData.events ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Once for each type.namespace in types; type may be omitted\n\t\ttypes = ( types || \"\" ).match( rnothtmlwhite ) || [ \"\" ];\n\t\tt = types.length;\n\t\twhile ( t-- ) {\n\t\t\ttmp = rtypenamespace.exec( types[ t ] ) || [];\n\t\t\ttype = origType = tmp[ 1 ];\n\t\t\tnamespaces = ( tmp[ 2 ] || \"\" ).split( \".\" ).sort();\n\n\t\t\t// Unbind all events (on this namespace, if provided) for the element\n\t\t\tif ( !type ) {\n\t\t\t\tfor ( type in events ) {\n\t\t\t\t\tjQuery.event.remove( elem, type + types[ t ], handler, selector, true );\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tspecial = jQuery.event.special[ type ] || {};\n\t\t\ttype = ( selector ? special.delegateType : special.bindType ) || type;\n\t\t\thandlers = events[ type ] || [];\n\t\t\ttmp = tmp[ 2 ] &&\n\t\t\t\tnew RegExp( \"(^|\\\\.)\" + namespaces.join( \"\\\\.(?:.*\\\\.|)\" ) + \"(\\\\.|$)\" );\n\n\t\t\t// Remove matching events\n\t\t\torigCount = j = handlers.length;\n\t\t\twhile ( j-- ) {\n\t\t\t\thandleObj = handlers[ j ];\n\n\t\t\t\tif ( ( mappedTypes || origType === handleObj.origType ) &&\n\t\t\t\t\t( !handler || handler.guid === handleObj.guid ) &&\n\t\t\t\t\t( !tmp || tmp.test( handleObj.namespace ) ) &&\n\t\t\t\t\t( !selector || selector === handleObj.selector ||\n\t\t\t\t\t\tselector === \"**\" && handleObj.selector ) ) {\n\t\t\t\t\thandlers.splice( j, 1 );\n\n\t\t\t\t\tif ( handleObj.selector ) {\n\t\t\t\t\t\thandlers.delegateCount--;\n\t\t\t\t\t}\n\t\t\t\t\tif ( special.remove ) {\n\t\t\t\t\t\tspecial.remove.call( elem, handleObj );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Remove generic event handler if we removed something and no more handlers exist\n\t\t\t// (avoids potential for endless recursion during removal of special event handlers)\n\t\t\tif ( origCount && !handlers.length ) {\n\t\t\t\tif ( !special.teardown ||\n\t\t\t\t\tspecial.teardown.call( elem, namespaces, elemData.handle ) === false ) {\n\n\t\t\t\t\tjQuery.removeEvent( elem, type, elemData.handle );\n\t\t\t\t}\n\n\t\t\t\tdelete events[ type ];\n\t\t\t}\n\t\t}\n\n\t\t// Remove data and the expando if it's no longer used\n\t\tif ( jQuery.isEmptyObject( events ) ) {\n\t\t\tdataPriv.remove( elem, \"handle events\" );\n\t\t}\n\t},\n\n\tdispatch: function( nativeEvent ) {\n\n\t\t// Make a writable jQuery.Event from the native event object\n\t\tvar event = jQuery.event.fix( nativeEvent );\n\n\t\tvar i, j, ret, matched, handleObj, handlerQueue,\n\t\t\targs = new Array( arguments.length ),\n\t\t\thandlers = ( dataPriv.get( this, \"events\" ) || {} )[ event.type ] || [],\n\t\t\tspecial = jQuery.event.special[ event.type ] || {};\n\n\t\t// Use the fix-ed jQuery.Event rather than the (read-only) native event\n\t\targs[ 0 ] = event;\n\n\t\tfor ( i = 1; i < arguments.length; i++ ) {\n\t\t\targs[ i ] = arguments[ i ];\n\t\t}\n\n\t\tevent.delegateTarget = this;\n\n\t\t// Call the preDispatch hook for the mapped type, and let it bail if desired\n\t\tif ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Determine handlers\n\t\thandlerQueue = jQuery.event.handlers.call( this, event, handlers );\n\n\t\t// Run delegates first; they may want to stop propagation beneath us\n\t\ti = 0;\n\t\twhile ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) {\n\t\t\tevent.currentTarget = matched.elem;\n\n\t\t\tj = 0;\n\t\t\twhile ( ( handleObj = matched.handlers[ j++ ] ) &&\n\t\t\t\t!event.isImmediatePropagationStopped() ) {\n\n\t\t\t\t// Triggered event must either 1) have no namespace, or 2) have namespace(s)\n\t\t\t\t// a subset or equal to those in the bound event (both can have no namespace).\n\t\t\t\tif ( !event.rnamespace || event.rnamespace.test( handleObj.namespace ) ) {\n\n\t\t\t\t\tevent.handleObj = handleObj;\n\t\t\t\t\tevent.data = handleObj.data;\n\n\t\t\t\t\tret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle ||\n\t\t\t\t\t\thandleObj.handler ).apply( matched.elem, args );\n\n\t\t\t\t\tif ( ret !== undefined ) {\n\t\t\t\t\t\tif ( ( event.result = ret ) === false ) {\n\t\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\t\tevent.stopPropagation();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Call the postDispatch hook for the mapped type\n\t\tif ( special.postDispatch ) {\n\t\t\tspecial.postDispatch.call( this, event );\n\t\t}\n\n\t\treturn event.result;\n\t},\n\n\thandlers: function( event, handlers ) {\n\t\tvar i, handleObj, sel, matchedHandlers, matchedSelectors,\n\t\t\thandlerQueue = [],\n\t\t\tdelegateCount = handlers.delegateCount,\n\t\t\tcur = event.target;\n\n\t\t// Find delegate handlers\n\t\tif ( delegateCount &&\n\n\t\t\t// Support: IE <=9\n\t\t\t// Black-hole SVG <use> instance trees (trac-13180)\n\t\t\tcur.nodeType &&\n\n\t\t\t// Support: Firefox <=42\n\t\t\t// Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861)\n\t\t\t// https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click\n\t\t\t// Support: IE 11 only\n\t\t\t// ...but not arrow key \"clicks\" of radio inputs, which can have `button` -1 (gh-2343)\n\t\t\t!( event.type === \"click\" && event.button >= 1 ) ) {\n\n\t\t\tfor ( ; cur !== this; cur = cur.parentNode || this ) {\n\n\t\t\t\t// Don't check non-elements (#13208)\n\t\t\t\t// Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)\n\t\t\t\tif ( cur.nodeType === 1 && !( event.type === \"click\" && cur.disabled === true ) ) {\n\t\t\t\t\tmatchedHandlers = [];\n\t\t\t\t\tmatchedSelectors = {};\n\t\t\t\t\tfor ( i = 0; i < delegateCount; i++ ) {\n\t\t\t\t\t\thandleObj = handlers[ i ];\n\n\t\t\t\t\t\t// Don't conflict with Object.prototype properties (#13203)\n\t\t\t\t\t\tsel = handleObj.selector + \" \";\n\n\t\t\t\t\t\tif ( matchedSelectors[ sel ] === undefined ) {\n\t\t\t\t\t\t\tmatchedSelectors[ sel ] = handleObj.needsContext ?\n\t\t\t\t\t\t\t\tjQuery( sel, this ).index( cur ) > -1 :\n\t\t\t\t\t\t\t\tjQuery.find( sel, this, null, [ cur ] ).length;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif ( matchedSelectors[ sel ] ) {\n\t\t\t\t\t\t\tmatchedHandlers.push( handleObj );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif ( matchedHandlers.length ) {\n\t\t\t\t\t\thandlerQueue.push( { elem: cur, handlers: matchedHandlers } );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Add the remaining (directly-bound) handlers\n\t\tcur = this;\n\t\tif ( delegateCount < handlers.length ) {\n\t\t\thandlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } );\n\t\t}\n\n\t\treturn handlerQueue;\n\t},\n\n\taddProp: function( name, hook ) {\n\t\tObject.defineProperty( jQuery.Event.prototype, name, {\n\t\t\tenumerable: true,\n\t\t\tconfigurable: true,\n\n\t\t\tget: jQuery.isFunction( hook ) ?\n\t\t\t\tfunction() {\n\t\t\t\t\tif ( this.originalEvent ) {\n\t\t\t\t\t\t\treturn hook( this.originalEvent );\n\t\t\t\t\t}\n\t\t\t\t} :\n\t\t\t\tfunction() {\n\t\t\t\t\tif ( this.originalEvent ) {\n\t\t\t\t\t\t\treturn this.originalEvent[ name ];\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\tset: function( value ) {\n\t\t\t\tObject.defineProperty( this, name, {\n\t\t\t\t\tenumerable: true,\n\t\t\t\t\tconfigurable: true,\n\t\t\t\t\twritable: true,\n\t\t\t\t\tvalue: value\n\t\t\t\t} );\n\t\t\t}\n\t\t} );\n\t},\n\n\tfix: function( originalEvent ) {\n\t\treturn originalEvent[ jQuery.expando ] ?\n\t\t\toriginalEvent :\n\t\t\tnew jQuery.Event( originalEvent );\n\t},\n\n\tspecial: {\n\t\tload: {\n\n\t\t\t// Prevent triggered image.load events from bubbling to window.load\n\t\t\tnoBubble: true\n\t\t},\n\t\tfocus: {\n\n\t\t\t// Fire native event if possible so blur/focus sequence is correct\n\t\t\ttrigger: function() {\n\t\t\t\tif ( this !== safeActiveElement() && this.focus ) {\n\t\t\t\t\tthis.focus();\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t},\n\t\t\tdelegateType: \"focusin\"\n\t\t},\n\t\tblur: {\n\t\t\ttrigger: function() {\n\t\t\t\tif ( this === safeActiveElement() && this.blur ) {\n\t\t\t\t\tthis.blur();\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t},\n\t\t\tdelegateType: \"focusout\"\n\t\t},\n\t\tclick: {\n\n\t\t\t// For checkbox, fire native event so checked state will be right\n\t\t\ttrigger: function() {\n\t\t\t\tif ( this.type === \"checkbox\" && this.click && nodeName( this, \"input\" ) ) {\n\t\t\t\t\tthis.click();\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t},\n\n\t\t\t// For cross-browser consistency, don't fire native .click() on links\n\t\t\t_default: function( event ) {\n\t\t\t\treturn nodeName( event.target, \"a\" );\n\t\t\t}\n\t\t},\n\n\t\tbeforeunload: {\n\t\t\tpostDispatch: function( event ) {\n\n\t\t\t\t// Support: Firefox 20+\n\t\t\t\t// Firefox doesn't alert if the returnValue field is not set.\n\t\t\t\tif ( event.result !== undefined && event.originalEvent ) {\n\t\t\t\t\tevent.originalEvent.returnValue = event.result;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n};\n\njQuery.removeEvent = function( elem, type, handle ) {\n\n\t// This \"if\" is needed for plain objects\n\tif ( elem.removeEventListener ) {\n\t\telem.removeEventListener( type, handle );\n\t}\n};\n\njQuery.Event = function( src, props ) {\n\n\t// Allow instantiation without the 'new' keyword\n\tif ( !( this instanceof jQuery.Event ) ) {\n\t\treturn new jQuery.Event( src, props );\n\t}\n\n\t// Event object\n\tif ( src && src.type ) {\n\t\tthis.originalEvent = src;\n\t\tthis.type = src.type;\n\n\t\t// Events bubbling up the document may have been marked as prevented\n\t\t// by a handler lower down the tree; reflect the correct value.\n\t\tthis.isDefaultPrevented = src.defaultPrevented ||\n\t\t\t\tsrc.defaultPrevented === undefined &&\n\n\t\t\t\t// Support: Android <=2.3 only\n\t\t\t\tsrc.returnValue === false ?\n\t\t\treturnTrue :\n\t\t\treturnFalse;\n\n\t\t// Create target properties\n\t\t// Support: Safari <=6 - 7 only\n\t\t// Target should not be a text node (#504, #13143)\n\t\tthis.target = ( src.target && src.target.nodeType === 3 ) ?\n\t\t\tsrc.target.parentNode :\n\t\t\tsrc.target;\n\n\t\tthis.currentTarget = src.currentTarget;\n\t\tthis.relatedTarget = src.relatedTarget;\n\n\t// Event type\n\t} else {\n\t\tthis.type = src;\n\t}\n\n\t// Put explicitly provided properties onto the event object\n\tif ( props ) {\n\t\tjQuery.extend( this, props );\n\t}\n\n\t// Create a timestamp if incoming event doesn't have one\n\tthis.timeStamp = src && src.timeStamp || jQuery.now();\n\n\t// Mark it as fixed\n\tthis[ jQuery.expando ] = true;\n};\n\n// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding\n// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html\njQuery.Event.prototype = {\n\tconstructor: jQuery.Event,\n\tisDefaultPrevented: returnFalse,\n\tisPropagationStopped: returnFalse,\n\tisImmediatePropagationStopped: returnFalse,\n\tisSimulated: false,\n\n\tpreventDefault: function() {\n\t\tvar e = this.originalEvent;\n\n\t\tthis.isDefaultPrevented = returnTrue;\n\n\t\tif ( e && !this.isSimulated ) {\n\t\t\te.preventDefault();\n\t\t}\n\t},\n\tstopPropagation: function() {\n\t\tvar e = this.originalEvent;\n\n\t\tthis.isPropagationStopped = returnTrue;\n\n\t\tif ( e && !this.isSimulated ) {\n\t\t\te.stopPropagation();\n\t\t}\n\t},\n\tstopImmediatePropagation: function() {\n\t\tvar e = this.originalEvent;\n\n\t\tthis.isImmediatePropagationStopped = returnTrue;\n\n\t\tif ( e && !this.isSimulated ) {\n\t\t\te.stopImmediatePropagation();\n\t\t}\n\n\t\tthis.stopPropagation();\n\t}\n};\n\n// Includes all common event props including KeyEvent and MouseEvent specific props\njQuery.each( {\n\taltKey: true,\n\tbubbles: true,\n\tcancelable: true,\n\tchangedTouches: true,\n\tctrlKey: true,\n\tdetail: true,\n\teventPhase: true,\n\tmetaKey: true,\n\tpageX: true,\n\tpageY: true,\n\tshiftKey: true,\n\tview: true,\n\t\"char\": true,\n\tcharCode: true,\n\tkey: true,\n\tkeyCode: true,\n\tbutton: true,\n\tbuttons: true,\n\tclientX: true,\n\tclientY: true,\n\toffsetX: true,\n\toffsetY: true,\n\tpointerId: true,\n\tpointerType: true,\n\tscreenX: true,\n\tscreenY: true,\n\ttargetTouches: true,\n\ttoElement: true,\n\ttouches: true,\n\n\twhich: function( event ) {\n\t\tvar button = event.button;\n\n\t\t// Add which for key events\n\t\tif ( event.which == null && rkeyEvent.test( event.type ) ) {\n\t\t\treturn event.charCode != null ? event.charCode : event.keyCode;\n\t\t}\n\n\t\t// Add which for click: 1 === left; 2 === middle; 3 === right\n\t\tif ( !event.which && button !== undefined && rmouseEvent.test( event.type ) ) {\n\t\t\tif ( button & 1 ) {\n\t\t\t\treturn 1;\n\t\t\t}\n\n\t\t\tif ( button & 2 ) {\n\t\t\t\treturn 3;\n\t\t\t}\n\n\t\t\tif ( button & 4 ) {\n\t\t\t\treturn 2;\n\t\t\t}\n\n\t\t\treturn 0;\n\t\t}\n\n\t\treturn event.which;\n\t}\n}, jQuery.event.addProp );\n\n// Create mouseenter/leave events using mouseover/out and event-time checks\n// so that event delegation works in jQuery.\n// Do the same for pointerenter/pointerleave and pointerover/pointerout\n//\n// Support: Safari 7 only\n// Safari sends mouseenter too often; see:\n// https://bugs.chromium.org/p/chromium/issues/detail?id=470258\n// for the description of the bug (it existed in older Chrome versions as well).\njQuery.each( {\n\tmouseenter: \"mouseover\",\n\tmouseleave: \"mouseout\",\n\tpointerenter: \"pointerover\",\n\tpointerleave: \"pointerout\"\n}, function( orig, fix ) {\n\tjQuery.event.special[ orig ] = {\n\t\tdelegateType: fix,\n\t\tbindType: fix,\n\n\t\thandle: function( event ) {\n\t\t\tvar ret,\n\t\t\t\ttarget = this,\n\t\t\t\trelated = event.relatedTarget,\n\t\t\t\thandleObj = event.handleObj;\n\n\t\t\t// For mouseenter/leave call the handler if related is outside the target.\n\t\t\t// NB: No relatedTarget if the mouse left/entered the browser window\n\t\t\tif ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) {\n\t\t\t\tevent.type = handleObj.origType;\n\t\t\t\tret = handleObj.handler.apply( this, arguments );\n\t\t\t\tevent.type = fix;\n\t\t\t}\n\t\t\treturn ret;\n\t\t}\n\t};\n} );\n\njQuery.fn.extend( {\n\n\ton: function( types, selector, data, fn ) {\n\t\treturn on( this, types, selector, data, fn );\n\t},\n\tone: function( types, selector, data, fn ) {\n\t\treturn on( this, types, selector, data, fn, 1 );\n\t},\n\toff: function( types, selector, fn ) {\n\t\tvar handleObj, type;\n\t\tif ( types && types.preventDefault && types.handleObj ) {\n\n\t\t\t// ( event )  dispatched jQuery.Event\n\t\t\thandleObj = types.handleObj;\n\t\t\tjQuery( types.delegateTarget ).off(\n\t\t\t\thandleObj.namespace ?\n\t\t\t\t\thandleObj.origType + \".\" + handleObj.namespace :\n\t\t\t\t\thandleObj.origType,\n\t\t\t\thandleObj.selector,\n\t\t\t\thandleObj.handler\n\t\t\t);\n\t\t\treturn this;\n\t\t}\n\t\tif ( typeof types === \"object\" ) {\n\n\t\t\t// ( types-object [, selector] )\n\t\t\tfor ( type in types ) {\n\t\t\t\tthis.off( type, selector, types[ type ] );\n\t\t\t}\n\t\t\treturn this;\n\t\t}\n\t\tif ( selector === false || typeof selector === \"function\" ) {\n\n\t\t\t// ( types [, fn] )\n\t\t\tfn = selector;\n\t\t\tselector = undefined;\n\t\t}\n\t\tif ( fn === false ) {\n\t\t\tfn = returnFalse;\n\t\t}\n\t\treturn this.each( function() {\n\t\t\tjQuery.event.remove( this, types, fn, selector );\n\t\t} );\n\t}\n} );\n\n\nvar\n\n\t/* eslint-disable max-len */\n\n\t// See https://github.com/eslint/eslint/issues/3229\n\trxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\\/\\0>\\x20\\t\\r\\n\\f]*)[^>]*)\\/>/gi,\n\n\t/* eslint-enable */\n\n\t// Support: IE <=10 - 11, Edge 12 - 13\n\t// In IE/Edge using regex groups here causes severe slowdowns.\n\t// See https://connect.microsoft.com/IE/feedback/details/1736512/\n\trnoInnerhtml = /<script|<style|<link/i,\n\n\t// checked=\"checked\" or checked\n\trchecked = /checked\\s*(?:[^=]|=\\s*.checked.)/i,\n\trscriptTypeMasked = /^true\\/(.*)/,\n\trcleanScript = /^\\s*<!(?:\\[CDATA\\[|--)|(?:\\]\\]|--)>\\s*$/g;\n\n// Prefer a tbody over its parent table for containing new rows\nfunction manipulationTarget( elem, content ) {\n\tif ( nodeName( elem, \"table\" ) &&\n\t\tnodeName( content.nodeType !== 11 ? content : content.firstChild, \"tr\" ) ) {\n\n\t\treturn jQuery( \">tbody\", elem )[ 0 ] || elem;\n\t}\n\n\treturn elem;\n}\n\n// Replace/restore the type attribute of script elements for safe DOM manipulation\nfunction disableScript( elem ) {\n\telem.type = ( elem.getAttribute( \"type\" ) !== null ) + \"/\" + elem.type;\n\treturn elem;\n}\nfunction restoreScript( elem ) {\n\tvar match = rscriptTypeMasked.exec( elem.type );\n\n\tif ( match ) {\n\t\telem.type = match[ 1 ];\n\t} else {\n\t\telem.removeAttribute( \"type\" );\n\t}\n\n\treturn elem;\n}\n\nfunction cloneCopyEvent( src, dest ) {\n\tvar i, l, type, pdataOld, pdataCur, udataOld, udataCur, events;\n\n\tif ( dest.nodeType !== 1 ) {\n\t\treturn;\n\t}\n\n\t// 1. Copy private data: events, handlers, etc.\n\tif ( dataPriv.hasData( src ) ) {\n\t\tpdataOld = dataPriv.access( src );\n\t\tpdataCur = dataPriv.set( dest, pdataOld );\n\t\tevents = pdataOld.events;\n\n\t\tif ( events ) {\n\t\t\tdelete pdataCur.handle;\n\t\t\tpdataCur.events = {};\n\n\t\t\tfor ( type in events ) {\n\t\t\t\tfor ( i = 0, l = events[ type ].length; i < l; i++ ) {\n\t\t\t\t\tjQuery.event.add( dest, type, events[ type ][ i ] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// 2. Copy user data\n\tif ( dataUser.hasData( src ) ) {\n\t\tudataOld = dataUser.access( src );\n\t\tudataCur = jQuery.extend( {}, udataOld );\n\n\t\tdataUser.set( dest, udataCur );\n\t}\n}\n\n// Fix IE bugs, see support tests\nfunction fixInput( src, dest ) {\n\tvar nodeName = dest.nodeName.toLowerCase();\n\n\t// Fails to persist the checked state of a cloned checkbox or radio button.\n\tif ( nodeName === \"input\" && rcheckableType.test( src.type ) ) {\n\t\tdest.checked = src.checked;\n\n\t// Fails to return the selected option to the default selected state when cloning options\n\t} else if ( nodeName === \"input\" || nodeName === \"textarea\" ) {\n\t\tdest.defaultValue = src.defaultValue;\n\t}\n}\n\nfunction domManip( collection, args, callback, ignored ) {\n\n\t// Flatten any nested arrays\n\targs = concat.apply( [], args );\n\n\tvar fragment, first, scripts, hasScripts, node, doc,\n\t\ti = 0,\n\t\tl = collection.length,\n\t\tiNoClone = l - 1,\n\t\tvalue = args[ 0 ],\n\t\tisFunction = jQuery.isFunction( value );\n\n\t// We can't cloneNode fragments that contain checked, in WebKit\n\tif ( isFunction ||\n\t\t\t( l > 1 && typeof value === \"string\" &&\n\t\t\t\t!support.checkClone && rchecked.test( value ) ) ) {\n\t\treturn collection.each( function( index ) {\n\t\t\tvar self = collection.eq( index );\n\t\t\tif ( isFunction ) {\n\t\t\t\targs[ 0 ] = value.call( this, index, self.html() );\n\t\t\t}\n\t\t\tdomManip( self, args, callback, ignored );\n\t\t} );\n\t}\n\n\tif ( l ) {\n\t\tfragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored );\n\t\tfirst = fragment.firstChild;\n\n\t\tif ( fragment.childNodes.length === 1 ) {\n\t\t\tfragment = first;\n\t\t}\n\n\t\t// Require either new content or an interest in ignored elements to invoke the callback\n\t\tif ( first || ignored ) {\n\t\t\tscripts = jQuery.map( getAll( fragment, \"script\" ), disableScript );\n\t\t\thasScripts = scripts.length;\n\n\t\t\t// Use the original fragment for the last item\n\t\t\t// instead of the first because it can end up\n\t\t\t// being emptied incorrectly in certain situations (#8070).\n\t\t\tfor ( ; i < l; i++ ) {\n\t\t\t\tnode = fragment;\n\n\t\t\t\tif ( i !== iNoClone ) {\n\t\t\t\t\tnode = jQuery.clone( node, true, true );\n\n\t\t\t\t\t// Keep references to cloned scripts for later restoration\n\t\t\t\t\tif ( hasScripts ) {\n\n\t\t\t\t\t\t// Support: Android <=4.0 only, PhantomJS 1 only\n\t\t\t\t\t\t// push.apply(_, arraylike) throws on ancient WebKit\n\t\t\t\t\t\tjQuery.merge( scripts, getAll( node, \"script\" ) );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tcallback.call( collection[ i ], node, i );\n\t\t\t}\n\n\t\t\tif ( hasScripts ) {\n\t\t\t\tdoc = scripts[ scripts.length - 1 ].ownerDocument;\n\n\t\t\t\t// Reenable scripts\n\t\t\t\tjQuery.map( scripts, restoreScript );\n\n\t\t\t\t// Evaluate executable scripts on first document insertion\n\t\t\t\tfor ( i = 0; i < hasScripts; i++ ) {\n\t\t\t\t\tnode = scripts[ i ];\n\t\t\t\t\tif ( rscriptType.test( node.type || \"\" ) &&\n\t\t\t\t\t\t!dataPriv.access( node, \"globalEval\" ) &&\n\t\t\t\t\t\tjQuery.contains( doc, node ) ) {\n\n\t\t\t\t\t\tif ( node.src ) {\n\n\t\t\t\t\t\t\t// Optional AJAX dependency, but won't run scripts if not present\n\t\t\t\t\t\t\tif ( jQuery._evalUrl ) {\n\t\t\t\t\t\t\t\tjQuery._evalUrl( node.src );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tDOMEval( node.textContent.replace( rcleanScript, \"\" ), doc );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn collection;\n}\n\nfunction remove( elem, selector, keepData ) {\n\tvar node,\n\t\tnodes = selector ? jQuery.filter( selector, elem ) : elem,\n\t\ti = 0;\n\n\tfor ( ; ( node = nodes[ i ] ) != null; i++ ) {\n\t\tif ( !keepData && node.nodeType === 1 ) {\n\t\t\tjQuery.cleanData( getAll( node ) );\n\t\t}\n\n\t\tif ( node.parentNode ) {\n\t\t\tif ( keepData && jQuery.contains( node.ownerDocument, node ) ) {\n\t\t\t\tsetGlobalEval( getAll( node, \"script\" ) );\n\t\t\t}\n\t\t\tnode.parentNode.removeChild( node );\n\t\t}\n\t}\n\n\treturn elem;\n}\n\njQuery.extend( {\n\thtmlPrefilter: function( html ) {\n\t\treturn html.replace( rxhtmlTag, \"<$1></$2>\" );\n\t},\n\n\tclone: function( elem, dataAndEvents, deepDataAndEvents ) {\n\t\tvar i, l, srcElements, destElements,\n\t\t\tclone = elem.cloneNode( true ),\n\t\t\tinPage = jQuery.contains( elem.ownerDocument, elem );\n\n\t\t// Fix IE cloning issues\n\t\tif ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) &&\n\t\t\t\t!jQuery.isXMLDoc( elem ) ) {\n\n\t\t\t// We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2\n\t\t\tdestElements = getAll( clone );\n\t\t\tsrcElements = getAll( elem );\n\n\t\t\tfor ( i = 0, l = srcElements.length; i < l; i++ ) {\n\t\t\t\tfixInput( srcElements[ i ], destElements[ i ] );\n\t\t\t}\n\t\t}\n\n\t\t// Copy the events from the original to the clone\n\t\tif ( dataAndEvents ) {\n\t\t\tif ( deepDataAndEvents ) {\n\t\t\t\tsrcElements = srcElements || getAll( elem );\n\t\t\t\tdestElements = destElements || getAll( clone );\n\n\t\t\t\tfor ( i = 0, l = srcElements.length; i < l; i++ ) {\n\t\t\t\t\tcloneCopyEvent( srcElements[ i ], destElements[ i ] );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tcloneCopyEvent( elem, clone );\n\t\t\t}\n\t\t}\n\n\t\t// Preserve script evaluation history\n\t\tdestElements = getAll( clone, \"script\" );\n\t\tif ( destElements.length > 0 ) {\n\t\t\tsetGlobalEval( destElements, !inPage && getAll( elem, \"script\" ) );\n\t\t}\n\n\t\t// Return the cloned set\n\t\treturn clone;\n\t},\n\n\tcleanData: function( elems ) {\n\t\tvar data, elem, type,\n\t\t\tspecial = jQuery.event.special,\n\t\t\ti = 0;\n\n\t\tfor ( ; ( elem = elems[ i ] ) !== undefined; i++ ) {\n\t\t\tif ( acceptData( elem ) ) {\n\t\t\t\tif ( ( data = elem[ dataPriv.expando ] ) ) {\n\t\t\t\t\tif ( data.events ) {\n\t\t\t\t\t\tfor ( type in data.events ) {\n\t\t\t\t\t\t\tif ( special[ type ] ) {\n\t\t\t\t\t\t\t\tjQuery.event.remove( elem, type );\n\n\t\t\t\t\t\t\t// This is a shortcut to avoid jQuery.event.remove's overhead\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tjQuery.removeEvent( elem, type, data.handle );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Support: Chrome <=35 - 45+\n\t\t\t\t\t// Assign undefined instead of using delete, see Data#remove\n\t\t\t\t\telem[ dataPriv.expando ] = undefined;\n\t\t\t\t}\n\t\t\t\tif ( elem[ dataUser.expando ] ) {\n\n\t\t\t\t\t// Support: Chrome <=35 - 45+\n\t\t\t\t\t// Assign undefined instead of using delete, see Data#remove\n\t\t\t\t\telem[ dataUser.expando ] = undefined;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n} );\n\njQuery.fn.extend( {\n\tdetach: function( selector ) {\n\t\treturn remove( this, selector, true );\n\t},\n\n\tremove: function( selector ) {\n\t\treturn remove( this, selector );\n\t},\n\n\ttext: function( value ) {\n\t\treturn access( this, function( value ) {\n\t\t\treturn value === undefined ?\n\t\t\t\tjQuery.text( this ) :\n\t\t\t\tthis.empty().each( function() {\n\t\t\t\t\tif ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {\n\t\t\t\t\t\tthis.textContent = value;\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t}, null, value, arguments.length );\n\t},\n\n\tappend: function() {\n\t\treturn domManip( this, arguments, function( elem ) {\n\t\t\tif ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {\n\t\t\t\tvar target = manipulationTarget( this, elem );\n\t\t\t\ttarget.appendChild( elem );\n\t\t\t}\n\t\t} );\n\t},\n\n\tprepend: function() {\n\t\treturn domManip( this, arguments, function( elem ) {\n\t\t\tif ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {\n\t\t\t\tvar target = manipulationTarget( this, elem );\n\t\t\t\ttarget.insertBefore( elem, target.firstChild );\n\t\t\t}\n\t\t} );\n\t},\n\n\tbefore: function() {\n\t\treturn domManip( this, arguments, function( elem ) {\n\t\t\tif ( this.parentNode ) {\n\t\t\t\tthis.parentNode.insertBefore( elem, this );\n\t\t\t}\n\t\t} );\n\t},\n\n\tafter: function() {\n\t\treturn domManip( this, arguments, function( elem ) {\n\t\t\tif ( this.parentNode ) {\n\t\t\t\tthis.parentNode.insertBefore( elem, this.nextSibling );\n\t\t\t}\n\t\t} );\n\t},\n\n\tempty: function() {\n\t\tvar elem,\n\t\t\ti = 0;\n\n\t\tfor ( ; ( elem = this[ i ] ) != null; i++ ) {\n\t\t\tif ( elem.nodeType === 1 ) {\n\n\t\t\t\t// Prevent memory leaks\n\t\t\t\tjQuery.cleanData( getAll( elem, false ) );\n\n\t\t\t\t// Remove any remaining nodes\n\t\t\t\telem.textContent = \"\";\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\tclone: function( dataAndEvents, deepDataAndEvents ) {\n\t\tdataAndEvents = dataAndEvents == null ? false : dataAndEvents;\n\t\tdeepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;\n\n\t\treturn this.map( function() {\n\t\t\treturn jQuery.clone( this, dataAndEvents, deepDataAndEvents );\n\t\t} );\n\t},\n\n\thtml: function( value ) {\n\t\treturn access( this, function( value ) {\n\t\t\tvar elem = this[ 0 ] || {},\n\t\t\t\ti = 0,\n\t\t\t\tl = this.length;\n\n\t\t\tif ( value === undefined && elem.nodeType === 1 ) {\n\t\t\t\treturn elem.innerHTML;\n\t\t\t}\n\n\t\t\t// See if we can take a shortcut and just use innerHTML\n\t\t\tif ( typeof value === \"string\" && !rnoInnerhtml.test( value ) &&\n\t\t\t\t!wrapMap[ ( rtagName.exec( value ) || [ \"\", \"\" ] )[ 1 ].toLowerCase() ] ) {\n\n\t\t\t\tvalue = jQuery.htmlPrefilter( value );\n\n\t\t\t\ttry {\n\t\t\t\t\tfor ( ; i < l; i++ ) {\n\t\t\t\t\t\telem = this[ i ] || {};\n\n\t\t\t\t\t\t// Remove element nodes and prevent memory leaks\n\t\t\t\t\t\tif ( elem.nodeType === 1 ) {\n\t\t\t\t\t\t\tjQuery.cleanData( getAll( elem, false ) );\n\t\t\t\t\t\t\telem.innerHTML = value;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\telem = 0;\n\n\t\t\t\t// If using innerHTML throws an exception, use the fallback method\n\t\t\t\t} catch ( e ) {}\n\t\t\t}\n\n\t\t\tif ( elem ) {\n\t\t\t\tthis.empty().append( value );\n\t\t\t}\n\t\t}, null, value, arguments.length );\n\t},\n\n\treplaceWith: function() {\n\t\tvar ignored = [];\n\n\t\t// Make the changes, replacing each non-ignored context element with the new content\n\t\treturn domManip( this, arguments, function( elem ) {\n\t\t\tvar parent = this.parentNode;\n\n\t\t\tif ( jQuery.inArray( this, ignored ) < 0 ) {\n\t\t\t\tjQuery.cleanData( getAll( this ) );\n\t\t\t\tif ( parent ) {\n\t\t\t\t\tparent.replaceChild( elem, this );\n\t\t\t\t}\n\t\t\t}\n\n\t\t// Force callback invocation\n\t\t}, ignored );\n\t}\n} );\n\njQuery.each( {\n\tappendTo: \"append\",\n\tprependTo: \"prepend\",\n\tinsertBefore: \"before\",\n\tinsertAfter: \"after\",\n\treplaceAll: \"replaceWith\"\n}, function( name, original ) {\n\tjQuery.fn[ name ] = function( selector ) {\n\t\tvar elems,\n\t\t\tret = [],\n\t\t\tinsert = jQuery( selector ),\n\t\t\tlast = insert.length - 1,\n\t\t\ti = 0;\n\n\t\tfor ( ; i <= last; i++ ) {\n\t\t\telems = i === last ? this : this.clone( true );\n\t\t\tjQuery( insert[ i ] )[ original ]( elems );\n\n\t\t\t// Support: Android <=4.0 only, PhantomJS 1 only\n\t\t\t// .get() because push.apply(_, arraylike) throws on ancient WebKit\n\t\t\tpush.apply( ret, elems.get() );\n\t\t}\n\n\t\treturn this.pushStack( ret );\n\t};\n} );\nvar rmargin = ( /^margin/ );\n\nvar rnumnonpx = new RegExp( \"^(\" + pnum + \")(?!px)[a-z%]+$\", \"i\" );\n\nvar getStyles = function( elem ) {\n\n\t\t// Support: IE <=11 only, Firefox <=30 (#15098, #14150)\n\t\t// IE throws on elements created in popups\n\t\t// FF meanwhile throws on frame elements through \"defaultView.getComputedStyle\"\n\t\tvar view = elem.ownerDocument.defaultView;\n\n\t\tif ( !view || !view.opener ) {\n\t\t\tview = window;\n\t\t}\n\n\t\treturn view.getComputedStyle( elem );\n\t};\n\n\n\n( function() {\n\n\t// Executing both pixelPosition & boxSizingReliable tests require only one layout\n\t// so they're executed at the same time to save the second computation.\n\tfunction computeStyleTests() {\n\n\t\t// This is a singleton, we need to execute it only once\n\t\tif ( !div ) {\n\t\t\treturn;\n\t\t}\n\n\t\tdiv.style.cssText =\n\t\t\t\"box-sizing:border-box;\" +\n\t\t\t\"position:relative;display:block;\" +\n\t\t\t\"margin:auto;border:1px;padding:1px;\" +\n\t\t\t\"top:1%;width:50%\";\n\t\tdiv.innerHTML = \"\";\n\t\tdocumentElement.appendChild( container );\n\n\t\tvar divStyle = window.getComputedStyle( div );\n\t\tpixelPositionVal = divStyle.top !== \"1%\";\n\n\t\t// Support: Android 4.0 - 4.3 only, Firefox <=3 - 44\n\t\treliableMarginLeftVal = divStyle.marginLeft === \"2px\";\n\t\tboxSizingReliableVal = divStyle.width === \"4px\";\n\n\t\t// Support: Android 4.0 - 4.3 only\n\t\t// Some styles come back with percentage values, even though they shouldn't\n\t\tdiv.style.marginRight = \"50%\";\n\t\tpixelMarginRightVal = divStyle.marginRight === \"4px\";\n\n\t\tdocumentElement.removeChild( container );\n\n\t\t// Nullify the div so it wouldn't be stored in the memory and\n\t\t// it will also be a sign that checks already performed\n\t\tdiv = null;\n\t}\n\n\tvar pixelPositionVal, boxSizingReliableVal, pixelMarginRightVal, reliableMarginLeftVal,\n\t\tcontainer = document.createElement( \"div\" ),\n\t\tdiv = document.createElement( \"div\" );\n\n\t// Finish early in limited (non-browser) environments\n\tif ( !div.style ) {\n\t\treturn;\n\t}\n\n\t// Support: IE <=9 - 11 only\n\t// Style of cloned element affects source element cloned (#8908)\n\tdiv.style.backgroundClip = \"content-box\";\n\tdiv.cloneNode( true ).style.backgroundClip = \"\";\n\tsupport.clearCloneStyle = div.style.backgroundClip === \"content-box\";\n\n\tcontainer.style.cssText = \"border:0;width:8px;height:0;top:0;left:-9999px;\" +\n\t\t\"padding:0;margin-top:1px;position:absolute\";\n\tcontainer.appendChild( div );\n\n\tjQuery.extend( support, {\n\t\tpixelPosition: function() {\n\t\t\tcomputeStyleTests();\n\t\t\treturn pixelPositionVal;\n\t\t},\n\t\tboxSizingReliable: function() {\n\t\t\tcomputeStyleTests();\n\t\t\treturn boxSizingReliableVal;\n\t\t},\n\t\tpixelMarginRight: function() {\n\t\t\tcomputeStyleTests();\n\t\t\treturn pixelMarginRightVal;\n\t\t},\n\t\treliableMarginLeft: function() {\n\t\t\tcomputeStyleTests();\n\t\t\treturn reliableMarginLeftVal;\n\t\t}\n\t} );\n} )();\n\n\nfunction curCSS( elem, name, computed ) {\n\tvar width, minWidth, maxWidth, ret,\n\n\t\t// Support: Firefox 51+\n\t\t// Retrieving style before computed somehow\n\t\t// fixes an issue with getting wrong values\n\t\t// on detached elements\n\t\tstyle = elem.style;\n\n\tcomputed = computed || getStyles( elem );\n\n\t// getPropertyValue is needed for:\n\t//   .css('filter') (IE 9 only, #12537)\n\t//   .css('--customProperty) (#3144)\n\tif ( computed ) {\n\t\tret = computed.getPropertyValue( name ) || computed[ name ];\n\n\t\tif ( ret === \"\" && !jQuery.contains( elem.ownerDocument, elem ) ) {\n\t\t\tret = jQuery.style( elem, name );\n\t\t}\n\n\t\t// A tribute to the \"awesome hack by Dean Edwards\"\n\t\t// Android Browser returns percentage for some values,\n\t\t// but width seems to be reliably pixels.\n\t\t// This is against the CSSOM draft spec:\n\t\t// https://drafts.csswg.org/cssom/#resolved-values\n\t\tif ( !support.pixelMarginRight() && rnumnonpx.test( ret ) && rmargin.test( name ) ) {\n\n\t\t\t// Remember the original values\n\t\t\twidth = style.width;\n\t\t\tminWidth = style.minWidth;\n\t\t\tmaxWidth = style.maxWidth;\n\n\t\t\t// Put in the new values to get a computed value out\n\t\t\tstyle.minWidth = style.maxWidth = style.width = ret;\n\t\t\tret = computed.width;\n\n\t\t\t// Revert the changed values\n\t\t\tstyle.width = width;\n\t\t\tstyle.minWidth = minWidth;\n\t\t\tstyle.maxWidth = maxWidth;\n\t\t}\n\t}\n\n\treturn ret !== undefined ?\n\n\t\t// Support: IE <=9 - 11 only\n\t\t// IE returns zIndex value as an integer.\n\t\tret + \"\" :\n\t\tret;\n}\n\n\nfunction addGetHookIf( conditionFn, hookFn ) {\n\n\t// Define the hook, we'll check on the first run if it's really needed.\n\treturn {\n\t\tget: function() {\n\t\t\tif ( conditionFn() ) {\n\n\t\t\t\t// Hook not needed (or it's not possible to use it due\n\t\t\t\t// to missing dependency), remove it.\n\t\t\t\tdelete this.get;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Hook needed; redefine it so that the support test is not executed again.\n\t\t\treturn ( this.get = hookFn ).apply( this, arguments );\n\t\t}\n\t};\n}\n\n\nvar\n\n\t// Swappable if display is none or starts with table\n\t// except \"table\", \"table-cell\", or \"table-caption\"\n\t// See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display\n\trdisplayswap = /^(none|table(?!-c[ea]).+)/,\n\trcustomProp = /^--/,\n\tcssShow = { position: \"absolute\", visibility: \"hidden\", display: \"block\" },\n\tcssNormalTransform = {\n\t\tletterSpacing: \"0\",\n\t\tfontWeight: \"400\"\n\t},\n\n\tcssPrefixes = [ \"Webkit\", \"Moz\", \"ms\" ],\n\temptyStyle = document.createElement( \"div\" ).style;\n\n// Return a css property mapped to a potentially vendor prefixed property\nfunction vendorPropName( name ) {\n\n\t// Shortcut for names that are not vendor prefixed\n\tif ( name in emptyStyle ) {\n\t\treturn name;\n\t}\n\n\t// Check for vendor prefixed names\n\tvar capName = name[ 0 ].toUpperCase() + name.slice( 1 ),\n\t\ti = cssPrefixes.length;\n\n\twhile ( i-- ) {\n\t\tname = cssPrefixes[ i ] + capName;\n\t\tif ( name in emptyStyle ) {\n\t\t\treturn name;\n\t\t}\n\t}\n}\n\n// Return a property mapped along what jQuery.cssProps suggests or to\n// a vendor prefixed property.\nfunction finalPropName( name ) {\n\tvar ret = jQuery.cssProps[ name ];\n\tif ( !ret ) {\n\t\tret = jQuery.cssProps[ name ] = vendorPropName( name ) || name;\n\t}\n\treturn ret;\n}\n\nfunction setPositiveNumber( elem, value, subtract ) {\n\n\t// Any relative (+/-) values have already been\n\t// normalized at this point\n\tvar matches = rcssNum.exec( value );\n\treturn matches ?\n\n\t\t// Guard against undefined \"subtract\", e.g., when used as in cssHooks\n\t\tMath.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || \"px\" ) :\n\t\tvalue;\n}\n\nfunction augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {\n\tvar i,\n\t\tval = 0;\n\n\t// If we already have the right measurement, avoid augmentation\n\tif ( extra === ( isBorderBox ? \"border\" : \"content\" ) ) {\n\t\ti = 4;\n\n\t// Otherwise initialize for horizontal or vertical properties\n\t} else {\n\t\ti = name === \"width\" ? 1 : 0;\n\t}\n\n\tfor ( ; i < 4; i += 2 ) {\n\n\t\t// Both box models exclude margin, so add it if we want it\n\t\tif ( extra === \"margin\" ) {\n\t\t\tval += jQuery.css( elem, extra + cssExpand[ i ], true, styles );\n\t\t}\n\n\t\tif ( isBorderBox ) {\n\n\t\t\t// border-box includes padding, so remove it if we want content\n\t\t\tif ( extra === \"content\" ) {\n\t\t\t\tval -= jQuery.css( elem, \"padding\" + cssExpand[ i ], true, styles );\n\t\t\t}\n\n\t\t\t// At this point, extra isn't border nor margin, so remove border\n\t\t\tif ( extra !== \"margin\" ) {\n\t\t\t\tval -= jQuery.css( elem, \"border\" + cssExpand[ i ] + \"Width\", true, styles );\n\t\t\t}\n\t\t} else {\n\n\t\t\t// At this point, extra isn't content, so add padding\n\t\t\tval += jQuery.css( elem, \"padding\" + cssExpand[ i ], true, styles );\n\n\t\t\t// At this point, extra isn't content nor padding, so add border\n\t\t\tif ( extra !== \"padding\" ) {\n\t\t\t\tval += jQuery.css( elem, \"border\" + cssExpand[ i ] + \"Width\", true, styles );\n\t\t\t}\n\t\t}\n\t}\n\n\treturn val;\n}\n\nfunction getWidthOrHeight( elem, name, extra ) {\n\n\t// Start with computed style\n\tvar valueIsBorderBox,\n\t\tstyles = getStyles( elem ),\n\t\tval = curCSS( elem, name, styles ),\n\t\tisBorderBox = jQuery.css( elem, \"boxSizing\", false, styles ) === \"border-box\";\n\n\t// Computed unit is not pixels. Stop here and return.\n\tif ( rnumnonpx.test( val ) ) {\n\t\treturn val;\n\t}\n\n\t// Check for style in case a browser which returns unreliable values\n\t// for getComputedStyle silently falls back to the reliable elem.style\n\tvalueIsBorderBox = isBorderBox &&\n\t\t( support.boxSizingReliable() || val === elem.style[ name ] );\n\n\t// Fall back to offsetWidth/Height when value is \"auto\"\n\t// This happens for inline elements with no explicit setting (gh-3571)\n\tif ( val === \"auto\" ) {\n\t\tval = elem[ \"offset\" + name[ 0 ].toUpperCase() + name.slice( 1 ) ];\n\t}\n\n\t// Normalize \"\", auto, and prepare for extra\n\tval = parseFloat( val ) || 0;\n\n\t// Use the active box-sizing model to add/subtract irrelevant styles\n\treturn ( val +\n\t\taugmentWidthOrHeight(\n\t\t\telem,\n\t\t\tname,\n\t\t\textra || ( isBorderBox ? \"border\" : \"content\" ),\n\t\t\tvalueIsBorderBox,\n\t\t\tstyles\n\t\t)\n\t) + \"px\";\n}\n\njQuery.extend( {\n\n\t// Add in style property hooks for overriding the default\n\t// behavior of getting and setting a style property\n\tcssHooks: {\n\t\topacity: {\n\t\t\tget: function( elem, computed ) {\n\t\t\t\tif ( computed ) {\n\n\t\t\t\t\t// We should always get a number back from opacity\n\t\t\t\t\tvar ret = curCSS( elem, \"opacity\" );\n\t\t\t\t\treturn ret === \"\" ? \"1\" : ret;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\t// Don't automatically add \"px\" to these possibly-unitless properties\n\tcssNumber: {\n\t\t\"animationIterationCount\": true,\n\t\t\"columnCount\": true,\n\t\t\"fillOpacity\": true,\n\t\t\"flexGrow\": true,\n\t\t\"flexShrink\": true,\n\t\t\"fontWeight\": true,\n\t\t\"lineHeight\": true,\n\t\t\"opacity\": true,\n\t\t\"order\": true,\n\t\t\"orphans\": true,\n\t\t\"widows\": true,\n\t\t\"zIndex\": true,\n\t\t\"zoom\": true\n\t},\n\n\t// Add in properties whose names you wish to fix before\n\t// setting or getting the value\n\tcssProps: {\n\t\t\"float\": \"cssFloat\"\n\t},\n\n\t// Get and set the style property on a DOM Node\n\tstyle: function( elem, name, value, extra ) {\n\n\t\t// Don't set styles on text and comment nodes\n\t\tif ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Make sure that we're working with the right name\n\t\tvar ret, type, hooks,\n\t\t\torigName = jQuery.camelCase( name ),\n\t\t\tisCustomProp = rcustomProp.test( name ),\n\t\t\tstyle = elem.style;\n\n\t\t// Make sure that we're working with the right name. We don't\n\t\t// want to query the value if it is a CSS custom property\n\t\t// since they are user-defined.\n\t\tif ( !isCustomProp ) {\n\t\t\tname = finalPropName( origName );\n\t\t}\n\n\t\t// Gets hook for the prefixed version, then unprefixed version\n\t\thooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];\n\n\t\t// Check if we're setting a value\n\t\tif ( value !== undefined ) {\n\t\t\ttype = typeof value;\n\n\t\t\t// Convert \"+=\" or \"-=\" to relative numbers (#7345)\n\t\t\tif ( type === \"string\" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) {\n\t\t\t\tvalue = adjustCSS( elem, name, ret );\n\n\t\t\t\t// Fixes bug #9237\n\t\t\t\ttype = \"number\";\n\t\t\t}\n\n\t\t\t// Make sure that null and NaN values aren't set (#7116)\n\t\t\tif ( value == null || value !== value ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// If a number was passed in, add the unit (except for certain CSS properties)\n\t\t\tif ( type === \"number\" ) {\n\t\t\t\tvalue += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? \"\" : \"px\" );\n\t\t\t}\n\n\t\t\t// background-* props affect original clone's values\n\t\t\tif ( !support.clearCloneStyle && value === \"\" && name.indexOf( \"background\" ) === 0 ) {\n\t\t\t\tstyle[ name ] = \"inherit\";\n\t\t\t}\n\n\t\t\t// If a hook was provided, use that value, otherwise just set the specified value\n\t\t\tif ( !hooks || !( \"set\" in hooks ) ||\n\t\t\t\t( value = hooks.set( elem, value, extra ) ) !== undefined ) {\n\n\t\t\t\tif ( isCustomProp ) {\n\t\t\t\t\tstyle.setProperty( name, value );\n\t\t\t\t} else {\n\t\t\t\t\tstyle[ name ] = value;\n\t\t\t\t}\n\t\t\t}\n\n\t\t} else {\n\n\t\t\t// If a hook was provided get the non-computed value from there\n\t\t\tif ( hooks && \"get\" in hooks &&\n\t\t\t\t( ret = hooks.get( elem, false, extra ) ) !== undefined ) {\n\n\t\t\t\treturn ret;\n\t\t\t}\n\n\t\t\t// Otherwise just get the value from the style object\n\t\t\treturn style[ name ];\n\t\t}\n\t},\n\n\tcss: function( elem, name, extra, styles ) {\n\t\tvar val, num, hooks,\n\t\t\torigName = jQuery.camelCase( name ),\n\t\t\tisCustomProp = rcustomProp.test( name );\n\n\t\t// Make sure that we're working with the right name. We don't\n\t\t// want to modify the value if it is a CSS custom property\n\t\t// since they are user-defined.\n\t\tif ( !isCustomProp ) {\n\t\t\tname = finalPropName( origName );\n\t\t}\n\n\t\t// Try prefixed name followed by the unprefixed name\n\t\thooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];\n\n\t\t// If a hook was provided get the computed value from there\n\t\tif ( hooks && \"get\" in hooks ) {\n\t\t\tval = hooks.get( elem, true, extra );\n\t\t}\n\n\t\t// Otherwise, if a way to get the computed value exists, use that\n\t\tif ( val === undefined ) {\n\t\t\tval = curCSS( elem, name, styles );\n\t\t}\n\n\t\t// Convert \"normal\" to computed value\n\t\tif ( val === \"normal\" && name in cssNormalTransform ) {\n\t\t\tval = cssNormalTransform[ name ];\n\t\t}\n\n\t\t// Make numeric if forced or a qualifier was provided and val looks numeric\n\t\tif ( extra === \"\" || extra ) {\n\t\t\tnum = parseFloat( val );\n\t\t\treturn extra === true || isFinite( num ) ? num || 0 : val;\n\t\t}\n\n\t\treturn val;\n\t}\n} );\n\njQuery.each( [ \"height\", \"width\" ], function( i, name ) {\n\tjQuery.cssHooks[ name ] = {\n\t\tget: function( elem, computed, extra ) {\n\t\t\tif ( computed ) {\n\n\t\t\t\t// Certain elements can have dimension info if we invisibly show them\n\t\t\t\t// but it must have a current display style that would benefit\n\t\t\t\treturn rdisplayswap.test( jQuery.css( elem, \"display\" ) ) &&\n\n\t\t\t\t\t// Support: Safari 8+\n\t\t\t\t\t// Table columns in Safari have non-zero offsetWidth & zero\n\t\t\t\t\t// getBoundingClientRect().width unless display is changed.\n\t\t\t\t\t// Support: IE <=11 only\n\t\t\t\t\t// Running getBoundingClientRect on a disconnected node\n\t\t\t\t\t// in IE throws an error.\n\t\t\t\t\t( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ?\n\t\t\t\t\t\tswap( elem, cssShow, function() {\n\t\t\t\t\t\t\treturn getWidthOrHeight( elem, name, extra );\n\t\t\t\t\t\t} ) :\n\t\t\t\t\t\tgetWidthOrHeight( elem, name, extra );\n\t\t\t}\n\t\t},\n\n\t\tset: function( elem, value, extra ) {\n\t\t\tvar matches,\n\t\t\t\tstyles = extra && getStyles( elem ),\n\t\t\t\tsubtract = extra && augmentWidthOrHeight(\n\t\t\t\t\telem,\n\t\t\t\t\tname,\n\t\t\t\t\textra,\n\t\t\t\t\tjQuery.css( elem, \"boxSizing\", false, styles ) === \"border-box\",\n\t\t\t\t\tstyles\n\t\t\t\t);\n\n\t\t\t// Convert to pixels if value adjustment is needed\n\t\t\tif ( subtract && ( matches = rcssNum.exec( value ) ) &&\n\t\t\t\t( matches[ 3 ] || \"px\" ) !== \"px\" ) {\n\n\t\t\t\telem.style[ name ] = value;\n\t\t\t\tvalue = jQuery.css( elem, name );\n\t\t\t}\n\n\t\t\treturn setPositiveNumber( elem, value, subtract );\n\t\t}\n\t};\n} );\n\njQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft,\n\tfunction( elem, computed ) {\n\t\tif ( computed ) {\n\t\t\treturn ( parseFloat( curCSS( elem, \"marginLeft\" ) ) ||\n\t\t\t\telem.getBoundingClientRect().left -\n\t\t\t\t\tswap( elem, { marginLeft: 0 }, function() {\n\t\t\t\t\t\treturn elem.getBoundingClientRect().left;\n\t\t\t\t\t} )\n\t\t\t\t) + \"px\";\n\t\t}\n\t}\n);\n\n// These hooks are used by animate to expand properties\njQuery.each( {\n\tmargin: \"\",\n\tpadding: \"\",\n\tborder: \"Width\"\n}, function( prefix, suffix ) {\n\tjQuery.cssHooks[ prefix + suffix ] = {\n\t\texpand: function( value ) {\n\t\t\tvar i = 0,\n\t\t\t\texpanded = {},\n\n\t\t\t\t// Assumes a single number if not a string\n\t\t\t\tparts = typeof value === \"string\" ? value.split( \" \" ) : [ value ];\n\n\t\t\tfor ( ; i < 4; i++ ) {\n\t\t\t\texpanded[ prefix + cssExpand[ i ] + suffix ] =\n\t\t\t\t\tparts[ i ] || parts[ i - 2 ] || parts[ 0 ];\n\t\t\t}\n\n\t\t\treturn expanded;\n\t\t}\n\t};\n\n\tif ( !rmargin.test( prefix ) ) {\n\t\tjQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;\n\t}\n} );\n\njQuery.fn.extend( {\n\tcss: function( name, value ) {\n\t\treturn access( this, function( elem, name, value ) {\n\t\t\tvar styles, len,\n\t\t\t\tmap = {},\n\t\t\t\ti = 0;\n\n\t\t\tif ( Array.isArray( name ) ) {\n\t\t\t\tstyles = getStyles( elem );\n\t\t\t\tlen = name.length;\n\n\t\t\t\tfor ( ; i < len; i++ ) {\n\t\t\t\t\tmap[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );\n\t\t\t\t}\n\n\t\t\t\treturn map;\n\t\t\t}\n\n\t\t\treturn value !== undefined ?\n\t\t\t\tjQuery.style( elem, name, value ) :\n\t\t\t\tjQuery.css( elem, name );\n\t\t}, name, value, arguments.length > 1 );\n\t}\n} );\n\n\nfunction Tween( elem, options, prop, end, easing ) {\n\treturn new Tween.prototype.init( elem, options, prop, end, easing );\n}\njQuery.Tween = Tween;\n\nTween.prototype = {\n\tconstructor: Tween,\n\tinit: function( elem, options, prop, end, easing, unit ) {\n\t\tthis.elem = elem;\n\t\tthis.prop = prop;\n\t\tthis.easing = easing || jQuery.easing._default;\n\t\tthis.options = options;\n\t\tthis.start = this.now = this.cur();\n\t\tthis.end = end;\n\t\tthis.unit = unit || ( jQuery.cssNumber[ prop ] ? \"\" : \"px\" );\n\t},\n\tcur: function() {\n\t\tvar hooks = Tween.propHooks[ this.prop ];\n\n\t\treturn hooks && hooks.get ?\n\t\t\thooks.get( this ) :\n\t\t\tTween.propHooks._default.get( this );\n\t},\n\trun: function( percent ) {\n\t\tvar eased,\n\t\t\thooks = Tween.propHooks[ this.prop ];\n\n\t\tif ( this.options.duration ) {\n\t\t\tthis.pos = eased = jQuery.easing[ this.easing ](\n\t\t\t\tpercent, this.options.duration * percent, 0, 1, this.options.duration\n\t\t\t);\n\t\t} else {\n\t\t\tthis.pos = eased = percent;\n\t\t}\n\t\tthis.now = ( this.end - this.start ) * eased + this.start;\n\n\t\tif ( this.options.step ) {\n\t\t\tthis.options.step.call( this.elem, this.now, this );\n\t\t}\n\n\t\tif ( hooks && hooks.set ) {\n\t\t\thooks.set( this );\n\t\t} else {\n\t\t\tTween.propHooks._default.set( this );\n\t\t}\n\t\treturn this;\n\t}\n};\n\nTween.prototype.init.prototype = Tween.prototype;\n\nTween.propHooks = {\n\t_default: {\n\t\tget: function( tween ) {\n\t\t\tvar result;\n\n\t\t\t// Use a property on the element directly when it is not a DOM element,\n\t\t\t// or when there is no matching style property that exists.\n\t\t\tif ( tween.elem.nodeType !== 1 ||\n\t\t\t\ttween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) {\n\t\t\t\treturn tween.elem[ tween.prop ];\n\t\t\t}\n\n\t\t\t// Passing an empty string as a 3rd parameter to .css will automatically\n\t\t\t// attempt a parseFloat and fallback to a string if the parse fails.\n\t\t\t// Simple values such as \"10px\" are parsed to Float;\n\t\t\t// complex values such as \"rotate(1rad)\" are returned as-is.\n\t\t\tresult = jQuery.css( tween.elem, tween.prop, \"\" );\n\n\t\t\t// Empty strings, null, undefined and \"auto\" are converted to 0.\n\t\t\treturn !result || result === \"auto\" ? 0 : result;\n\t\t},\n\t\tset: function( tween ) {\n\n\t\t\t// Use step hook for back compat.\n\t\t\t// Use cssHook if its there.\n\t\t\t// Use .style if available and use plain properties where available.\n\t\t\tif ( jQuery.fx.step[ tween.prop ] ) {\n\t\t\t\tjQuery.fx.step[ tween.prop ]( tween );\n\t\t\t} else if ( tween.elem.nodeType === 1 &&\n\t\t\t\t( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null ||\n\t\t\t\t\tjQuery.cssHooks[ tween.prop ] ) ) {\n\t\t\t\tjQuery.style( tween.elem, tween.prop, tween.now + tween.unit );\n\t\t\t} else {\n\t\t\t\ttween.elem[ tween.prop ] = tween.now;\n\t\t\t}\n\t\t}\n\t}\n};\n\n// Support: IE <=9 only\n// Panic based approach to setting things on disconnected nodes\nTween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {\n\tset: function( tween ) {\n\t\tif ( tween.elem.nodeType && tween.elem.parentNode ) {\n\t\t\ttween.elem[ tween.prop ] = tween.now;\n\t\t}\n\t}\n};\n\njQuery.easing = {\n\tlinear: function( p ) {\n\t\treturn p;\n\t},\n\tswing: function( p ) {\n\t\treturn 0.5 - Math.cos( p * Math.PI ) / 2;\n\t},\n\t_default: \"swing\"\n};\n\njQuery.fx = Tween.prototype.init;\n\n// Back compat <1.8 extension point\njQuery.fx.step = {};\n\n\n\n\nvar\n\tfxNow, inProgress,\n\trfxtypes = /^(?:toggle|show|hide)$/,\n\trrun = /queueHooks$/;\n\nfunction schedule() {\n\tif ( inProgress ) {\n\t\tif ( document.hidden === false && window.requestAnimationFrame ) {\n\t\t\twindow.requestAnimationFrame( schedule );\n\t\t} else {\n\t\t\twindow.setTimeout( schedule, jQuery.fx.interval );\n\t\t}\n\n\t\tjQuery.fx.tick();\n\t}\n}\n\n// Animations created synchronously will run synchronously\nfunction createFxNow() {\n\twindow.setTimeout( function() {\n\t\tfxNow = undefined;\n\t} );\n\treturn ( fxNow = jQuery.now() );\n}\n\n// Generate parameters to create a standard animation\nfunction genFx( type, includeWidth ) {\n\tvar which,\n\t\ti = 0,\n\t\tattrs = { height: type };\n\n\t// If we include width, step value is 1 to do all cssExpand values,\n\t// otherwise step value is 2 to skip over Left and Right\n\tincludeWidth = includeWidth ? 1 : 0;\n\tfor ( ; i < 4; i += 2 - includeWidth ) {\n\t\twhich = cssExpand[ i ];\n\t\tattrs[ \"margin\" + which ] = attrs[ \"padding\" + which ] = type;\n\t}\n\n\tif ( includeWidth ) {\n\t\tattrs.opacity = attrs.width = type;\n\t}\n\n\treturn attrs;\n}\n\nfunction createTween( value, prop, animation ) {\n\tvar tween,\n\t\tcollection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ \"*\" ] ),\n\t\tindex = 0,\n\t\tlength = collection.length;\n\tfor ( ; index < length; index++ ) {\n\t\tif ( ( tween = collection[ index ].call( animation, prop, value ) ) ) {\n\n\t\t\t// We're done with this property\n\t\t\treturn tween;\n\t\t}\n\t}\n}\n\nfunction defaultPrefilter( elem, props, opts ) {\n\tvar prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display,\n\t\tisBox = \"width\" in props || \"height\" in props,\n\t\tanim = this,\n\t\torig = {},\n\t\tstyle = elem.style,\n\t\thidden = elem.nodeType && isHiddenWithinTree( elem ),\n\t\tdataShow = dataPriv.get( elem, \"fxshow\" );\n\n\t// Queue-skipping animations hijack the fx hooks\n\tif ( !opts.queue ) {\n\t\thooks = jQuery._queueHooks( elem, \"fx\" );\n\t\tif ( hooks.unqueued == null ) {\n\t\t\thooks.unqueued = 0;\n\t\t\toldfire = hooks.empty.fire;\n\t\t\thooks.empty.fire = function() {\n\t\t\t\tif ( !hooks.unqueued ) {\n\t\t\t\t\toldfire();\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\t\thooks.unqueued++;\n\n\t\tanim.always( function() {\n\n\t\t\t// Ensure the complete handler is called before this completes\n\t\t\tanim.always( function() {\n\t\t\t\thooks.unqueued--;\n\t\t\t\tif ( !jQuery.queue( elem, \"fx\" ).length ) {\n\t\t\t\t\thooks.empty.fire();\n\t\t\t\t}\n\t\t\t} );\n\t\t} );\n\t}\n\n\t// Detect show/hide animations\n\tfor ( prop in props ) {\n\t\tvalue = props[ prop ];\n\t\tif ( rfxtypes.test( value ) ) {\n\t\t\tdelete props[ prop ];\n\t\t\ttoggle = toggle || value === \"toggle\";\n\t\t\tif ( value === ( hidden ? \"hide\" : \"show\" ) ) {\n\n\t\t\t\t// Pretend to be hidden if this is a \"show\" and\n\t\t\t\t// there is still data from a stopped show/hide\n\t\t\t\tif ( value === \"show\" && dataShow && dataShow[ prop ] !== undefined ) {\n\t\t\t\t\thidden = true;\n\n\t\t\t\t// Ignore all other no-op show/hide data\n\t\t\t\t} else {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t\torig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );\n\t\t}\n\t}\n\n\t// Bail out if this is a no-op like .hide().hide()\n\tpropTween = !jQuery.isEmptyObject( props );\n\tif ( !propTween && jQuery.isEmptyObject( orig ) ) {\n\t\treturn;\n\t}\n\n\t// Restrict \"overflow\" and \"display\" styles during box animations\n\tif ( isBox && elem.nodeType === 1 ) {\n\n\t\t// Support: IE <=9 - 11, Edge 12 - 13\n\t\t// Record all 3 overflow attributes because IE does not infer the shorthand\n\t\t// from identically-valued overflowX and overflowY\n\t\topts.overflow = [ style.overflow, style.overflowX, style.overflowY ];\n\n\t\t// Identify a display type, preferring old show/hide data over the CSS cascade\n\t\trestoreDisplay = dataShow && dataShow.display;\n\t\tif ( restoreDisplay == null ) {\n\t\t\trestoreDisplay = dataPriv.get( elem, \"display\" );\n\t\t}\n\t\tdisplay = jQuery.css( elem, \"display\" );\n\t\tif ( display === \"none\" ) {\n\t\t\tif ( restoreDisplay ) {\n\t\t\t\tdisplay = restoreDisplay;\n\t\t\t} else {\n\n\t\t\t\t// Get nonempty value(s) by temporarily forcing visibility\n\t\t\t\tshowHide( [ elem ], true );\n\t\t\t\trestoreDisplay = elem.style.display || restoreDisplay;\n\t\t\t\tdisplay = jQuery.css( elem, \"display\" );\n\t\t\t\tshowHide( [ elem ] );\n\t\t\t}\n\t\t}\n\n\t\t// Animate inline elements as inline-block\n\t\tif ( display === \"inline\" || display === \"inline-block\" && restoreDisplay != null ) {\n\t\t\tif ( jQuery.css( elem, \"float\" ) === \"none\" ) {\n\n\t\t\t\t// Restore the original display value at the end of pure show/hide animations\n\t\t\t\tif ( !propTween ) {\n\t\t\t\t\tanim.done( function() {\n\t\t\t\t\t\tstyle.display = restoreDisplay;\n\t\t\t\t\t} );\n\t\t\t\t\tif ( restoreDisplay == null ) {\n\t\t\t\t\t\tdisplay = style.display;\n\t\t\t\t\t\trestoreDisplay = display === \"none\" ? \"\" : display;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tstyle.display = \"inline-block\";\n\t\t\t}\n\t\t}\n\t}\n\n\tif ( opts.overflow ) {\n\t\tstyle.overflow = \"hidden\";\n\t\tanim.always( function() {\n\t\t\tstyle.overflow = opts.overflow[ 0 ];\n\t\t\tstyle.overflowX = opts.overflow[ 1 ];\n\t\t\tstyle.overflowY = opts.overflow[ 2 ];\n\t\t} );\n\t}\n\n\t// Implement show/hide animations\n\tpropTween = false;\n\tfor ( prop in orig ) {\n\n\t\t// General show/hide setup for this element animation\n\t\tif ( !propTween ) {\n\t\t\tif ( dataShow ) {\n\t\t\t\tif ( \"hidden\" in dataShow ) {\n\t\t\t\t\thidden = dataShow.hidden;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tdataShow = dataPriv.access( elem, \"fxshow\", { display: restoreDisplay } );\n\t\t\t}\n\n\t\t\t// Store hidden/visible for toggle so `.stop().toggle()` \"reverses\"\n\t\t\tif ( toggle ) {\n\t\t\t\tdataShow.hidden = !hidden;\n\t\t\t}\n\n\t\t\t// Show elements before animating them\n\t\t\tif ( hidden ) {\n\t\t\t\tshowHide( [ elem ], true );\n\t\t\t}\n\n\t\t\t/* eslint-disable no-loop-func */\n\n\t\t\tanim.done( function() {\n\n\t\t\t/* eslint-enable no-loop-func */\n\n\t\t\t\t// The final step of a \"hide\" animation is actually hiding the element\n\t\t\t\tif ( !hidden ) {\n\t\t\t\t\tshowHide( [ elem ] );\n\t\t\t\t}\n\t\t\t\tdataPriv.remove( elem, \"fxshow\" );\n\t\t\t\tfor ( prop in orig ) {\n\t\t\t\t\tjQuery.style( elem, prop, orig[ prop ] );\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\n\t\t// Per-property setup\n\t\tpropTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );\n\t\tif ( !( prop in dataShow ) ) {\n\t\t\tdataShow[ prop ] = propTween.start;\n\t\t\tif ( hidden ) {\n\t\t\t\tpropTween.end = propTween.start;\n\t\t\t\tpropTween.start = 0;\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction propFilter( props, specialEasing ) {\n\tvar index, name, easing, value, hooks;\n\n\t// camelCase, specialEasing and expand cssHook pass\n\tfor ( index in props ) {\n\t\tname = jQuery.camelCase( index );\n\t\teasing = specialEasing[ name ];\n\t\tvalue = props[ index ];\n\t\tif ( Array.isArray( value ) ) {\n\t\t\teasing = value[ 1 ];\n\t\t\tvalue = props[ index ] = value[ 0 ];\n\t\t}\n\n\t\tif ( index !== name ) {\n\t\t\tprops[ name ] = value;\n\t\t\tdelete props[ index ];\n\t\t}\n\n\t\thooks = jQuery.cssHooks[ name ];\n\t\tif ( hooks && \"expand\" in hooks ) {\n\t\t\tvalue = hooks.expand( value );\n\t\t\tdelete props[ name ];\n\n\t\t\t// Not quite $.extend, this won't overwrite existing keys.\n\t\t\t// Reusing 'index' because we have the correct \"name\"\n\t\t\tfor ( index in value ) {\n\t\t\t\tif ( !( index in props ) ) {\n\t\t\t\t\tprops[ index ] = value[ index ];\n\t\t\t\t\tspecialEasing[ index ] = easing;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tspecialEasing[ name ] = easing;\n\t\t}\n\t}\n}\n\nfunction Animation( elem, properties, options ) {\n\tvar result,\n\t\tstopped,\n\t\tindex = 0,\n\t\tlength = Animation.prefilters.length,\n\t\tdeferred = jQuery.Deferred().always( function() {\n\n\t\t\t// Don't match elem in the :animated selector\n\t\t\tdelete tick.elem;\n\t\t} ),\n\t\ttick = function() {\n\t\t\tif ( stopped ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tvar currentTime = fxNow || createFxNow(),\n\t\t\t\tremaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),\n\n\t\t\t\t// Support: Android 2.3 only\n\t\t\t\t// Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497)\n\t\t\t\ttemp = remaining / animation.duration || 0,\n\t\t\t\tpercent = 1 - temp,\n\t\t\t\tindex = 0,\n\t\t\t\tlength = animation.tweens.length;\n\n\t\t\tfor ( ; index < length; index++ ) {\n\t\t\t\tanimation.tweens[ index ].run( percent );\n\t\t\t}\n\n\t\t\tdeferred.notifyWith( elem, [ animation, percent, remaining ] );\n\n\t\t\t// If there's more to do, yield\n\t\t\tif ( percent < 1 && length ) {\n\t\t\t\treturn remaining;\n\t\t\t}\n\n\t\t\t// If this was an empty animation, synthesize a final progress notification\n\t\t\tif ( !length ) {\n\t\t\t\tdeferred.notifyWith( elem, [ animation, 1, 0 ] );\n\t\t\t}\n\n\t\t\t// Resolve the animation and report its conclusion\n\t\t\tdeferred.resolveWith( elem, [ animation ] );\n\t\t\treturn false;\n\t\t},\n\t\tanimation = deferred.promise( {\n\t\t\telem: elem,\n\t\t\tprops: jQuery.extend( {}, properties ),\n\t\t\topts: jQuery.extend( true, {\n\t\t\t\tspecialEasing: {},\n\t\t\t\teasing: jQuery.easing._default\n\t\t\t}, options ),\n\t\t\toriginalProperties: properties,\n\t\t\toriginalOptions: options,\n\t\t\tstartTime: fxNow || createFxNow(),\n\t\t\tduration: options.duration,\n\t\t\ttweens: [],\n\t\t\tcreateTween: function( prop, end ) {\n\t\t\t\tvar tween = jQuery.Tween( elem, animation.opts, prop, end,\n\t\t\t\t\t\tanimation.opts.specialEasing[ prop ] || animation.opts.easing );\n\t\t\t\tanimation.tweens.push( tween );\n\t\t\t\treturn tween;\n\t\t\t},\n\t\t\tstop: function( gotoEnd ) {\n\t\t\t\tvar index = 0,\n\n\t\t\t\t\t// If we are going to the end, we want to run all the tweens\n\t\t\t\t\t// otherwise we skip this part\n\t\t\t\t\tlength = gotoEnd ? animation.tweens.length : 0;\n\t\t\t\tif ( stopped ) {\n\t\t\t\t\treturn this;\n\t\t\t\t}\n\t\t\t\tstopped = true;\n\t\t\t\tfor ( ; index < length; index++ ) {\n\t\t\t\t\tanimation.tweens[ index ].run( 1 );\n\t\t\t\t}\n\n\t\t\t\t// Resolve when we played the last frame; otherwise, reject\n\t\t\t\tif ( gotoEnd ) {\n\t\t\t\t\tdeferred.notifyWith( elem, [ animation, 1, 0 ] );\n\t\t\t\t\tdeferred.resolveWith( elem, [ animation, gotoEnd ] );\n\t\t\t\t} else {\n\t\t\t\t\tdeferred.rejectWith( elem, [ animation, gotoEnd ] );\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t}\n\t\t} ),\n\t\tprops = animation.props;\n\n\tpropFilter( props, animation.opts.specialEasing );\n\n\tfor ( ; index < length; index++ ) {\n\t\tresult = Animation.prefilters[ index ].call( animation, elem, props, animation.opts );\n\t\tif ( result ) {\n\t\t\tif ( jQuery.isFunction( result.stop ) ) {\n\t\t\t\tjQuery._queueHooks( animation.elem, animation.opts.queue ).stop =\n\t\t\t\t\tjQuery.proxy( result.stop, result );\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\t}\n\n\tjQuery.map( props, createTween, animation );\n\n\tif ( jQuery.isFunction( animation.opts.start ) ) {\n\t\tanimation.opts.start.call( elem, animation );\n\t}\n\n\t// Attach callbacks from options\n\tanimation\n\t\t.progress( animation.opts.progress )\n\t\t.done( animation.opts.done, animation.opts.complete )\n\t\t.fail( animation.opts.fail )\n\t\t.always( animation.opts.always );\n\n\tjQuery.fx.timer(\n\t\tjQuery.extend( tick, {\n\t\t\telem: elem,\n\t\t\tanim: animation,\n\t\t\tqueue: animation.opts.queue\n\t\t} )\n\t);\n\n\treturn animation;\n}\n\njQuery.Animation = jQuery.extend( Animation, {\n\n\ttweeners: {\n\t\t\"*\": [ function( prop, value ) {\n\t\t\tvar tween = this.createTween( prop, value );\n\t\t\tadjustCSS( tween.elem, prop, rcssNum.exec( value ), tween );\n\t\t\treturn tween;\n\t\t} ]\n\t},\n\n\ttweener: function( props, callback ) {\n\t\tif ( jQuery.isFunction( props ) ) {\n\t\t\tcallback = props;\n\t\t\tprops = [ \"*\" ];\n\t\t} else {\n\t\t\tprops = props.match( rnothtmlwhite );\n\t\t}\n\n\t\tvar prop,\n\t\t\tindex = 0,\n\t\t\tlength = props.length;\n\n\t\tfor ( ; index < length; index++ ) {\n\t\t\tprop = props[ index ];\n\t\t\tAnimation.tweeners[ prop ] = Animation.tweeners[ prop ] || [];\n\t\t\tAnimation.tweeners[ prop ].unshift( callback );\n\t\t}\n\t},\n\n\tprefilters: [ defaultPrefilter ],\n\n\tprefilter: function( callback, prepend ) {\n\t\tif ( prepend ) {\n\t\t\tAnimation.prefilters.unshift( callback );\n\t\t} else {\n\t\t\tAnimation.prefilters.push( callback );\n\t\t}\n\t}\n} );\n\njQuery.speed = function( speed, easing, fn ) {\n\tvar opt = speed && typeof speed === \"object\" ? jQuery.extend( {}, speed ) : {\n\t\tcomplete: fn || !fn && easing ||\n\t\t\tjQuery.isFunction( speed ) && speed,\n\t\tduration: speed,\n\t\teasing: fn && easing || easing && !jQuery.isFunction( easing ) && easing\n\t};\n\n\t// Go to the end state if fx are off\n\tif ( jQuery.fx.off ) {\n\t\topt.duration = 0;\n\n\t} else {\n\t\tif ( typeof opt.duration !== \"number\" ) {\n\t\t\tif ( opt.duration in jQuery.fx.speeds ) {\n\t\t\t\topt.duration = jQuery.fx.speeds[ opt.duration ];\n\n\t\t\t} else {\n\t\t\t\topt.duration = jQuery.fx.speeds._default;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Normalize opt.queue - true/undefined/null -> \"fx\"\n\tif ( opt.queue == null || opt.queue === true ) {\n\t\topt.queue = \"fx\";\n\t}\n\n\t// Queueing\n\topt.old = opt.complete;\n\n\topt.complete = function() {\n\t\tif ( jQuery.isFunction( opt.old ) ) {\n\t\t\topt.old.call( this );\n\t\t}\n\n\t\tif ( opt.queue ) {\n\t\t\tjQuery.dequeue( this, opt.queue );\n\t\t}\n\t};\n\n\treturn opt;\n};\n\njQuery.fn.extend( {\n\tfadeTo: function( speed, to, easing, callback ) {\n\n\t\t// Show any hidden elements after setting opacity to 0\n\t\treturn this.filter( isHiddenWithinTree ).css( \"opacity\", 0 ).show()\n\n\t\t\t// Animate to the value specified\n\t\t\t.end().animate( { opacity: to }, speed, easing, callback );\n\t},\n\tanimate: function( prop, speed, easing, callback ) {\n\t\tvar empty = jQuery.isEmptyObject( prop ),\n\t\t\toptall = jQuery.speed( speed, easing, callback ),\n\t\t\tdoAnimation = function() {\n\n\t\t\t\t// Operate on a copy of prop so per-property easing won't be lost\n\t\t\t\tvar anim = Animation( this, jQuery.extend( {}, prop ), optall );\n\n\t\t\t\t// Empty animations, or finishing resolves immediately\n\t\t\t\tif ( empty || dataPriv.get( this, \"finish\" ) ) {\n\t\t\t\t\tanim.stop( true );\n\t\t\t\t}\n\t\t\t};\n\t\t\tdoAnimation.finish = doAnimation;\n\n\t\treturn empty || optall.queue === false ?\n\t\t\tthis.each( doAnimation ) :\n\t\t\tthis.queue( optall.queue, doAnimation );\n\t},\n\tstop: function( type, clearQueue, gotoEnd ) {\n\t\tvar stopQueue = function( hooks ) {\n\t\t\tvar stop = hooks.stop;\n\t\t\tdelete hooks.stop;\n\t\t\tstop( gotoEnd );\n\t\t};\n\n\t\tif ( typeof type !== \"string\" ) {\n\t\t\tgotoEnd = clearQueue;\n\t\t\tclearQueue = type;\n\t\t\ttype = undefined;\n\t\t}\n\t\tif ( clearQueue && type !== false ) {\n\t\t\tthis.queue( type || \"fx\", [] );\n\t\t}\n\n\t\treturn this.each( function() {\n\t\t\tvar dequeue = true,\n\t\t\t\tindex = type != null && type + \"queueHooks\",\n\t\t\t\ttimers = jQuery.timers,\n\t\t\t\tdata = dataPriv.get( this );\n\n\t\t\tif ( index ) {\n\t\t\t\tif ( data[ index ] && data[ index ].stop ) {\n\t\t\t\t\tstopQueue( data[ index ] );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfor ( index in data ) {\n\t\t\t\t\tif ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {\n\t\t\t\t\t\tstopQueue( data[ index ] );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor ( index = timers.length; index--; ) {\n\t\t\t\tif ( timers[ index ].elem === this &&\n\t\t\t\t\t( type == null || timers[ index ].queue === type ) ) {\n\n\t\t\t\t\ttimers[ index ].anim.stop( gotoEnd );\n\t\t\t\t\tdequeue = false;\n\t\t\t\t\ttimers.splice( index, 1 );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Start the next in the queue if the last step wasn't forced.\n\t\t\t// Timers currently will call their complete callbacks, which\n\t\t\t// will dequeue but only if they were gotoEnd.\n\t\t\tif ( dequeue || !gotoEnd ) {\n\t\t\t\tjQuery.dequeue( this, type );\n\t\t\t}\n\t\t} );\n\t},\n\tfinish: function( type ) {\n\t\tif ( type !== false ) {\n\t\t\ttype = type || \"fx\";\n\t\t}\n\t\treturn this.each( function() {\n\t\t\tvar index,\n\t\t\t\tdata = dataPriv.get( this ),\n\t\t\t\tqueue = data[ type + \"queue\" ],\n\t\t\t\thooks = data[ type + \"queueHooks\" ],\n\t\t\t\ttimers = jQuery.timers,\n\t\t\t\tlength = queue ? queue.length : 0;\n\n\t\t\t// Enable finishing flag on private data\n\t\t\tdata.finish = true;\n\n\t\t\t// Empty the queue first\n\t\t\tjQuery.queue( this, type, [] );\n\n\t\t\tif ( hooks && hooks.stop ) {\n\t\t\t\thooks.stop.call( this, true );\n\t\t\t}\n\n\t\t\t// Look for any active animations, and finish them\n\t\t\tfor ( index = timers.length; index--; ) {\n\t\t\t\tif ( timers[ index ].elem === this && timers[ index ].queue === type ) {\n\t\t\t\t\ttimers[ index ].anim.stop( true );\n\t\t\t\t\ttimers.splice( index, 1 );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Look for any animations in the old queue and finish them\n\t\t\tfor ( index = 0; index < length; index++ ) {\n\t\t\t\tif ( queue[ index ] && queue[ index ].finish ) {\n\t\t\t\t\tqueue[ index ].finish.call( this );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Turn off finishing flag\n\t\t\tdelete data.finish;\n\t\t} );\n\t}\n} );\n\njQuery.each( [ \"toggle\", \"show\", \"hide\" ], function( i, name ) {\n\tvar cssFn = jQuery.fn[ name ];\n\tjQuery.fn[ name ] = function( speed, easing, callback ) {\n\t\treturn speed == null || typeof speed === \"boolean\" ?\n\t\t\tcssFn.apply( this, arguments ) :\n\t\t\tthis.animate( genFx( name, true ), speed, easing, callback );\n\t};\n} );\n\n// Generate shortcuts for custom animations\njQuery.each( {\n\tslideDown: genFx( \"show\" ),\n\tslideUp: genFx( \"hide\" ),\n\tslideToggle: genFx( \"toggle\" ),\n\tfadeIn: { opacity: \"show\" },\n\tfadeOut: { opacity: \"hide\" },\n\tfadeToggle: { opacity: \"toggle\" }\n}, function( name, props ) {\n\tjQuery.fn[ name ] = function( speed, easing, callback ) {\n\t\treturn this.animate( props, speed, easing, callback );\n\t};\n} );\n\njQuery.timers = [];\njQuery.fx.tick = function() {\n\tvar timer,\n\t\ti = 0,\n\t\ttimers = jQuery.timers;\n\n\tfxNow = jQuery.now();\n\n\tfor ( ; i < timers.length; i++ ) {\n\t\ttimer = timers[ i ];\n\n\t\t// Run the timer and safely remove it when done (allowing for external removal)\n\t\tif ( !timer() && timers[ i ] === timer ) {\n\t\t\ttimers.splice( i--, 1 );\n\t\t}\n\t}\n\n\tif ( !timers.length ) {\n\t\tjQuery.fx.stop();\n\t}\n\tfxNow = undefined;\n};\n\njQuery.fx.timer = function( timer ) {\n\tjQuery.timers.push( timer );\n\tjQuery.fx.start();\n};\n\njQuery.fx.interval = 13;\njQuery.fx.start = function() {\n\tif ( inProgress ) {\n\t\treturn;\n\t}\n\n\tinProgress = true;\n\tschedule();\n};\n\njQuery.fx.stop = function() {\n\tinProgress = null;\n};\n\njQuery.fx.speeds = {\n\tslow: 600,\n\tfast: 200,\n\n\t// Default speed\n\t_default: 400\n};\n\n\n// Based off of the plugin by Clint Helfers, with permission.\n// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/\njQuery.fn.delay = function( time, type ) {\n\ttime = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;\n\ttype = type || \"fx\";\n\n\treturn this.queue( type, function( next, hooks ) {\n\t\tvar timeout = window.setTimeout( next, time );\n\t\thooks.stop = function() {\n\t\t\twindow.clearTimeout( timeout );\n\t\t};\n\t} );\n};\n\n\n( function() {\n\tvar input = document.createElement( \"input\" ),\n\t\tselect = document.createElement( \"select\" ),\n\t\topt = select.appendChild( document.createElement( \"option\" ) );\n\n\tinput.type = \"checkbox\";\n\n\t// Support: Android <=4.3 only\n\t// Default value for a checkbox should be \"on\"\n\tsupport.checkOn = input.value !== \"\";\n\n\t// Support: IE <=11 only\n\t// Must access selectedIndex to make default options select\n\tsupport.optSelected = opt.selected;\n\n\t// Support: IE <=11 only\n\t// An input loses its value after becoming a radio\n\tinput = document.createElement( \"input\" );\n\tinput.value = \"t\";\n\tinput.type = \"radio\";\n\tsupport.radioValue = input.value === \"t\";\n} )();\n\n\nvar boolHook,\n\tattrHandle = jQuery.expr.attrHandle;\n\njQuery.fn.extend( {\n\tattr: function( name, value ) {\n\t\treturn access( this, jQuery.attr, name, value, arguments.length > 1 );\n\t},\n\n\tremoveAttr: function( name ) {\n\t\treturn this.each( function() {\n\t\t\tjQuery.removeAttr( this, name );\n\t\t} );\n\t}\n} );\n\njQuery.extend( {\n\tattr: function( elem, name, value ) {\n\t\tvar ret, hooks,\n\t\t\tnType = elem.nodeType;\n\n\t\t// Don't get/set attributes on text, comment and attribute nodes\n\t\tif ( nType === 3 || nType === 8 || nType === 2 ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Fallback to prop when attributes are not supported\n\t\tif ( typeof elem.getAttribute === \"undefined\" ) {\n\t\t\treturn jQuery.prop( elem, name, value );\n\t\t}\n\n\t\t// Attribute hooks are determined by the lowercase version\n\t\t// Grab necessary hook if one is defined\n\t\tif ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {\n\t\t\thooks = jQuery.attrHooks[ name.toLowerCase() ] ||\n\t\t\t\t( jQuery.expr.match.bool.test( name ) ? boolHook : undefined );\n\t\t}\n\n\t\tif ( value !== undefined ) {\n\t\t\tif ( value === null ) {\n\t\t\t\tjQuery.removeAttr( elem, name );\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( hooks && \"set\" in hooks &&\n\t\t\t\t( ret = hooks.set( elem, value, name ) ) !== undefined ) {\n\t\t\t\treturn ret;\n\t\t\t}\n\n\t\t\telem.setAttribute( name, value + \"\" );\n\t\t\treturn value;\n\t\t}\n\n\t\tif ( hooks && \"get\" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) {\n\t\t\treturn ret;\n\t\t}\n\n\t\tret = jQuery.find.attr( elem, name );\n\n\t\t// Non-existent attributes return null, we normalize to undefined\n\t\treturn ret == null ? undefined : ret;\n\t},\n\n\tattrHooks: {\n\t\ttype: {\n\t\t\tset: function( elem, value ) {\n\t\t\t\tif ( !support.radioValue && value === \"radio\" &&\n\t\t\t\t\tnodeName( elem, \"input\" ) ) {\n\t\t\t\t\tvar val = elem.value;\n\t\t\t\t\telem.setAttribute( \"type\", value );\n\t\t\t\t\tif ( val ) {\n\t\t\t\t\t\telem.value = val;\n\t\t\t\t\t}\n\t\t\t\t\treturn value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\tremoveAttr: function( elem, value ) {\n\t\tvar name,\n\t\t\ti = 0,\n\n\t\t\t// Attribute names can contain non-HTML whitespace characters\n\t\t\t// https://html.spec.whatwg.org/multipage/syntax.html#attributes-2\n\t\t\tattrNames = value && value.match( rnothtmlwhite );\n\n\t\tif ( attrNames && elem.nodeType === 1 ) {\n\t\t\twhile ( ( name = attrNames[ i++ ] ) ) {\n\t\t\t\telem.removeAttribute( name );\n\t\t\t}\n\t\t}\n\t}\n} );\n\n// Hooks for boolean attributes\nboolHook = {\n\tset: function( elem, value, name ) {\n\t\tif ( value === false ) {\n\n\t\t\t// Remove boolean attributes when set to false\n\t\t\tjQuery.removeAttr( elem, name );\n\t\t} else {\n\t\t\telem.setAttribute( name, name );\n\t\t}\n\t\treturn name;\n\t}\n};\n\njQuery.each( jQuery.expr.match.bool.source.match( /\\w+/g ), function( i, name ) {\n\tvar getter = attrHandle[ name ] || jQuery.find.attr;\n\n\tattrHandle[ name ] = function( elem, name, isXML ) {\n\t\tvar ret, handle,\n\t\t\tlowercaseName = name.toLowerCase();\n\n\t\tif ( !isXML ) {\n\n\t\t\t// Avoid an infinite loop by temporarily removing this function from the getter\n\t\t\thandle = attrHandle[ lowercaseName ];\n\t\t\tattrHandle[ lowercaseName ] = ret;\n\t\t\tret = getter( elem, name, isXML ) != null ?\n\t\t\t\tlowercaseName :\n\t\t\t\tnull;\n\t\t\tattrHandle[ lowercaseName ] = handle;\n\t\t}\n\t\treturn ret;\n\t};\n} );\n\n\n\n\nvar rfocusable = /^(?:input|select|textarea|button)$/i,\n\trclickable = /^(?:a|area)$/i;\n\njQuery.fn.extend( {\n\tprop: function( name, value ) {\n\t\treturn access( this, jQuery.prop, name, value, arguments.length > 1 );\n\t},\n\n\tremoveProp: function( name ) {\n\t\treturn this.each( function() {\n\t\t\tdelete this[ jQuery.propFix[ name ] || name ];\n\t\t} );\n\t}\n} );\n\njQuery.extend( {\n\tprop: function( elem, name, value ) {\n\t\tvar ret, hooks,\n\t\t\tnType = elem.nodeType;\n\n\t\t// Don't get/set properties on text, comment and attribute nodes\n\t\tif ( nType === 3 || nType === 8 || nType === 2 ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {\n\n\t\t\t// Fix name and attach hooks\n\t\t\tname = jQuery.propFix[ name ] || name;\n\t\t\thooks = jQuery.propHooks[ name ];\n\t\t}\n\n\t\tif ( value !== undefined ) {\n\t\t\tif ( hooks && \"set\" in hooks &&\n\t\t\t\t( ret = hooks.set( elem, value, name ) ) !== undefined ) {\n\t\t\t\treturn ret;\n\t\t\t}\n\n\t\t\treturn ( elem[ name ] = value );\n\t\t}\n\n\t\tif ( hooks && \"get\" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) {\n\t\t\treturn ret;\n\t\t}\n\n\t\treturn elem[ name ];\n\t},\n\n\tpropHooks: {\n\t\ttabIndex: {\n\t\t\tget: function( elem ) {\n\n\t\t\t\t// Support: IE <=9 - 11 only\n\t\t\t\t// elem.tabIndex doesn't always return the\n\t\t\t\t// correct value when it hasn't been explicitly set\n\t\t\t\t// https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/\n\t\t\t\t// Use proper attribute retrieval(#12072)\n\t\t\t\tvar tabindex = jQuery.find.attr( elem, \"tabindex\" );\n\n\t\t\t\tif ( tabindex ) {\n\t\t\t\t\treturn parseInt( tabindex, 10 );\n\t\t\t\t}\n\n\t\t\t\tif (\n\t\t\t\t\trfocusable.test( elem.nodeName ) ||\n\t\t\t\t\trclickable.test( elem.nodeName ) &&\n\t\t\t\t\telem.href\n\t\t\t\t) {\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t}\n\t},\n\n\tpropFix: {\n\t\t\"for\": \"htmlFor\",\n\t\t\"class\": \"className\"\n\t}\n} );\n\n// Support: IE <=11 only\n// Accessing the selectedIndex property\n// forces the browser to respect setting selected\n// on the option\n// The getter ensures a default option is selected\n// when in an optgroup\n// eslint rule \"no-unused-expressions\" is disabled for this code\n// since it considers such accessions noop\nif ( !support.optSelected ) {\n\tjQuery.propHooks.selected = {\n\t\tget: function( elem ) {\n\n\t\t\t/* eslint no-unused-expressions: \"off\" */\n\n\t\t\tvar parent = elem.parentNode;\n\t\t\tif ( parent && parent.parentNode ) {\n\t\t\t\tparent.parentNode.selectedIndex;\n\t\t\t}\n\t\t\treturn null;\n\t\t},\n\t\tset: function( elem ) {\n\n\t\t\t/* eslint no-unused-expressions: \"off\" */\n\n\t\t\tvar parent = elem.parentNode;\n\t\t\tif ( parent ) {\n\t\t\t\tparent.selectedIndex;\n\n\t\t\t\tif ( parent.parentNode ) {\n\t\t\t\t\tparent.parentNode.selectedIndex;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n}\n\njQuery.each( [\n\t\"tabIndex\",\n\t\"readOnly\",\n\t\"maxLength\",\n\t\"cellSpacing\",\n\t\"cellPadding\",\n\t\"rowSpan\",\n\t\"colSpan\",\n\t\"useMap\",\n\t\"frameBorder\",\n\t\"contentEditable\"\n], function() {\n\tjQuery.propFix[ this.toLowerCase() ] = this;\n} );\n\n\n\n\n\t// Strip and collapse whitespace according to HTML spec\n\t// https://html.spec.whatwg.org/multipage/infrastructure.html#strip-and-collapse-whitespace\n\tfunction stripAndCollapse( value ) {\n\t\tvar tokens = value.match( rnothtmlwhite ) || [];\n\t\treturn tokens.join( \" \" );\n\t}\n\n\nfunction getClass( elem ) {\n\treturn elem.getAttribute && elem.getAttribute( \"class\" ) || \"\";\n}\n\njQuery.fn.extend( {\n\taddClass: function( value ) {\n\t\tvar classes, elem, cur, curValue, clazz, j, finalValue,\n\t\t\ti = 0;\n\n\t\tif ( jQuery.isFunction( value ) ) {\n\t\t\treturn this.each( function( j ) {\n\t\t\t\tjQuery( this ).addClass( value.call( this, j, getClass( this ) ) );\n\t\t\t} );\n\t\t}\n\n\t\tif ( typeof value === \"string\" && value ) {\n\t\t\tclasses = value.match( rnothtmlwhite ) || [];\n\n\t\t\twhile ( ( elem = this[ i++ ] ) ) {\n\t\t\t\tcurValue = getClass( elem );\n\t\t\t\tcur = elem.nodeType === 1 && ( \" \" + stripAndCollapse( curValue ) + \" \" );\n\n\t\t\t\tif ( cur ) {\n\t\t\t\t\tj = 0;\n\t\t\t\t\twhile ( ( clazz = classes[ j++ ] ) ) {\n\t\t\t\t\t\tif ( cur.indexOf( \" \" + clazz + \" \" ) < 0 ) {\n\t\t\t\t\t\t\tcur += clazz + \" \";\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Only assign if different to avoid unneeded rendering.\n\t\t\t\t\tfinalValue = stripAndCollapse( cur );\n\t\t\t\t\tif ( curValue !== finalValue ) {\n\t\t\t\t\t\telem.setAttribute( \"class\", finalValue );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\tremoveClass: function( value ) {\n\t\tvar classes, elem, cur, curValue, clazz, j, finalValue,\n\t\t\ti = 0;\n\n\t\tif ( jQuery.isFunction( value ) ) {\n\t\t\treturn this.each( function( j ) {\n\t\t\t\tjQuery( this ).removeClass( value.call( this, j, getClass( this ) ) );\n\t\t\t} );\n\t\t}\n\n\t\tif ( !arguments.length ) {\n\t\t\treturn this.attr( \"class\", \"\" );\n\t\t}\n\n\t\tif ( typeof value === \"string\" && value ) {\n\t\t\tclasses = value.match( rnothtmlwhite ) || [];\n\n\t\t\twhile ( ( elem = this[ i++ ] ) ) {\n\t\t\t\tcurValue = getClass( elem );\n\n\t\t\t\t// This expression is here for better compressibility (see addClass)\n\t\t\t\tcur = elem.nodeType === 1 && ( \" \" + stripAndCollapse( curValue ) + \" \" );\n\n\t\t\t\tif ( cur ) {\n\t\t\t\t\tj = 0;\n\t\t\t\t\twhile ( ( clazz = classes[ j++ ] ) ) {\n\n\t\t\t\t\t\t// Remove *all* instances\n\t\t\t\t\t\twhile ( cur.indexOf( \" \" + clazz + \" \" ) > -1 ) {\n\t\t\t\t\t\t\tcur = cur.replace( \" \" + clazz + \" \", \" \" );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Only assign if different to avoid unneeded rendering.\n\t\t\t\t\tfinalValue = stripAndCollapse( cur );\n\t\t\t\t\tif ( curValue !== finalValue ) {\n\t\t\t\t\t\telem.setAttribute( \"class\", finalValue );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\ttoggleClass: function( value, stateVal ) {\n\t\tvar type = typeof value;\n\n\t\tif ( typeof stateVal === \"boolean\" && type === \"string\" ) {\n\t\t\treturn stateVal ? this.addClass( value ) : this.removeClass( value );\n\t\t}\n\n\t\tif ( jQuery.isFunction( value ) ) {\n\t\t\treturn this.each( function( i ) {\n\t\t\t\tjQuery( this ).toggleClass(\n\t\t\t\t\tvalue.call( this, i, getClass( this ), stateVal ),\n\t\t\t\t\tstateVal\n\t\t\t\t);\n\t\t\t} );\n\t\t}\n\n\t\treturn this.each( function() {\n\t\t\tvar className, i, self, classNames;\n\n\t\t\tif ( type === \"string\" ) {\n\n\t\t\t\t// Toggle individual class names\n\t\t\t\ti = 0;\n\t\t\t\tself = jQuery( this );\n\t\t\t\tclassNames = value.match( rnothtmlwhite ) || [];\n\n\t\t\t\twhile ( ( className = classNames[ i++ ] ) ) {\n\n\t\t\t\t\t// Check each className given, space separated list\n\t\t\t\t\tif ( self.hasClass( className ) ) {\n\t\t\t\t\t\tself.removeClass( className );\n\t\t\t\t\t} else {\n\t\t\t\t\t\tself.addClass( className );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t// Toggle whole class name\n\t\t\t} else if ( value === undefined || type === \"boolean\" ) {\n\t\t\t\tclassName = getClass( this );\n\t\t\t\tif ( className ) {\n\n\t\t\t\t\t// Store className if set\n\t\t\t\t\tdataPriv.set( this, \"__className__\", className );\n\t\t\t\t}\n\n\t\t\t\t// If the element has a class name or if we're passed `false`,\n\t\t\t\t// then remove the whole classname (if there was one, the above saved it).\n\t\t\t\t// Otherwise bring back whatever was previously saved (if anything),\n\t\t\t\t// falling back to the empty string if nothing was stored.\n\t\t\t\tif ( this.setAttribute ) {\n\t\t\t\t\tthis.setAttribute( \"class\",\n\t\t\t\t\t\tclassName || value === false ?\n\t\t\t\t\t\t\"\" :\n\t\t\t\t\t\tdataPriv.get( this, \"__className__\" ) || \"\"\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t},\n\n\thasClass: function( selector ) {\n\t\tvar className, elem,\n\t\t\ti = 0;\n\n\t\tclassName = \" \" + selector + \" \";\n\t\twhile ( ( elem = this[ i++ ] ) ) {\n\t\t\tif ( elem.nodeType === 1 &&\n\t\t\t\t( \" \" + stripAndCollapse( getClass( elem ) ) + \" \" ).indexOf( className ) > -1 ) {\n\t\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n} );\n\n\n\n\nvar rreturn = /\\r/g;\n\njQuery.fn.extend( {\n\tval: function( value ) {\n\t\tvar hooks, ret, isFunction,\n\t\t\telem = this[ 0 ];\n\n\t\tif ( !arguments.length ) {\n\t\t\tif ( elem ) {\n\t\t\t\thooks = jQuery.valHooks[ elem.type ] ||\n\t\t\t\t\tjQuery.valHooks[ elem.nodeName.toLowerCase() ];\n\n\t\t\t\tif ( hooks &&\n\t\t\t\t\t\"get\" in hooks &&\n\t\t\t\t\t( ret = hooks.get( elem, \"value\" ) ) !== undefined\n\t\t\t\t) {\n\t\t\t\t\treturn ret;\n\t\t\t\t}\n\n\t\t\t\tret = elem.value;\n\n\t\t\t\t// Handle most common string cases\n\t\t\t\tif ( typeof ret === \"string\" ) {\n\t\t\t\t\treturn ret.replace( rreturn, \"\" );\n\t\t\t\t}\n\n\t\t\t\t// Handle cases where value is null/undef or number\n\t\t\t\treturn ret == null ? \"\" : ret;\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\tisFunction = jQuery.isFunction( value );\n\n\t\treturn this.each( function( i ) {\n\t\t\tvar val;\n\n\t\t\tif ( this.nodeType !== 1 ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( isFunction ) {\n\t\t\t\tval = value.call( this, i, jQuery( this ).val() );\n\t\t\t} else {\n\t\t\t\tval = value;\n\t\t\t}\n\n\t\t\t// Treat null/undefined as \"\"; convert numbers to string\n\t\t\tif ( val == null ) {\n\t\t\t\tval = \"\";\n\n\t\t\t} else if ( typeof val === \"number\" ) {\n\t\t\t\tval += \"\";\n\n\t\t\t} else if ( Array.isArray( val ) ) {\n\t\t\t\tval = jQuery.map( val, function( value ) {\n\t\t\t\t\treturn value == null ? \"\" : value + \"\";\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\thooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];\n\n\t\t\t// If set returns undefined, fall back to normal setting\n\t\t\tif ( !hooks || !( \"set\" in hooks ) || hooks.set( this, val, \"value\" ) === undefined ) {\n\t\t\t\tthis.value = val;\n\t\t\t}\n\t\t} );\n\t}\n} );\n\njQuery.extend( {\n\tvalHooks: {\n\t\toption: {\n\t\t\tget: function( elem ) {\n\n\t\t\t\tvar val = jQuery.find.attr( elem, \"value\" );\n\t\t\t\treturn val != null ?\n\t\t\t\t\tval :\n\n\t\t\t\t\t// Support: IE <=10 - 11 only\n\t\t\t\t\t// option.text throws exceptions (#14686, #14858)\n\t\t\t\t\t// Strip and collapse whitespace\n\t\t\t\t\t// https://html.spec.whatwg.org/#strip-and-collapse-whitespace\n\t\t\t\t\tstripAndCollapse( jQuery.text( elem ) );\n\t\t\t}\n\t\t},\n\t\tselect: {\n\t\t\tget: function( elem ) {\n\t\t\t\tvar value, option, i,\n\t\t\t\t\toptions = elem.options,\n\t\t\t\t\tindex = elem.selectedIndex,\n\t\t\t\t\tone = elem.type === \"select-one\",\n\t\t\t\t\tvalues = one ? null : [],\n\t\t\t\t\tmax = one ? index + 1 : options.length;\n\n\t\t\t\tif ( index < 0 ) {\n\t\t\t\t\ti = max;\n\n\t\t\t\t} else {\n\t\t\t\t\ti = one ? index : 0;\n\t\t\t\t}\n\n\t\t\t\t// Loop through all the selected options\n\t\t\t\tfor ( ; i < max; i++ ) {\n\t\t\t\t\toption = options[ i ];\n\n\t\t\t\t\t// Support: IE <=9 only\n\t\t\t\t\t// IE8-9 doesn't update selected after form reset (#2551)\n\t\t\t\t\tif ( ( option.selected || i === index ) &&\n\n\t\t\t\t\t\t\t// Don't return options that are disabled or in a disabled optgroup\n\t\t\t\t\t\t\t!option.disabled &&\n\t\t\t\t\t\t\t( !option.parentNode.disabled ||\n\t\t\t\t\t\t\t\t!nodeName( option.parentNode, \"optgroup\" ) ) ) {\n\n\t\t\t\t\t\t// Get the specific value for the option\n\t\t\t\t\t\tvalue = jQuery( option ).val();\n\n\t\t\t\t\t\t// We don't need an array for one selects\n\t\t\t\t\t\tif ( one ) {\n\t\t\t\t\t\t\treturn value;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Multi-Selects return an array\n\t\t\t\t\t\tvalues.push( value );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn values;\n\t\t\t},\n\n\t\t\tset: function( elem, value ) {\n\t\t\t\tvar optionSet, option,\n\t\t\t\t\toptions = elem.options,\n\t\t\t\t\tvalues = jQuery.makeArray( value ),\n\t\t\t\t\ti = options.length;\n\n\t\t\t\twhile ( i-- ) {\n\t\t\t\t\toption = options[ i ];\n\n\t\t\t\t\t/* eslint-disable no-cond-assign */\n\n\t\t\t\t\tif ( option.selected =\n\t\t\t\t\t\tjQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1\n\t\t\t\t\t) {\n\t\t\t\t\t\toptionSet = true;\n\t\t\t\t\t}\n\n\t\t\t\t\t/* eslint-enable no-cond-assign */\n\t\t\t\t}\n\n\t\t\t\t// Force browsers to behave consistently when non-matching value is set\n\t\t\t\tif ( !optionSet ) {\n\t\t\t\t\telem.selectedIndex = -1;\n\t\t\t\t}\n\t\t\t\treturn values;\n\t\t\t}\n\t\t}\n\t}\n} );\n\n// Radios and checkboxes getter/setter\njQuery.each( [ \"radio\", \"checkbox\" ], function() {\n\tjQuery.valHooks[ this ] = {\n\t\tset: function( elem, value ) {\n\t\t\tif ( Array.isArray( value ) ) {\n\t\t\t\treturn ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 );\n\t\t\t}\n\t\t}\n\t};\n\tif ( !support.checkOn ) {\n\t\tjQuery.valHooks[ this ].get = function( elem ) {\n\t\t\treturn elem.getAttribute( \"value\" ) === null ? \"on\" : elem.value;\n\t\t};\n\t}\n} );\n\n\n\n\n// Return jQuery for attributes-only inclusion\n\n\nvar rfocusMorph = /^(?:focusinfocus|focusoutblur)$/;\n\njQuery.extend( jQuery.event, {\n\n\ttrigger: function( event, data, elem, onlyHandlers ) {\n\n\t\tvar i, cur, tmp, bubbleType, ontype, handle, special,\n\t\t\teventPath = [ elem || document ],\n\t\t\ttype = hasOwn.call( event, \"type\" ) ? event.type : event,\n\t\t\tnamespaces = hasOwn.call( event, \"namespace\" ) ? event.namespace.split( \".\" ) : [];\n\n\t\tcur = tmp = elem = elem || document;\n\n\t\t// Don't do events on text and comment nodes\n\t\tif ( elem.nodeType === 3 || elem.nodeType === 8 ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// focus/blur morphs to focusin/out; ensure we're not firing them right now\n\t\tif ( rfocusMorph.test( type + jQuery.event.triggered ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( type.indexOf( \".\" ) > -1 ) {\n\n\t\t\t// Namespaced trigger; create a regexp to match event type in handle()\n\t\t\tnamespaces = type.split( \".\" );\n\t\t\ttype = namespaces.shift();\n\t\t\tnamespaces.sort();\n\t\t}\n\t\tontype = type.indexOf( \":\" ) < 0 && \"on\" + type;\n\n\t\t// Caller can pass in a jQuery.Event object, Object, or just an event type string\n\t\tevent = event[ jQuery.expando ] ?\n\t\t\tevent :\n\t\t\tnew jQuery.Event( type, typeof event === \"object\" && event );\n\n\t\t// Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)\n\t\tevent.isTrigger = onlyHandlers ? 2 : 3;\n\t\tevent.namespace = namespaces.join( \".\" );\n\t\tevent.rnamespace = event.namespace ?\n\t\t\tnew RegExp( \"(^|\\\\.)\" + namespaces.join( \"\\\\.(?:.*\\\\.|)\" ) + \"(\\\\.|$)\" ) :\n\t\t\tnull;\n\n\t\t// Clean up the event in case it is being reused\n\t\tevent.result = undefined;\n\t\tif ( !event.target ) {\n\t\t\tevent.target = elem;\n\t\t}\n\n\t\t// Clone any incoming data and prepend the event, creating the handler arg list\n\t\tdata = data == null ?\n\t\t\t[ event ] :\n\t\t\tjQuery.makeArray( data, [ event ] );\n\n\t\t// Allow special events to draw outside the lines\n\t\tspecial = jQuery.event.special[ type ] || {};\n\t\tif ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Determine event propagation path in advance, per W3C events spec (#9951)\n\t\t// Bubble up to document, then to window; watch for a global ownerDocument var (#9724)\n\t\tif ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {\n\n\t\t\tbubbleType = special.delegateType || type;\n\t\t\tif ( !rfocusMorph.test( bubbleType + type ) ) {\n\t\t\t\tcur = cur.parentNode;\n\t\t\t}\n\t\t\tfor ( ; cur; cur = cur.parentNode ) {\n\t\t\t\teventPath.push( cur );\n\t\t\t\ttmp = cur;\n\t\t\t}\n\n\t\t\t// Only add window if we got to document (e.g., not plain obj or detached DOM)\n\t\t\tif ( tmp === ( elem.ownerDocument || document ) ) {\n\t\t\t\teventPath.push( tmp.defaultView || tmp.parentWindow || window );\n\t\t\t}\n\t\t}\n\n\t\t// Fire handlers on the event path\n\t\ti = 0;\n\t\twhile ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) {\n\n\t\t\tevent.type = i > 1 ?\n\t\t\t\tbubbleType :\n\t\t\t\tspecial.bindType || type;\n\n\t\t\t// jQuery handler\n\t\t\thandle = ( dataPriv.get( cur, \"events\" ) || {} )[ event.type ] &&\n\t\t\t\tdataPriv.get( cur, \"handle\" );\n\t\t\tif ( handle ) {\n\t\t\t\thandle.apply( cur, data );\n\t\t\t}\n\n\t\t\t// Native handler\n\t\t\thandle = ontype && cur[ ontype ];\n\t\t\tif ( handle && handle.apply && acceptData( cur ) ) {\n\t\t\t\tevent.result = handle.apply( cur, data );\n\t\t\t\tif ( event.result === false ) {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tevent.type = type;\n\n\t\t// If nobody prevented the default action, do it now\n\t\tif ( !onlyHandlers && !event.isDefaultPrevented() ) {\n\n\t\t\tif ( ( !special._default ||\n\t\t\t\tspecial._default.apply( eventPath.pop(), data ) === false ) &&\n\t\t\t\tacceptData( elem ) ) {\n\n\t\t\t\t// Call a native DOM method on the target with the same name as the event.\n\t\t\t\t// Don't do default actions on window, that's where global variables be (#6170)\n\t\t\t\tif ( ontype && jQuery.isFunction( elem[ type ] ) && !jQuery.isWindow( elem ) ) {\n\n\t\t\t\t\t// Don't re-trigger an onFOO event when we call its FOO() method\n\t\t\t\t\ttmp = elem[ ontype ];\n\n\t\t\t\t\tif ( tmp ) {\n\t\t\t\t\t\telem[ ontype ] = null;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Prevent re-triggering of the same event, since we already bubbled it above\n\t\t\t\t\tjQuery.event.triggered = type;\n\t\t\t\t\telem[ type ]();\n\t\t\t\t\tjQuery.event.triggered = undefined;\n\n\t\t\t\t\tif ( tmp ) {\n\t\t\t\t\t\telem[ ontype ] = tmp;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn event.result;\n\t},\n\n\t// Piggyback on a donor event to simulate a different one\n\t// Used only for `focus(in | out)` events\n\tsimulate: function( type, elem, event ) {\n\t\tvar e = jQuery.extend(\n\t\t\tnew jQuery.Event(),\n\t\t\tevent,\n\t\t\t{\n\t\t\t\ttype: type,\n\t\t\t\tisSimulated: true\n\t\t\t}\n\t\t);\n\n\t\tjQuery.event.trigger( e, null, elem );\n\t}\n\n} );\n\njQuery.fn.extend( {\n\n\ttrigger: function( type, data ) {\n\t\treturn this.each( function() {\n\t\t\tjQuery.event.trigger( type, data, this );\n\t\t} );\n\t},\n\ttriggerHandler: function( type, data ) {\n\t\tvar elem = this[ 0 ];\n\t\tif ( elem ) {\n\t\t\treturn jQuery.event.trigger( type, data, elem, true );\n\t\t}\n\t}\n} );\n\n\njQuery.each( ( \"blur focus focusin focusout resize scroll click dblclick \" +\n\t\"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave \" +\n\t\"change select submit keydown keypress keyup contextmenu\" ).split( \" \" ),\n\tfunction( i, name ) {\n\n\t// Handle event binding\n\tjQuery.fn[ name ] = function( data, fn ) {\n\t\treturn arguments.length > 0 ?\n\t\t\tthis.on( name, null, data, fn ) :\n\t\t\tthis.trigger( name );\n\t};\n} );\n\njQuery.fn.extend( {\n\thover: function( fnOver, fnOut ) {\n\t\treturn this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );\n\t}\n} );\n\n\n\n\nsupport.focusin = \"onfocusin\" in window;\n\n\n// Support: Firefox <=44\n// Firefox doesn't have focus(in | out) events\n// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787\n//\n// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1\n// focus(in | out) events fire after focus & blur events,\n// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order\n// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857\nif ( !support.focusin ) {\n\tjQuery.each( { focus: \"focusin\", blur: \"focusout\" }, function( orig, fix ) {\n\n\t\t// Attach a single capturing handler on the document while someone wants focusin/focusout\n\t\tvar handler = function( event ) {\n\t\t\tjQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) );\n\t\t};\n\n\t\tjQuery.event.special[ fix ] = {\n\t\t\tsetup: function() {\n\t\t\t\tvar doc = this.ownerDocument || this,\n\t\t\t\t\tattaches = dataPriv.access( doc, fix );\n\n\t\t\t\tif ( !attaches ) {\n\t\t\t\t\tdoc.addEventListener( orig, handler, true );\n\t\t\t\t}\n\t\t\t\tdataPriv.access( doc, fix, ( attaches || 0 ) + 1 );\n\t\t\t},\n\t\t\tteardown: function() {\n\t\t\t\tvar doc = this.ownerDocument || this,\n\t\t\t\t\tattaches = dataPriv.access( doc, fix ) - 1;\n\n\t\t\t\tif ( !attaches ) {\n\t\t\t\t\tdoc.removeEventListener( orig, handler, true );\n\t\t\t\t\tdataPriv.remove( doc, fix );\n\n\t\t\t\t} else {\n\t\t\t\t\tdataPriv.access( doc, fix, attaches );\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t} );\n}\nvar location = window.location;\n\nvar nonce = jQuery.now();\n\nvar rquery = ( /\\?/ );\n\n\n\n// Cross-browser xml parsing\njQuery.parseXML = function( data ) {\n\tvar xml;\n\tif ( !data || typeof data !== \"string\" ) {\n\t\treturn null;\n\t}\n\n\t// Support: IE 9 - 11 only\n\t// IE throws on parseFromString with invalid input.\n\ttry {\n\t\txml = ( new window.DOMParser() ).parseFromString( data, \"text/xml\" );\n\t} catch ( e ) {\n\t\txml = undefined;\n\t}\n\n\tif ( !xml || xml.getElementsByTagName( \"parsererror\" ).length ) {\n\t\tjQuery.error( \"Invalid XML: \" + data );\n\t}\n\treturn xml;\n};\n\n\nvar\n\trbracket = /\\[\\]$/,\n\trCRLF = /\\r?\\n/g,\n\trsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,\n\trsubmittable = /^(?:input|select|textarea|keygen)/i;\n\nfunction buildParams( prefix, obj, traditional, add ) {\n\tvar name;\n\n\tif ( Array.isArray( obj ) ) {\n\n\t\t// Serialize array item.\n\t\tjQuery.each( obj, function( i, v ) {\n\t\t\tif ( traditional || rbracket.test( prefix ) ) {\n\n\t\t\t\t// Treat each array item as a scalar.\n\t\t\t\tadd( prefix, v );\n\n\t\t\t} else {\n\n\t\t\t\t// Item is non-scalar (array or object), encode its numeric index.\n\t\t\t\tbuildParams(\n\t\t\t\t\tprefix + \"[\" + ( typeof v === \"object\" && v != null ? i : \"\" ) + \"]\",\n\t\t\t\t\tv,\n\t\t\t\t\ttraditional,\n\t\t\t\t\tadd\n\t\t\t\t);\n\t\t\t}\n\t\t} );\n\n\t} else if ( !traditional && jQuery.type( obj ) === \"object\" ) {\n\n\t\t// Serialize object item.\n\t\tfor ( name in obj ) {\n\t\t\tbuildParams( prefix + \"[\" + name + \"]\", obj[ name ], traditional, add );\n\t\t}\n\n\t} else {\n\n\t\t// Serialize scalar item.\n\t\tadd( prefix, obj );\n\t}\n}\n\n// Serialize an array of form elements or a set of\n// key/values into a query string\njQuery.param = function( a, traditional ) {\n\tvar prefix,\n\t\ts = [],\n\t\tadd = function( key, valueOrFunction ) {\n\n\t\t\t// If value is a function, invoke it and use its return value\n\t\t\tvar value = jQuery.isFunction( valueOrFunction ) ?\n\t\t\t\tvalueOrFunction() :\n\t\t\t\tvalueOrFunction;\n\n\t\t\ts[ s.length ] = encodeURIComponent( key ) + \"=\" +\n\t\t\t\tencodeURIComponent( value == null ? \"\" : value );\n\t\t};\n\n\t// If an array was passed in, assume that it is an array of form elements.\n\tif ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {\n\n\t\t// Serialize the form elements\n\t\tjQuery.each( a, function() {\n\t\t\tadd( this.name, this.value );\n\t\t} );\n\n\t} else {\n\n\t\t// If traditional, encode the \"old\" way (the way 1.3.2 or older\n\t\t// did it), otherwise encode params recursively.\n\t\tfor ( prefix in a ) {\n\t\t\tbuildParams( prefix, a[ prefix ], traditional, add );\n\t\t}\n\t}\n\n\t// Return the resulting serialization\n\treturn s.join( \"&\" );\n};\n\njQuery.fn.extend( {\n\tserialize: function() {\n\t\treturn jQuery.param( this.serializeArray() );\n\t},\n\tserializeArray: function() {\n\t\treturn this.map( function() {\n\n\t\t\t// Can add propHook for \"elements\" to filter or add form elements\n\t\t\tvar elements = jQuery.prop( this, \"elements\" );\n\t\t\treturn elements ? jQuery.makeArray( elements ) : this;\n\t\t} )\n\t\t.filter( function() {\n\t\t\tvar type = this.type;\n\n\t\t\t// Use .is( \":disabled\" ) so that fieldset[disabled] works\n\t\t\treturn this.name && !jQuery( this ).is( \":disabled\" ) &&\n\t\t\t\trsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&\n\t\t\t\t( this.checked || !rcheckableType.test( type ) );\n\t\t} )\n\t\t.map( function( i, elem ) {\n\t\t\tvar val = jQuery( this ).val();\n\n\t\t\tif ( val == null ) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tif ( Array.isArray( val ) ) {\n\t\t\t\treturn jQuery.map( val, function( val ) {\n\t\t\t\t\treturn { name: elem.name, value: val.replace( rCRLF, \"\\r\\n\" ) };\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\treturn { name: elem.name, value: val.replace( rCRLF, \"\\r\\n\" ) };\n\t\t} ).get();\n\t}\n} );\n\n\nvar\n\tr20 = /%20/g,\n\trhash = /#.*$/,\n\trantiCache = /([?&])_=[^&]*/,\n\trheaders = /^(.*?):[ \\t]*([^\\r\\n]*)$/mg,\n\n\t// #7653, #8125, #8152: local protocol detection\n\trlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,\n\trnoContent = /^(?:GET|HEAD)$/,\n\trprotocol = /^\\/\\//,\n\n\t/* Prefilters\n\t * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)\n\t * 2) These are called:\n\t *    - BEFORE asking for a transport\n\t *    - AFTER param serialization (s.data is a string if s.processData is true)\n\t * 3) key is the dataType\n\t * 4) the catchall symbol \"*\" can be used\n\t * 5) execution will start with transport dataType and THEN continue down to \"*\" if needed\n\t */\n\tprefilters = {},\n\n\t/* Transports bindings\n\t * 1) key is the dataType\n\t * 2) the catchall symbol \"*\" can be used\n\t * 3) selection will start with transport dataType and THEN go to \"*\" if needed\n\t */\n\ttransports = {},\n\n\t// Avoid comment-prolog char sequence (#10098); must appease lint and evade compression\n\tallTypes = \"*/\".concat( \"*\" ),\n\n\t// Anchor tag for parsing the document origin\n\toriginAnchor = document.createElement( \"a\" );\n\toriginAnchor.href = location.href;\n\n// Base \"constructor\" for jQuery.ajaxPrefilter and jQuery.ajaxTransport\nfunction addToPrefiltersOrTransports( structure ) {\n\n\t// dataTypeExpression is optional and defaults to \"*\"\n\treturn function( dataTypeExpression, func ) {\n\n\t\tif ( typeof dataTypeExpression !== \"string\" ) {\n\t\t\tfunc = dataTypeExpression;\n\t\t\tdataTypeExpression = \"*\";\n\t\t}\n\n\t\tvar dataType,\n\t\t\ti = 0,\n\t\t\tdataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || [];\n\n\t\tif ( jQuery.isFunction( func ) ) {\n\n\t\t\t// For each dataType in the dataTypeExpression\n\t\t\twhile ( ( dataType = dataTypes[ i++ ] ) ) {\n\n\t\t\t\t// Prepend if requested\n\t\t\t\tif ( dataType[ 0 ] === \"+\" ) {\n\t\t\t\t\tdataType = dataType.slice( 1 ) || \"*\";\n\t\t\t\t\t( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func );\n\n\t\t\t\t// Otherwise append\n\t\t\t\t} else {\n\t\t\t\t\t( structure[ dataType ] = structure[ dataType ] || [] ).push( func );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n}\n\n// Base inspection function for prefilters and transports\nfunction inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {\n\n\tvar inspected = {},\n\t\tseekingTransport = ( structure === transports );\n\n\tfunction inspect( dataType ) {\n\t\tvar selected;\n\t\tinspected[ dataType ] = true;\n\t\tjQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {\n\t\t\tvar dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );\n\t\t\tif ( typeof dataTypeOrTransport === \"string\" &&\n\t\t\t\t!seekingTransport && !inspected[ dataTypeOrTransport ] ) {\n\n\t\t\t\toptions.dataTypes.unshift( dataTypeOrTransport );\n\t\t\t\tinspect( dataTypeOrTransport );\n\t\t\t\treturn false;\n\t\t\t} else if ( seekingTransport ) {\n\t\t\t\treturn !( selected = dataTypeOrTransport );\n\t\t\t}\n\t\t} );\n\t\treturn selected;\n\t}\n\n\treturn inspect( options.dataTypes[ 0 ] ) || !inspected[ \"*\" ] && inspect( \"*\" );\n}\n\n// A special extend for ajax options\n// that takes \"flat\" options (not to be deep extended)\n// Fixes #9887\nfunction ajaxExtend( target, src ) {\n\tvar key, deep,\n\t\tflatOptions = jQuery.ajaxSettings.flatOptions || {};\n\n\tfor ( key in src ) {\n\t\tif ( src[ key ] !== undefined ) {\n\t\t\t( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ];\n\t\t}\n\t}\n\tif ( deep ) {\n\t\tjQuery.extend( true, target, deep );\n\t}\n\n\treturn target;\n}\n\n/* Handles responses to an ajax request:\n * - finds the right dataType (mediates between content-type and expected dataType)\n * - returns the corresponding response\n */\nfunction ajaxHandleResponses( s, jqXHR, responses ) {\n\n\tvar ct, type, finalDataType, firstDataType,\n\t\tcontents = s.contents,\n\t\tdataTypes = s.dataTypes;\n\n\t// Remove auto dataType and get content-type in the process\n\twhile ( dataTypes[ 0 ] === \"*\" ) {\n\t\tdataTypes.shift();\n\t\tif ( ct === undefined ) {\n\t\t\tct = s.mimeType || jqXHR.getResponseHeader( \"Content-Type\" );\n\t\t}\n\t}\n\n\t// Check if we're dealing with a known content-type\n\tif ( ct ) {\n\t\tfor ( type in contents ) {\n\t\t\tif ( contents[ type ] && contents[ type ].test( ct ) ) {\n\t\t\t\tdataTypes.unshift( type );\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Check to see if we have a response for the expected dataType\n\tif ( dataTypes[ 0 ] in responses ) {\n\t\tfinalDataType = dataTypes[ 0 ];\n\t} else {\n\n\t\t// Try convertible dataTypes\n\t\tfor ( type in responses ) {\n\t\t\tif ( !dataTypes[ 0 ] || s.converters[ type + \" \" + dataTypes[ 0 ] ] ) {\n\t\t\t\tfinalDataType = type;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif ( !firstDataType ) {\n\t\t\t\tfirstDataType = type;\n\t\t\t}\n\t\t}\n\n\t\t// Or just use first one\n\t\tfinalDataType = finalDataType || firstDataType;\n\t}\n\n\t// If we found a dataType\n\t// We add the dataType to the list if needed\n\t// and return the corresponding response\n\tif ( finalDataType ) {\n\t\tif ( finalDataType !== dataTypes[ 0 ] ) {\n\t\t\tdataTypes.unshift( finalDataType );\n\t\t}\n\t\treturn responses[ finalDataType ];\n\t}\n}\n\n/* Chain conversions given the request and the original response\n * Also sets the responseXXX fields on the jqXHR instance\n */\nfunction ajaxConvert( s, response, jqXHR, isSuccess ) {\n\tvar conv2, current, conv, tmp, prev,\n\t\tconverters = {},\n\n\t\t// Work with a copy of dataTypes in case we need to modify it for conversion\n\t\tdataTypes = s.dataTypes.slice();\n\n\t// Create converters map with lowercased keys\n\tif ( dataTypes[ 1 ] ) {\n\t\tfor ( conv in s.converters ) {\n\t\t\tconverters[ conv.toLowerCase() ] = s.converters[ conv ];\n\t\t}\n\t}\n\n\tcurrent = dataTypes.shift();\n\n\t// Convert to each sequential dataType\n\twhile ( current ) {\n\n\t\tif ( s.responseFields[ current ] ) {\n\t\t\tjqXHR[ s.responseFields[ current ] ] = response;\n\t\t}\n\n\t\t// Apply the dataFilter if provided\n\t\tif ( !prev && isSuccess && s.dataFilter ) {\n\t\t\tresponse = s.dataFilter( response, s.dataType );\n\t\t}\n\n\t\tprev = current;\n\t\tcurrent = dataTypes.shift();\n\n\t\tif ( current ) {\n\n\t\t\t// There's only work to do if current dataType is non-auto\n\t\t\tif ( current === \"*\" ) {\n\n\t\t\t\tcurrent = prev;\n\n\t\t\t// Convert response if prev dataType is non-auto and differs from current\n\t\t\t} else if ( prev !== \"*\" && prev !== current ) {\n\n\t\t\t\t// Seek a direct converter\n\t\t\t\tconv = converters[ prev + \" \" + current ] || converters[ \"* \" + current ];\n\n\t\t\t\t// If none found, seek a pair\n\t\t\t\tif ( !conv ) {\n\t\t\t\t\tfor ( conv2 in converters ) {\n\n\t\t\t\t\t\t// If conv2 outputs current\n\t\t\t\t\t\ttmp = conv2.split( \" \" );\n\t\t\t\t\t\tif ( tmp[ 1 ] === current ) {\n\n\t\t\t\t\t\t\t// If prev can be converted to accepted input\n\t\t\t\t\t\t\tconv = converters[ prev + \" \" + tmp[ 0 ] ] ||\n\t\t\t\t\t\t\t\tconverters[ \"* \" + tmp[ 0 ] ];\n\t\t\t\t\t\t\tif ( conv ) {\n\n\t\t\t\t\t\t\t\t// Condense equivalence converters\n\t\t\t\t\t\t\t\tif ( conv === true ) {\n\t\t\t\t\t\t\t\t\tconv = converters[ conv2 ];\n\n\t\t\t\t\t\t\t\t// Otherwise, insert the intermediate dataType\n\t\t\t\t\t\t\t\t} else if ( converters[ conv2 ] !== true ) {\n\t\t\t\t\t\t\t\t\tcurrent = tmp[ 0 ];\n\t\t\t\t\t\t\t\t\tdataTypes.unshift( tmp[ 1 ] );\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Apply converter (if not an equivalence)\n\t\t\t\tif ( conv !== true ) {\n\n\t\t\t\t\t// Unless errors are allowed to bubble, catch and return them\n\t\t\t\t\tif ( conv && s.throws ) {\n\t\t\t\t\t\tresponse = conv( response );\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tresponse = conv( response );\n\t\t\t\t\t\t} catch ( e ) {\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\tstate: \"parsererror\",\n\t\t\t\t\t\t\t\terror: conv ? e : \"No conversion from \" + prev + \" to \" + current\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn { state: \"success\", data: response };\n}\n\njQuery.extend( {\n\n\t// Counter for holding the number of active queries\n\tactive: 0,\n\n\t// Last-Modified header cache for next request\n\tlastModified: {},\n\tetag: {},\n\n\tajaxSettings: {\n\t\turl: location.href,\n\t\ttype: \"GET\",\n\t\tisLocal: rlocalProtocol.test( location.protocol ),\n\t\tglobal: true,\n\t\tprocessData: true,\n\t\tasync: true,\n\t\tcontentType: \"application/x-www-form-urlencoded; charset=UTF-8\",\n\n\t\t/*\n\t\ttimeout: 0,\n\t\tdata: null,\n\t\tdataType: null,\n\t\tusername: null,\n\t\tpassword: null,\n\t\tcache: null,\n\t\tthrows: false,\n\t\ttraditional: false,\n\t\theaders: {},\n\t\t*/\n\n\t\taccepts: {\n\t\t\t\"*\": allTypes,\n\t\t\ttext: \"text/plain\",\n\t\t\thtml: \"text/html\",\n\t\t\txml: \"application/xml, text/xml\",\n\t\t\tjson: \"application/json, text/javascript\"\n\t\t},\n\n\t\tcontents: {\n\t\t\txml: /\\bxml\\b/,\n\t\t\thtml: /\\bhtml/,\n\t\t\tjson: /\\bjson\\b/\n\t\t},\n\n\t\tresponseFields: {\n\t\t\txml: \"responseXML\",\n\t\t\ttext: \"responseText\",\n\t\t\tjson: \"responseJSON\"\n\t\t},\n\n\t\t// Data converters\n\t\t// Keys separate source (or catchall \"*\") and destination types with a single space\n\t\tconverters: {\n\n\t\t\t// Convert anything to text\n\t\t\t\"* text\": String,\n\n\t\t\t// Text to html (true = no transformation)\n\t\t\t\"text html\": true,\n\n\t\t\t// Evaluate text as a json expression\n\t\t\t\"text json\": JSON.parse,\n\n\t\t\t// Parse text as xml\n\t\t\t\"text xml\": jQuery.parseXML\n\t\t},\n\n\t\t// For options that shouldn't be deep extended:\n\t\t// you can add your own custom options here if\n\t\t// and when you create one that shouldn't be\n\t\t// deep extended (see ajaxExtend)\n\t\tflatOptions: {\n\t\t\turl: true,\n\t\t\tcontext: true\n\t\t}\n\t},\n\n\t// Creates a full fledged settings object into target\n\t// with both ajaxSettings and settings fields.\n\t// If target is omitted, writes into ajaxSettings.\n\tajaxSetup: function( target, settings ) {\n\t\treturn settings ?\n\n\t\t\t// Building a settings object\n\t\t\tajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) :\n\n\t\t\t// Extending ajaxSettings\n\t\t\tajaxExtend( jQuery.ajaxSettings, target );\n\t},\n\n\tajaxPrefilter: addToPrefiltersOrTransports( prefilters ),\n\tajaxTransport: addToPrefiltersOrTransports( transports ),\n\n\t// Main method\n\tajax: function( url, options ) {\n\n\t\t// If url is an object, simulate pre-1.5 signature\n\t\tif ( typeof url === \"object\" ) {\n\t\t\toptions = url;\n\t\t\turl = undefined;\n\t\t}\n\n\t\t// Force options to be an object\n\t\toptions = options || {};\n\n\t\tvar transport,\n\n\t\t\t// URL without anti-cache param\n\t\t\tcacheURL,\n\n\t\t\t// Response headers\n\t\t\tresponseHeadersString,\n\t\t\tresponseHeaders,\n\n\t\t\t// timeout handle\n\t\t\ttimeoutTimer,\n\n\t\t\t// Url cleanup var\n\t\t\turlAnchor,\n\n\t\t\t// Request state (becomes false upon send and true upon completion)\n\t\t\tcompleted,\n\n\t\t\t// To know if global events are to be dispatched\n\t\t\tfireGlobals,\n\n\t\t\t// Loop variable\n\t\t\ti,\n\n\t\t\t// uncached part of the url\n\t\t\tuncached,\n\n\t\t\t// Create the final options object\n\t\t\ts = jQuery.ajaxSetup( {}, options ),\n\n\t\t\t// Callbacks context\n\t\t\tcallbackContext = s.context || s,\n\n\t\t\t// Context for global events is callbackContext if it is a DOM node or jQuery collection\n\t\t\tglobalEventContext = s.context &&\n\t\t\t\t( callbackContext.nodeType || callbackContext.jquery ) ?\n\t\t\t\t\tjQuery( callbackContext ) :\n\t\t\t\t\tjQuery.event,\n\n\t\t\t// Deferreds\n\t\t\tdeferred = jQuery.Deferred(),\n\t\t\tcompleteDeferred = jQuery.Callbacks( \"once memory\" ),\n\n\t\t\t// Status-dependent callbacks\n\t\t\tstatusCode = s.statusCode || {},\n\n\t\t\t// Headers (they are sent all at once)\n\t\t\trequestHeaders = {},\n\t\t\trequestHeadersNames = {},\n\n\t\t\t// Default abort message\n\t\t\tstrAbort = \"canceled\",\n\n\t\t\t// Fake xhr\n\t\t\tjqXHR = {\n\t\t\t\treadyState: 0,\n\n\t\t\t\t// Builds headers hashtable if needed\n\t\t\t\tgetResponseHeader: function( key ) {\n\t\t\t\t\tvar match;\n\t\t\t\t\tif ( completed ) {\n\t\t\t\t\t\tif ( !responseHeaders ) {\n\t\t\t\t\t\t\tresponseHeaders = {};\n\t\t\t\t\t\t\twhile ( ( match = rheaders.exec( responseHeadersString ) ) ) {\n\t\t\t\t\t\t\t\tresponseHeaders[ match[ 1 ].toLowerCase() ] = match[ 2 ];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tmatch = responseHeaders[ key.toLowerCase() ];\n\t\t\t\t\t}\n\t\t\t\t\treturn match == null ? null : match;\n\t\t\t\t},\n\n\t\t\t\t// Raw string\n\t\t\t\tgetAllResponseHeaders: function() {\n\t\t\t\t\treturn completed ? responseHeadersString : null;\n\t\t\t\t},\n\n\t\t\t\t// Caches the header\n\t\t\t\tsetRequestHeader: function( name, value ) {\n\t\t\t\t\tif ( completed == null ) {\n\t\t\t\t\t\tname = requestHeadersNames[ name.toLowerCase() ] =\n\t\t\t\t\t\t\trequestHeadersNames[ name.toLowerCase() ] || name;\n\t\t\t\t\t\trequestHeaders[ name ] = value;\n\t\t\t\t\t}\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\n\t\t\t\t// Overrides response content-type header\n\t\t\t\toverrideMimeType: function( type ) {\n\t\t\t\t\tif ( completed == null ) {\n\t\t\t\t\t\ts.mimeType = type;\n\t\t\t\t\t}\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\n\t\t\t\t// Status-dependent callbacks\n\t\t\t\tstatusCode: function( map ) {\n\t\t\t\t\tvar code;\n\t\t\t\t\tif ( map ) {\n\t\t\t\t\t\tif ( completed ) {\n\n\t\t\t\t\t\t\t// Execute the appropriate callbacks\n\t\t\t\t\t\t\tjqXHR.always( map[ jqXHR.status ] );\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t// Lazy-add the new callbacks in a way that preserves old ones\n\t\t\t\t\t\t\tfor ( code in map ) {\n\t\t\t\t\t\t\t\tstatusCode[ code ] = [ statusCode[ code ], map[ code ] ];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\n\t\t\t\t// Cancel the request\n\t\t\t\tabort: function( statusText ) {\n\t\t\t\t\tvar finalText = statusText || strAbort;\n\t\t\t\t\tif ( transport ) {\n\t\t\t\t\t\ttransport.abort( finalText );\n\t\t\t\t\t}\n\t\t\t\t\tdone( 0, finalText );\n\t\t\t\t\treturn this;\n\t\t\t\t}\n\t\t\t};\n\n\t\t// Attach deferreds\n\t\tdeferred.promise( jqXHR );\n\n\t\t// Add protocol if not provided (prefilters might expect it)\n\t\t// Handle falsy url in the settings object (#10093: consistency with old signature)\n\t\t// We also use the url parameter if available\n\t\ts.url = ( ( url || s.url || location.href ) + \"\" )\n\t\t\t.replace( rprotocol, location.protocol + \"//\" );\n\n\t\t// Alias method option to type as per ticket #12004\n\t\ts.type = options.method || options.type || s.method || s.type;\n\n\t\t// Extract dataTypes list\n\t\ts.dataTypes = ( s.dataType || \"*\" ).toLowerCase().match( rnothtmlwhite ) || [ \"\" ];\n\n\t\t// A cross-domain request is in order when the origin doesn't match the current origin.\n\t\tif ( s.crossDomain == null ) {\n\t\t\turlAnchor = document.createElement( \"a\" );\n\n\t\t\t// Support: IE <=8 - 11, Edge 12 - 13\n\t\t\t// IE throws exception on accessing the href property if url is malformed,\n\t\t\t// e.g. http://example.com:80x/\n\t\t\ttry {\n\t\t\t\turlAnchor.href = s.url;\n\n\t\t\t\t// Support: IE <=8 - 11 only\n\t\t\t\t// Anchor's host property isn't correctly set when s.url is relative\n\t\t\t\turlAnchor.href = urlAnchor.href;\n\t\t\t\ts.crossDomain = originAnchor.protocol + \"//\" + originAnchor.host !==\n\t\t\t\t\turlAnchor.protocol + \"//\" + urlAnchor.host;\n\t\t\t} catch ( e ) {\n\n\t\t\t\t// If there is an error parsing the URL, assume it is crossDomain,\n\t\t\t\t// it can be rejected by the transport if it is invalid\n\t\t\t\ts.crossDomain = true;\n\t\t\t}\n\t\t}\n\n\t\t// Convert data if not already a string\n\t\tif ( s.data && s.processData && typeof s.data !== \"string\" ) {\n\t\t\ts.data = jQuery.param( s.data, s.traditional );\n\t\t}\n\n\t\t// Apply prefilters\n\t\tinspectPrefiltersOrTransports( prefilters, s, options, jqXHR );\n\n\t\t// If request was aborted inside a prefilter, stop there\n\t\tif ( completed ) {\n\t\t\treturn jqXHR;\n\t\t}\n\n\t\t// We can fire global events as of now if asked to\n\t\t// Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118)\n\t\tfireGlobals = jQuery.event && s.global;\n\n\t\t// Watch for a new set of requests\n\t\tif ( fireGlobals && jQuery.active++ === 0 ) {\n\t\t\tjQuery.event.trigger( \"ajaxStart\" );\n\t\t}\n\n\t\t// Uppercase the type\n\t\ts.type = s.type.toUpperCase();\n\n\t\t// Determine if request has content\n\t\ts.hasContent = !rnoContent.test( s.type );\n\n\t\t// Save the URL in case we're toying with the If-Modified-Since\n\t\t// and/or If-None-Match header later on\n\t\t// Remove hash to simplify url manipulation\n\t\tcacheURL = s.url.replace( rhash, \"\" );\n\n\t\t// More options handling for requests with no content\n\t\tif ( !s.hasContent ) {\n\n\t\t\t// Remember the hash so we can put it back\n\t\t\tuncached = s.url.slice( cacheURL.length );\n\n\t\t\t// If data is available, append data to url\n\t\t\tif ( s.data ) {\n\t\t\t\tcacheURL += ( rquery.test( cacheURL ) ? \"&\" : \"?\" ) + s.data;\n\n\t\t\t\t// #9682: remove data so that it's not used in an eventual retry\n\t\t\t\tdelete s.data;\n\t\t\t}\n\n\t\t\t// Add or update anti-cache param if needed\n\t\t\tif ( s.cache === false ) {\n\t\t\t\tcacheURL = cacheURL.replace( rantiCache, \"$1\" );\n\t\t\t\tuncached = ( rquery.test( cacheURL ) ? \"&\" : \"?\" ) + \"_=\" + ( nonce++ ) + uncached;\n\t\t\t}\n\n\t\t\t// Put hash and anti-cache on the URL that will be requested (gh-1732)\n\t\t\ts.url = cacheURL + uncached;\n\n\t\t// Change '%20' to '+' if this is encoded form body content (gh-2658)\n\t\t} else if ( s.data && s.processData &&\n\t\t\t( s.contentType || \"\" ).indexOf( \"application/x-www-form-urlencoded\" ) === 0 ) {\n\t\t\ts.data = s.data.replace( r20, \"+\" );\n\t\t}\n\n\t\t// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.\n\t\tif ( s.ifModified ) {\n\t\t\tif ( jQuery.lastModified[ cacheURL ] ) {\n\t\t\t\tjqXHR.setRequestHeader( \"If-Modified-Since\", jQuery.lastModified[ cacheURL ] );\n\t\t\t}\n\t\t\tif ( jQuery.etag[ cacheURL ] ) {\n\t\t\t\tjqXHR.setRequestHeader( \"If-None-Match\", jQuery.etag[ cacheURL ] );\n\t\t\t}\n\t\t}\n\n\t\t// Set the correct header, if data is being sent\n\t\tif ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {\n\t\t\tjqXHR.setRequestHeader( \"Content-Type\", s.contentType );\n\t\t}\n\n\t\t// Set the Accepts header for the server, depending on the dataType\n\t\tjqXHR.setRequestHeader(\n\t\t\t\"Accept\",\n\t\t\ts.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ?\n\t\t\t\ts.accepts[ s.dataTypes[ 0 ] ] +\n\t\t\t\t\t( s.dataTypes[ 0 ] !== \"*\" ? \", \" + allTypes + \"; q=0.01\" : \"\" ) :\n\t\t\t\ts.accepts[ \"*\" ]\n\t\t);\n\n\t\t// Check for headers option\n\t\tfor ( i in s.headers ) {\n\t\t\tjqXHR.setRequestHeader( i, s.headers[ i ] );\n\t\t}\n\n\t\t// Allow custom headers/mimetypes and early abort\n\t\tif ( s.beforeSend &&\n\t\t\t( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) {\n\n\t\t\t// Abort if not done already and return\n\t\t\treturn jqXHR.abort();\n\t\t}\n\n\t\t// Aborting is no longer a cancellation\n\t\tstrAbort = \"abort\";\n\n\t\t// Install callbacks on deferreds\n\t\tcompleteDeferred.add( s.complete );\n\t\tjqXHR.done( s.success );\n\t\tjqXHR.fail( s.error );\n\n\t\t// Get transport\n\t\ttransport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );\n\n\t\t// If no transport, we auto-abort\n\t\tif ( !transport ) {\n\t\t\tdone( -1, \"No Transport\" );\n\t\t} else {\n\t\t\tjqXHR.readyState = 1;\n\n\t\t\t// Send global event\n\t\t\tif ( fireGlobals ) {\n\t\t\t\tglobalEventContext.trigger( \"ajaxSend\", [ jqXHR, s ] );\n\t\t\t}\n\n\t\t\t// If request was aborted inside ajaxSend, stop there\n\t\t\tif ( completed ) {\n\t\t\t\treturn jqXHR;\n\t\t\t}\n\n\t\t\t// Timeout\n\t\t\tif ( s.async && s.timeout > 0 ) {\n\t\t\t\ttimeoutTimer = window.setTimeout( function() {\n\t\t\t\t\tjqXHR.abort( \"timeout\" );\n\t\t\t\t}, s.timeout );\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tcompleted = false;\n\t\t\t\ttransport.send( requestHeaders, done );\n\t\t\t} catch ( e ) {\n\n\t\t\t\t// Rethrow post-completion exceptions\n\t\t\t\tif ( completed ) {\n\t\t\t\t\tthrow e;\n\t\t\t\t}\n\n\t\t\t\t// Propagate others as results\n\t\t\t\tdone( -1, e );\n\t\t\t}\n\t\t}\n\n\t\t// Callback for when everything is done\n\t\tfunction done( status, nativeStatusText, responses, headers ) {\n\t\t\tvar isSuccess, success, error, response, modified,\n\t\t\t\tstatusText = nativeStatusText;\n\n\t\t\t// Ignore repeat invocations\n\t\t\tif ( completed ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tcompleted = true;\n\n\t\t\t// Clear timeout if it exists\n\t\t\tif ( timeoutTimer ) {\n\t\t\t\twindow.clearTimeout( timeoutTimer );\n\t\t\t}\n\n\t\t\t// Dereference transport for early garbage collection\n\t\t\t// (no matter how long the jqXHR object will be used)\n\t\t\ttransport = undefined;\n\n\t\t\t// Cache response headers\n\t\t\tresponseHeadersString = headers || \"\";\n\n\t\t\t// Set readyState\n\t\t\tjqXHR.readyState = status > 0 ? 4 : 0;\n\n\t\t\t// Determine if successful\n\t\t\tisSuccess = status >= 200 && status < 300 || status === 304;\n\n\t\t\t// Get response data\n\t\t\tif ( responses ) {\n\t\t\t\tresponse = ajaxHandleResponses( s, jqXHR, responses );\n\t\t\t}\n\n\t\t\t// Convert no matter what (that way responseXXX fields are always set)\n\t\t\tresponse = ajaxConvert( s, response, jqXHR, isSuccess );\n\n\t\t\t// If successful, handle type chaining\n\t\t\tif ( isSuccess ) {\n\n\t\t\t\t// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.\n\t\t\t\tif ( s.ifModified ) {\n\t\t\t\t\tmodified = jqXHR.getResponseHeader( \"Last-Modified\" );\n\t\t\t\t\tif ( modified ) {\n\t\t\t\t\t\tjQuery.lastModified[ cacheURL ] = modified;\n\t\t\t\t\t}\n\t\t\t\t\tmodified = jqXHR.getResponseHeader( \"etag\" );\n\t\t\t\t\tif ( modified ) {\n\t\t\t\t\t\tjQuery.etag[ cacheURL ] = modified;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// if no content\n\t\t\t\tif ( status === 204 || s.type === \"HEAD\" ) {\n\t\t\t\t\tstatusText = \"nocontent\";\n\n\t\t\t\t// if not modified\n\t\t\t\t} else if ( status === 304 ) {\n\t\t\t\t\tstatusText = \"notmodified\";\n\n\t\t\t\t// If we have data, let's convert it\n\t\t\t\t} else {\n\t\t\t\t\tstatusText = response.state;\n\t\t\t\t\tsuccess = response.data;\n\t\t\t\t\terror = response.error;\n\t\t\t\t\tisSuccess = !error;\n\t\t\t\t}\n\t\t\t} else {\n\n\t\t\t\t// Extract error from statusText and normalize for non-aborts\n\t\t\t\terror = statusText;\n\t\t\t\tif ( status || !statusText ) {\n\t\t\t\t\tstatusText = \"error\";\n\t\t\t\t\tif ( status < 0 ) {\n\t\t\t\t\t\tstatus = 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Set data for the fake xhr object\n\t\t\tjqXHR.status = status;\n\t\t\tjqXHR.statusText = ( nativeStatusText || statusText ) + \"\";\n\n\t\t\t// Success/Error\n\t\t\tif ( isSuccess ) {\n\t\t\t\tdeferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );\n\t\t\t} else {\n\t\t\t\tdeferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );\n\t\t\t}\n\n\t\t\t// Status-dependent callbacks\n\t\t\tjqXHR.statusCode( statusCode );\n\t\t\tstatusCode = undefined;\n\n\t\t\tif ( fireGlobals ) {\n\t\t\t\tglobalEventContext.trigger( isSuccess ? \"ajaxSuccess\" : \"ajaxError\",\n\t\t\t\t\t[ jqXHR, s, isSuccess ? success : error ] );\n\t\t\t}\n\n\t\t\t// Complete\n\t\t\tcompleteDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );\n\n\t\t\tif ( fireGlobals ) {\n\t\t\t\tglobalEventContext.trigger( \"ajaxComplete\", [ jqXHR, s ] );\n\n\t\t\t\t// Handle the global AJAX counter\n\t\t\t\tif ( !( --jQuery.active ) ) {\n\t\t\t\t\tjQuery.event.trigger( \"ajaxStop\" );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn jqXHR;\n\t},\n\n\tgetJSON: function( url, data, callback ) {\n\t\treturn jQuery.get( url, data, callback, \"json\" );\n\t},\n\n\tgetScript: function( url, callback ) {\n\t\treturn jQuery.get( url, undefined, callback, \"script\" );\n\t}\n} );\n\njQuery.each( [ \"get\", \"post\" ], function( i, method ) {\n\tjQuery[ method ] = function( url, data, callback, type ) {\n\n\t\t// Shift arguments if data argument was omitted\n\t\tif ( jQuery.isFunction( data ) ) {\n\t\t\ttype = type || callback;\n\t\t\tcallback = data;\n\t\t\tdata = undefined;\n\t\t}\n\n\t\t// The url can be an options object (which then must have .url)\n\t\treturn jQuery.ajax( jQuery.extend( {\n\t\t\turl: url,\n\t\t\ttype: method,\n\t\t\tdataType: type,\n\t\t\tdata: data,\n\t\t\tsuccess: callback\n\t\t}, jQuery.isPlainObject( url ) && url ) );\n\t};\n} );\n\n\njQuery._evalUrl = function( url ) {\n\treturn jQuery.ajax( {\n\t\turl: url,\n\n\t\t// Make this explicit, since user can override this through ajaxSetup (#11264)\n\t\ttype: \"GET\",\n\t\tdataType: \"script\",\n\t\tcache: true,\n\t\tasync: false,\n\t\tglobal: false,\n\t\t\"throws\": true\n\t} );\n};\n\n\njQuery.fn.extend( {\n\twrapAll: function( html ) {\n\t\tvar wrap;\n\n\t\tif ( this[ 0 ] ) {\n\t\t\tif ( jQuery.isFunction( html ) ) {\n\t\t\t\thtml = html.call( this[ 0 ] );\n\t\t\t}\n\n\t\t\t// The elements to wrap the target around\n\t\t\twrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true );\n\n\t\t\tif ( this[ 0 ].parentNode ) {\n\t\t\t\twrap.insertBefore( this[ 0 ] );\n\t\t\t}\n\n\t\t\twrap.map( function() {\n\t\t\t\tvar elem = this;\n\n\t\t\t\twhile ( elem.firstElementChild ) {\n\t\t\t\t\telem = elem.firstElementChild;\n\t\t\t\t}\n\n\t\t\t\treturn elem;\n\t\t\t} ).append( this );\n\t\t}\n\n\t\treturn this;\n\t},\n\n\twrapInner: function( html ) {\n\t\tif ( jQuery.isFunction( html ) ) {\n\t\t\treturn this.each( function( i ) {\n\t\t\t\tjQuery( this ).wrapInner( html.call( this, i ) );\n\t\t\t} );\n\t\t}\n\n\t\treturn this.each( function() {\n\t\t\tvar self = jQuery( this ),\n\t\t\t\tcontents = self.contents();\n\n\t\t\tif ( contents.length ) {\n\t\t\t\tcontents.wrapAll( html );\n\n\t\t\t} else {\n\t\t\t\tself.append( html );\n\t\t\t}\n\t\t} );\n\t},\n\n\twrap: function( html ) {\n\t\tvar isFunction = jQuery.isFunction( html );\n\n\t\treturn this.each( function( i ) {\n\t\t\tjQuery( this ).wrapAll( isFunction ? html.call( this, i ) : html );\n\t\t} );\n\t},\n\n\tunwrap: function( selector ) {\n\t\tthis.parent( selector ).not( \"body\" ).each( function() {\n\t\t\tjQuery( this ).replaceWith( this.childNodes );\n\t\t} );\n\t\treturn this;\n\t}\n} );\n\n\njQuery.expr.pseudos.hidden = function( elem ) {\n\treturn !jQuery.expr.pseudos.visible( elem );\n};\njQuery.expr.pseudos.visible = function( elem ) {\n\treturn !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length );\n};\n\n\n\n\njQuery.ajaxSettings.xhr = function() {\n\ttry {\n\t\treturn new window.XMLHttpRequest();\n\t} catch ( e ) {}\n};\n\nvar xhrSuccessStatus = {\n\n\t\t// File protocol always yields status code 0, assume 200\n\t\t0: 200,\n\n\t\t// Support: IE <=9 only\n\t\t// #1450: sometimes IE returns 1223 when it should be 204\n\t\t1223: 204\n\t},\n\txhrSupported = jQuery.ajaxSettings.xhr();\n\nsupport.cors = !!xhrSupported && ( \"withCredentials\" in xhrSupported );\nsupport.ajax = xhrSupported = !!xhrSupported;\n\njQuery.ajaxTransport( function( options ) {\n\tvar callback, errorCallback;\n\n\t// Cross domain only allowed if supported through XMLHttpRequest\n\tif ( support.cors || xhrSupported && !options.crossDomain ) {\n\t\treturn {\n\t\t\tsend: function( headers, complete ) {\n\t\t\t\tvar i,\n\t\t\t\t\txhr = options.xhr();\n\n\t\t\t\txhr.open(\n\t\t\t\t\toptions.type,\n\t\t\t\t\toptions.url,\n\t\t\t\t\toptions.async,\n\t\t\t\t\toptions.username,\n\t\t\t\t\toptions.password\n\t\t\t\t);\n\n\t\t\t\t// Apply custom fields if provided\n\t\t\t\tif ( options.xhrFields ) {\n\t\t\t\t\tfor ( i in options.xhrFields ) {\n\t\t\t\t\t\txhr[ i ] = options.xhrFields[ i ];\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Override mime type if needed\n\t\t\t\tif ( options.mimeType && xhr.overrideMimeType ) {\n\t\t\t\t\txhr.overrideMimeType( options.mimeType );\n\t\t\t\t}\n\n\t\t\t\t// X-Requested-With header\n\t\t\t\t// For cross-domain requests, seeing as conditions for a preflight are\n\t\t\t\t// akin to a jigsaw puzzle, we simply never set it to be sure.\n\t\t\t\t// (it can always be set on a per-request basis or even using ajaxSetup)\n\t\t\t\t// For same-domain requests, won't change header if already provided.\n\t\t\t\tif ( !options.crossDomain && !headers[ \"X-Requested-With\" ] ) {\n\t\t\t\t\theaders[ \"X-Requested-With\" ] = \"XMLHttpRequest\";\n\t\t\t\t}\n\n\t\t\t\t// Set headers\n\t\t\t\tfor ( i in headers ) {\n\t\t\t\t\txhr.setRequestHeader( i, headers[ i ] );\n\t\t\t\t}\n\n\t\t\t\t// Callback\n\t\t\t\tcallback = function( type ) {\n\t\t\t\t\treturn function() {\n\t\t\t\t\t\tif ( callback ) {\n\t\t\t\t\t\t\tcallback = errorCallback = xhr.onload =\n\t\t\t\t\t\t\t\txhr.onerror = xhr.onabort = xhr.onreadystatechange = null;\n\n\t\t\t\t\t\t\tif ( type === \"abort\" ) {\n\t\t\t\t\t\t\t\txhr.abort();\n\t\t\t\t\t\t\t} else if ( type === \"error\" ) {\n\n\t\t\t\t\t\t\t\t// Support: IE <=9 only\n\t\t\t\t\t\t\t\t// On a manual native abort, IE9 throws\n\t\t\t\t\t\t\t\t// errors on any property access that is not readyState\n\t\t\t\t\t\t\t\tif ( typeof xhr.status !== \"number\" ) {\n\t\t\t\t\t\t\t\t\tcomplete( 0, \"error\" );\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tcomplete(\n\n\t\t\t\t\t\t\t\t\t\t// File: protocol always yields status 0; see #8605, #14207\n\t\t\t\t\t\t\t\t\t\txhr.status,\n\t\t\t\t\t\t\t\t\t\txhr.statusText\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tcomplete(\n\t\t\t\t\t\t\t\t\txhrSuccessStatus[ xhr.status ] || xhr.status,\n\t\t\t\t\t\t\t\t\txhr.statusText,\n\n\t\t\t\t\t\t\t\t\t// Support: IE <=9 only\n\t\t\t\t\t\t\t\t\t// IE9 has no XHR2 but throws on binary (trac-11426)\n\t\t\t\t\t\t\t\t\t// For XHR2 non-text, let the caller handle it (gh-2498)\n\t\t\t\t\t\t\t\t\t( xhr.responseType || \"text\" ) !== \"text\"  ||\n\t\t\t\t\t\t\t\t\ttypeof xhr.responseText !== \"string\" ?\n\t\t\t\t\t\t\t\t\t\t{ binary: xhr.response } :\n\t\t\t\t\t\t\t\t\t\t{ text: xhr.responseText },\n\t\t\t\t\t\t\t\t\txhr.getAllResponseHeaders()\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\t\t\t\t};\n\n\t\t\t\t// Listen to events\n\t\t\t\txhr.onload = callback();\n\t\t\t\terrorCallback = xhr.onerror = callback( \"error\" );\n\n\t\t\t\t// Support: IE 9 only\n\t\t\t\t// Use onreadystatechange to replace onabort\n\t\t\t\t// to handle uncaught aborts\n\t\t\t\tif ( xhr.onabort !== undefined ) {\n\t\t\t\t\txhr.onabort = errorCallback;\n\t\t\t\t} else {\n\t\t\t\t\txhr.onreadystatechange = function() {\n\n\t\t\t\t\t\t// Check readyState before timeout as it changes\n\t\t\t\t\t\tif ( xhr.readyState === 4 ) {\n\n\t\t\t\t\t\t\t// Allow onerror to be called first,\n\t\t\t\t\t\t\t// but that will not handle a native abort\n\t\t\t\t\t\t\t// Also, save errorCallback to a variable\n\t\t\t\t\t\t\t// as xhr.onerror cannot be accessed\n\t\t\t\t\t\t\twindow.setTimeout( function() {\n\t\t\t\t\t\t\t\tif ( callback ) {\n\t\t\t\t\t\t\t\t\terrorCallback();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\t// Create the abort callback\n\t\t\t\tcallback = callback( \"abort\" );\n\n\t\t\t\ttry {\n\n\t\t\t\t\t// Do send the request (this may raise an exception)\n\t\t\t\t\txhr.send( options.hasContent && options.data || null );\n\t\t\t\t} catch ( e ) {\n\n\t\t\t\t\t// #14683: Only rethrow if this hasn't been notified as an error yet\n\t\t\t\t\tif ( callback ) {\n\t\t\t\t\t\tthrow e;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\n\t\t\tabort: function() {\n\t\t\t\tif ( callback ) {\n\t\t\t\t\tcallback();\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}\n} );\n\n\n\n\n// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432)\njQuery.ajaxPrefilter( function( s ) {\n\tif ( s.crossDomain ) {\n\t\ts.contents.script = false;\n\t}\n} );\n\n// Install script dataType\njQuery.ajaxSetup( {\n\taccepts: {\n\t\tscript: \"text/javascript, application/javascript, \" +\n\t\t\t\"application/ecmascript, application/x-ecmascript\"\n\t},\n\tcontents: {\n\t\tscript: /\\b(?:java|ecma)script\\b/\n\t},\n\tconverters: {\n\t\t\"text script\": function( text ) {\n\t\t\tjQuery.globalEval( text );\n\t\t\treturn text;\n\t\t}\n\t}\n} );\n\n// Handle cache's special case and crossDomain\njQuery.ajaxPrefilter( \"script\", function( s ) {\n\tif ( s.cache === undefined ) {\n\t\ts.cache = false;\n\t}\n\tif ( s.crossDomain ) {\n\t\ts.type = \"GET\";\n\t}\n} );\n\n// Bind script tag hack transport\njQuery.ajaxTransport( \"script\", function( s ) {\n\n\t// This transport only deals with cross domain requests\n\tif ( s.crossDomain ) {\n\t\tvar script, callback;\n\t\treturn {\n\t\t\tsend: function( _, complete ) {\n\t\t\t\tscript = jQuery( \"<script>\" ).prop( {\n\t\t\t\t\tcharset: s.scriptCharset,\n\t\t\t\t\tsrc: s.url\n\t\t\t\t} ).on(\n\t\t\t\t\t\"load error\",\n\t\t\t\t\tcallback = function( evt ) {\n\t\t\t\t\t\tscript.remove();\n\t\t\t\t\t\tcallback = null;\n\t\t\t\t\t\tif ( evt ) {\n\t\t\t\t\t\t\tcomplete( evt.type === \"error\" ? 404 : 200, evt.type );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t);\n\n\t\t\t\t// Use native DOM manipulation to avoid our domManip AJAX trickery\n\t\t\t\tdocument.head.appendChild( script[ 0 ] );\n\t\t\t},\n\t\t\tabort: function() {\n\t\t\t\tif ( callback ) {\n\t\t\t\t\tcallback();\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}\n} );\n\n\n\n\nvar oldCallbacks = [],\n\trjsonp = /(=)\\?(?=&|$)|\\?\\?/;\n\n// Default jsonp settings\njQuery.ajaxSetup( {\n\tjsonp: \"callback\",\n\tjsonpCallback: function() {\n\t\tvar callback = oldCallbacks.pop() || ( jQuery.expando + \"_\" + ( nonce++ ) );\n\t\tthis[ callback ] = true;\n\t\treturn callback;\n\t}\n} );\n\n// Detect, normalize options and install callbacks for jsonp requests\njQuery.ajaxPrefilter( \"json jsonp\", function( s, originalSettings, jqXHR ) {\n\n\tvar callbackName, overwritten, responseContainer,\n\t\tjsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ?\n\t\t\t\"url\" :\n\t\t\ttypeof s.data === \"string\" &&\n\t\t\t\t( s.contentType || \"\" )\n\t\t\t\t\t.indexOf( \"application/x-www-form-urlencoded\" ) === 0 &&\n\t\t\t\trjsonp.test( s.data ) && \"data\"\n\t\t);\n\n\t// Handle iff the expected data type is \"jsonp\" or we have a parameter to set\n\tif ( jsonProp || s.dataTypes[ 0 ] === \"jsonp\" ) {\n\n\t\t// Get callback name, remembering preexisting value associated with it\n\t\tcallbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ?\n\t\t\ts.jsonpCallback() :\n\t\t\ts.jsonpCallback;\n\n\t\t// Insert callback into url or form data\n\t\tif ( jsonProp ) {\n\t\t\ts[ jsonProp ] = s[ jsonProp ].replace( rjsonp, \"$1\" + callbackName );\n\t\t} else if ( s.jsonp !== false ) {\n\t\t\ts.url += ( rquery.test( s.url ) ? \"&\" : \"?\" ) + s.jsonp + \"=\" + callbackName;\n\t\t}\n\n\t\t// Use data converter to retrieve json after script execution\n\t\ts.converters[ \"script json\" ] = function() {\n\t\t\tif ( !responseContainer ) {\n\t\t\t\tjQuery.error( callbackName + \" was not called\" );\n\t\t\t}\n\t\t\treturn responseContainer[ 0 ];\n\t\t};\n\n\t\t// Force json dataType\n\t\ts.dataTypes[ 0 ] = \"json\";\n\n\t\t// Install callback\n\t\toverwritten = window[ callbackName ];\n\t\twindow[ callbackName ] = function() {\n\t\t\tresponseContainer = arguments;\n\t\t};\n\n\t\t// Clean-up function (fires after converters)\n\t\tjqXHR.always( function() {\n\n\t\t\t// If previous value didn't exist - remove it\n\t\t\tif ( overwritten === undefined ) {\n\t\t\t\tjQuery( window ).removeProp( callbackName );\n\n\t\t\t// Otherwise restore preexisting value\n\t\t\t} else {\n\t\t\t\twindow[ callbackName ] = overwritten;\n\t\t\t}\n\n\t\t\t// Save back as free\n\t\t\tif ( s[ callbackName ] ) {\n\n\t\t\t\t// Make sure that re-using the options doesn't screw things around\n\t\t\t\ts.jsonpCallback = originalSettings.jsonpCallback;\n\n\t\t\t\t// Save the callback name for future use\n\t\t\t\toldCallbacks.push( callbackName );\n\t\t\t}\n\n\t\t\t// Call if it was a function and we have a response\n\t\t\tif ( responseContainer && jQuery.isFunction( overwritten ) ) {\n\t\t\t\toverwritten( responseContainer[ 0 ] );\n\t\t\t}\n\n\t\t\tresponseContainer = overwritten = undefined;\n\t\t} );\n\n\t\t// Delegate to script\n\t\treturn \"script\";\n\t}\n} );\n\n\n\n\n// Support: Safari 8 only\n// In Safari 8 documents created via document.implementation.createHTMLDocument\n// collapse sibling forms: the second one becomes a child of the first one.\n// Because of that, this security measure has to be disabled in Safari 8.\n// https://bugs.webkit.org/show_bug.cgi?id=137337\nsupport.createHTMLDocument = ( function() {\n\tvar body = document.implementation.createHTMLDocument( \"\" ).body;\n\tbody.innerHTML = \"<form></form><form></form>\";\n\treturn body.childNodes.length === 2;\n} )();\n\n\n// Argument \"data\" should be string of html\n// context (optional): If specified, the fragment will be created in this context,\n// defaults to document\n// keepScripts (optional): If true, will include scripts passed in the html string\njQuery.parseHTML = function( data, context, keepScripts ) {\n\tif ( typeof data !== \"string\" ) {\n\t\treturn [];\n\t}\n\tif ( typeof context === \"boolean\" ) {\n\t\tkeepScripts = context;\n\t\tcontext = false;\n\t}\n\n\tvar base, parsed, scripts;\n\n\tif ( !context ) {\n\n\t\t// Stop scripts or inline event handlers from being executed immediately\n\t\t// by using document.implementation\n\t\tif ( support.createHTMLDocument ) {\n\t\t\tcontext = document.implementation.createHTMLDocument( \"\" );\n\n\t\t\t// Set the base href for the created document\n\t\t\t// so any parsed elements with URLs\n\t\t\t// are based on the document's URL (gh-2965)\n\t\t\tbase = context.createElement( \"base\" );\n\t\t\tbase.href = document.location.href;\n\t\t\tcontext.head.appendChild( base );\n\t\t} else {\n\t\t\tcontext = document;\n\t\t}\n\t}\n\n\tparsed = rsingleTag.exec( data );\n\tscripts = !keepScripts && [];\n\n\t// Single tag\n\tif ( parsed ) {\n\t\treturn [ context.createElement( parsed[ 1 ] ) ];\n\t}\n\n\tparsed = buildFragment( [ data ], context, scripts );\n\n\tif ( scripts && scripts.length ) {\n\t\tjQuery( scripts ).remove();\n\t}\n\n\treturn jQuery.merge( [], parsed.childNodes );\n};\n\n\n/**\n * Load a url into a page\n */\njQuery.fn.load = function( url, params, callback ) {\n\tvar selector, type, response,\n\t\tself = this,\n\t\toff = url.indexOf( \" \" );\n\n\tif ( off > -1 ) {\n\t\tselector = stripAndCollapse( url.slice( off ) );\n\t\turl = url.slice( 0, off );\n\t}\n\n\t// If it's a function\n\tif ( jQuery.isFunction( params ) ) {\n\n\t\t// We assume that it's the callback\n\t\tcallback = params;\n\t\tparams = undefined;\n\n\t// Otherwise, build a param string\n\t} else if ( params && typeof params === \"object\" ) {\n\t\ttype = \"POST\";\n\t}\n\n\t// If we have elements to modify, make the request\n\tif ( self.length > 0 ) {\n\t\tjQuery.ajax( {\n\t\t\turl: url,\n\n\t\t\t// If \"type\" variable is undefined, then \"GET\" method will be used.\n\t\t\t// Make value of this field explicit since\n\t\t\t// user can override it through ajaxSetup method\n\t\t\ttype: type || \"GET\",\n\t\t\tdataType: \"html\",\n\t\t\tdata: params\n\t\t} ).done( function( responseText ) {\n\n\t\t\t// Save response for use in complete callback\n\t\t\tresponse = arguments;\n\n\t\t\tself.html( selector ?\n\n\t\t\t\t// If a selector was specified, locate the right elements in a dummy div\n\t\t\t\t// Exclude scripts to avoid IE 'Permission Denied' errors\n\t\t\t\tjQuery( \"<div>\" ).append( jQuery.parseHTML( responseText ) ).find( selector ) :\n\n\t\t\t\t// Otherwise use the full result\n\t\t\t\tresponseText );\n\n\t\t// If the request succeeds, this function gets \"data\", \"status\", \"jqXHR\"\n\t\t// but they are ignored because response was set above.\n\t\t// If it fails, this function gets \"jqXHR\", \"status\", \"error\"\n\t\t} ).always( callback && function( jqXHR, status ) {\n\t\t\tself.each( function() {\n\t\t\t\tcallback.apply( this, response || [ jqXHR.responseText, status, jqXHR ] );\n\t\t\t} );\n\t\t} );\n\t}\n\n\treturn this;\n};\n\n\n\n\n// Attach a bunch of functions for handling common AJAX events\njQuery.each( [\n\t\"ajaxStart\",\n\t\"ajaxStop\",\n\t\"ajaxComplete\",\n\t\"ajaxError\",\n\t\"ajaxSuccess\",\n\t\"ajaxSend\"\n], function( i, type ) {\n\tjQuery.fn[ type ] = function( fn ) {\n\t\treturn this.on( type, fn );\n\t};\n} );\n\n\n\n\njQuery.expr.pseudos.animated = function( elem ) {\n\treturn jQuery.grep( jQuery.timers, function( fn ) {\n\t\treturn elem === fn.elem;\n\t} ).length;\n};\n\n\n\n\njQuery.offset = {\n\tsetOffset: function( elem, options, i ) {\n\t\tvar curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition,\n\t\t\tposition = jQuery.css( elem, \"position\" ),\n\t\t\tcurElem = jQuery( elem ),\n\t\t\tprops = {};\n\n\t\t// Set position first, in-case top/left are set even on static elem\n\t\tif ( position === \"static\" ) {\n\t\t\telem.style.position = \"relative\";\n\t\t}\n\n\t\tcurOffset = curElem.offset();\n\t\tcurCSSTop = jQuery.css( elem, \"top\" );\n\t\tcurCSSLeft = jQuery.css( elem, \"left\" );\n\t\tcalculatePosition = ( position === \"absolute\" || position === \"fixed\" ) &&\n\t\t\t( curCSSTop + curCSSLeft ).indexOf( \"auto\" ) > -1;\n\n\t\t// Need to be able to calculate position if either\n\t\t// top or left is auto and position is either absolute or fixed\n\t\tif ( calculatePosition ) {\n\t\t\tcurPosition = curElem.position();\n\t\t\tcurTop = curPosition.top;\n\t\t\tcurLeft = curPosition.left;\n\n\t\t} else {\n\t\t\tcurTop = parseFloat( curCSSTop ) || 0;\n\t\t\tcurLeft = parseFloat( curCSSLeft ) || 0;\n\t\t}\n\n\t\tif ( jQuery.isFunction( options ) ) {\n\n\t\t\t// Use jQuery.extend here to allow modification of coordinates argument (gh-1848)\n\t\t\toptions = options.call( elem, i, jQuery.extend( {}, curOffset ) );\n\t\t}\n\n\t\tif ( options.top != null ) {\n\t\t\tprops.top = ( options.top - curOffset.top ) + curTop;\n\t\t}\n\t\tif ( options.left != null ) {\n\t\t\tprops.left = ( options.left - curOffset.left ) + curLeft;\n\t\t}\n\n\t\tif ( \"using\" in options ) {\n\t\t\toptions.using.call( elem, props );\n\n\t\t} else {\n\t\t\tcurElem.css( props );\n\t\t}\n\t}\n};\n\njQuery.fn.extend( {\n\toffset: function( options ) {\n\n\t\t// Preserve chaining for setter\n\t\tif ( arguments.length ) {\n\t\t\treturn options === undefined ?\n\t\t\t\tthis :\n\t\t\t\tthis.each( function( i ) {\n\t\t\t\t\tjQuery.offset.setOffset( this, options, i );\n\t\t\t\t} );\n\t\t}\n\n\t\tvar doc, docElem, rect, win,\n\t\t\telem = this[ 0 ];\n\n\t\tif ( !elem ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Return zeros for disconnected and hidden (display: none) elements (gh-2310)\n\t\t// Support: IE <=11 only\n\t\t// Running getBoundingClientRect on a\n\t\t// disconnected node in IE throws an error\n\t\tif ( !elem.getClientRects().length ) {\n\t\t\treturn { top: 0, left: 0 };\n\t\t}\n\n\t\trect = elem.getBoundingClientRect();\n\n\t\tdoc = elem.ownerDocument;\n\t\tdocElem = doc.documentElement;\n\t\twin = doc.defaultView;\n\n\t\treturn {\n\t\t\ttop: rect.top + win.pageYOffset - docElem.clientTop,\n\t\t\tleft: rect.left + win.pageXOffset - docElem.clientLeft\n\t\t};\n\t},\n\n\tposition: function() {\n\t\tif ( !this[ 0 ] ) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar offsetParent, offset,\n\t\t\telem = this[ 0 ],\n\t\t\tparentOffset = { top: 0, left: 0 };\n\n\t\t// Fixed elements are offset from window (parentOffset = {top:0, left: 0},\n\t\t// because it is its only offset parent\n\t\tif ( jQuery.css( elem, \"position\" ) === \"fixed\" ) {\n\n\t\t\t// Assume getBoundingClientRect is there when computed position is fixed\n\t\t\toffset = elem.getBoundingClientRect();\n\n\t\t} else {\n\n\t\t\t// Get *real* offsetParent\n\t\t\toffsetParent = this.offsetParent();\n\n\t\t\t// Get correct offsets\n\t\t\toffset = this.offset();\n\t\t\tif ( !nodeName( offsetParent[ 0 ], \"html\" ) ) {\n\t\t\t\tparentOffset = offsetParent.offset();\n\t\t\t}\n\n\t\t\t// Add offsetParent borders\n\t\t\tparentOffset = {\n\t\t\t\ttop: parentOffset.top + jQuery.css( offsetParent[ 0 ], \"borderTopWidth\", true ),\n\t\t\t\tleft: parentOffset.left + jQuery.css( offsetParent[ 0 ], \"borderLeftWidth\", true )\n\t\t\t};\n\t\t}\n\n\t\t// Subtract parent offsets and element margins\n\t\treturn {\n\t\t\ttop: offset.top - parentOffset.top - jQuery.css( elem, \"marginTop\", true ),\n\t\t\tleft: offset.left - parentOffset.left - jQuery.css( elem, \"marginLeft\", true )\n\t\t};\n\t},\n\n\t// This method will return documentElement in the following cases:\n\t// 1) For the element inside the iframe without offsetParent, this method will return\n\t//    documentElement of the parent window\n\t// 2) For the hidden or detached element\n\t// 3) For body or html element, i.e. in case of the html node - it will return itself\n\t//\n\t// but those exceptions were never presented as a real life use-cases\n\t// and might be considered as more preferable results.\n\t//\n\t// This logic, however, is not guaranteed and can change at any point in the future\n\toffsetParent: function() {\n\t\treturn this.map( function() {\n\t\t\tvar offsetParent = this.offsetParent;\n\n\t\t\twhile ( offsetParent && jQuery.css( offsetParent, \"position\" ) === \"static\" ) {\n\t\t\t\toffsetParent = offsetParent.offsetParent;\n\t\t\t}\n\n\t\t\treturn offsetParent || documentElement;\n\t\t} );\n\t}\n} );\n\n// Create scrollLeft and scrollTop methods\njQuery.each( { scrollLeft: \"pageXOffset\", scrollTop: \"pageYOffset\" }, function( method, prop ) {\n\tvar top = \"pageYOffset\" === prop;\n\n\tjQuery.fn[ method ] = function( val ) {\n\t\treturn access( this, function( elem, method, val ) {\n\n\t\t\t// Coalesce documents and windows\n\t\t\tvar win;\n\t\t\tif ( jQuery.isWindow( elem ) ) {\n\t\t\t\twin = elem;\n\t\t\t} else if ( elem.nodeType === 9 ) {\n\t\t\t\twin = elem.defaultView;\n\t\t\t}\n\n\t\t\tif ( val === undefined ) {\n\t\t\t\treturn win ? win[ prop ] : elem[ method ];\n\t\t\t}\n\n\t\t\tif ( win ) {\n\t\t\t\twin.scrollTo(\n\t\t\t\t\t!top ? val : win.pageXOffset,\n\t\t\t\t\ttop ? val : win.pageYOffset\n\t\t\t\t);\n\n\t\t\t} else {\n\t\t\t\telem[ method ] = val;\n\t\t\t}\n\t\t}, method, val, arguments.length );\n\t};\n} );\n\n// Support: Safari <=7 - 9.1, Chrome <=37 - 49\n// Add the top/left cssHooks using jQuery.fn.position\n// Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084\n// Blink bug: https://bugs.chromium.org/p/chromium/issues/detail?id=589347\n// getComputedStyle returns percent when specified for top/left/bottom/right;\n// rather than make the css module depend on the offset module, just check for it here\njQuery.each( [ \"top\", \"left\" ], function( i, prop ) {\n\tjQuery.cssHooks[ prop ] = addGetHookIf( support.pixelPosition,\n\t\tfunction( elem, computed ) {\n\t\t\tif ( computed ) {\n\t\t\t\tcomputed = curCSS( elem, prop );\n\n\t\t\t\t// If curCSS returns percentage, fallback to offset\n\t\t\t\treturn rnumnonpx.test( computed ) ?\n\t\t\t\t\tjQuery( elem ).position()[ prop ] + \"px\" :\n\t\t\t\t\tcomputed;\n\t\t\t}\n\t\t}\n\t);\n} );\n\n\n// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods\njQuery.each( { Height: \"height\", Width: \"width\" }, function( name, type ) {\n\tjQuery.each( { padding: \"inner\" + name, content: type, \"\": \"outer\" + name },\n\t\tfunction( defaultExtra, funcName ) {\n\n\t\t// Margin is only for outerHeight, outerWidth\n\t\tjQuery.fn[ funcName ] = function( margin, value ) {\n\t\t\tvar chainable = arguments.length && ( defaultExtra || typeof margin !== \"boolean\" ),\n\t\t\t\textra = defaultExtra || ( margin === true || value === true ? \"margin\" : \"border\" );\n\n\t\t\treturn access( this, function( elem, type, value ) {\n\t\t\t\tvar doc;\n\n\t\t\t\tif ( jQuery.isWindow( elem ) ) {\n\n\t\t\t\t\t// $( window ).outerWidth/Height return w/h including scrollbars (gh-1729)\n\t\t\t\t\treturn funcName.indexOf( \"outer\" ) === 0 ?\n\t\t\t\t\t\telem[ \"inner\" + name ] :\n\t\t\t\t\t\telem.document.documentElement[ \"client\" + name ];\n\t\t\t\t}\n\n\t\t\t\t// Get document width or height\n\t\t\t\tif ( elem.nodeType === 9 ) {\n\t\t\t\t\tdoc = elem.documentElement;\n\n\t\t\t\t\t// Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height],\n\t\t\t\t\t// whichever is greatest\n\t\t\t\t\treturn Math.max(\n\t\t\t\t\t\telem.body[ \"scroll\" + name ], doc[ \"scroll\" + name ],\n\t\t\t\t\t\telem.body[ \"offset\" + name ], doc[ \"offset\" + name ],\n\t\t\t\t\t\tdoc[ \"client\" + name ]\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\treturn value === undefined ?\n\n\t\t\t\t\t// Get width or height on the element, requesting but not forcing parseFloat\n\t\t\t\t\tjQuery.css( elem, type, extra ) :\n\n\t\t\t\t\t// Set width or height on the element\n\t\t\t\t\tjQuery.style( elem, type, value, extra );\n\t\t\t}, type, chainable ? margin : undefined, chainable );\n\t\t};\n\t} );\n} );\n\n\njQuery.fn.extend( {\n\n\tbind: function( types, data, fn ) {\n\t\treturn this.on( types, null, data, fn );\n\t},\n\tunbind: function( types, fn ) {\n\t\treturn this.off( types, null, fn );\n\t},\n\n\tdelegate: function( selector, types, data, fn ) {\n\t\treturn this.on( types, selector, data, fn );\n\t},\n\tundelegate: function( selector, types, fn ) {\n\n\t\t// ( namespace ) or ( selector, types [, fn] )\n\t\treturn arguments.length === 1 ?\n\t\t\tthis.off( selector, \"**\" ) :\n\t\t\tthis.off( types, selector || \"**\", fn );\n\t}\n} );\n\njQuery.holdReady = function( hold ) {\n\tif ( hold ) {\n\t\tjQuery.readyWait++;\n\t} else {\n\t\tjQuery.ready( true );\n\t}\n};\njQuery.isArray = Array.isArray;\njQuery.parseJSON = JSON.parse;\njQuery.nodeName = nodeName;\n\n\n\n\n// Register as a named AMD module, since jQuery can be concatenated with other\n// files that may use define, but not via a proper concatenation script that\n// understands anonymous AMD modules. A named AMD is safest and most robust\n// way to register. Lowercase jquery is used because AMD module names are\n// derived from file names, and jQuery is normally delivered in a lowercase\n// file name. Do this after creating the global so that if an AMD module wants\n// to call noConflict to hide this version of jQuery, it will work.\n\n// Note that for maximum portability, libraries that are not jQuery should\n// declare themselves as anonymous modules, and avoid setting a global if an\n// AMD loader is present. jQuery is a special case. For more information, see\n// https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon\n\nif ( typeof define === \"function\" && define.amd ) {\n\tdefine( \"jquery\", [], function() {\n\t\treturn jQuery;\n\t} );\n}\n\n\n\n\nvar\n\n\t// Map over jQuery in case of overwrite\n\t_jQuery = window.jQuery,\n\n\t// Map over the $ in case of overwrite\n\t_$ = window.$;\n\njQuery.noConflict = function( deep ) {\n\tif ( window.$ === jQuery ) {\n\t\twindow.$ = _$;\n\t}\n\n\tif ( deep && window.jQuery === jQuery ) {\n\t\twindow.jQuery = _jQuery;\n\t}\n\n\treturn jQuery;\n};\n\n// Expose jQuery and $ identifiers, even in AMD\n// (#7102#comment:10, https://github.com/jquery/jquery/pull/557)\n// and CommonJS for browser emulators (#13566)\nif ( !noGlobal ) {\n\twindow.jQuery = window.$ = jQuery;\n}\n\n\n\n\nreturn jQuery;\n} );\n"
  },
  {
    "path": "docs/_static/jquery.js",
    "content": "/*! jQuery v3.2.1 | (c) JS Foundation and other contributors | jquery.org/license */\n!function(a,b){\"use strict\";\"object\"==typeof module&&\"object\"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error(\"jQuery requires a window with a document\");return b(a)}:b(a)}(\"undefined\"!=typeof window?window:this,function(a,b){\"use strict\";var c=[],d=a.document,e=Object.getPrototypeOf,f=c.slice,g=c.concat,h=c.push,i=c.indexOf,j={},k=j.toString,l=j.hasOwnProperty,m=l.toString,n=m.call(Object),o={};function p(a,b){b=b||d;var c=b.createElement(\"script\");c.text=a,b.head.appendChild(c).parentNode.removeChild(c)}var q=\"3.2.1\",r=function(a,b){return new r.fn.init(a,b)},s=/^[\\s\\uFEFF\\xA0]+|[\\s\\uFEFF\\xA0]+$/g,t=/^-ms-/,u=/-([a-z])/g,v=function(a,b){return b.toUpperCase()};r.fn=r.prototype={jquery:q,constructor:r,length:0,toArray:function(){return f.call(this)},get:function(a){return null==a?f.call(this):a<0?this[a+this.length]:this[a]},pushStack:function(a){var b=r.merge(this.constructor(),a);return b.prevObject=this,b},each:function(a){return r.each(this,a)},map:function(a){return this.pushStack(r.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(f.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(a<0?b:0);return this.pushStack(c>=0&&c<b?[this[c]]:[])},end:function(){return this.prevObject||this.constructor()},push:h,sort:c.sort,splice:c.splice},r.extend=r.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for(\"boolean\"==typeof g&&(j=g,g=arguments[h]||{},h++),\"object\"==typeof g||r.isFunction(g)||(g={}),h===i&&(g=this,h--);h<i;h++)if(null!=(a=arguments[h]))for(b in a)c=g[b],d=a[b],g!==d&&(j&&d&&(r.isPlainObject(d)||(e=Array.isArray(d)))?(e?(e=!1,f=c&&Array.isArray(c)?c:[]):f=c&&r.isPlainObject(c)?c:{},g[b]=r.extend(j,f,d)):void 0!==d&&(g[b]=d));return g},r.extend({expando:\"jQuery\"+(q+Math.random()).replace(/\\D/g,\"\"),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return\"function\"===r.type(a)},isWindow:function(a){return null!=a&&a===a.window},isNumeric:function(a){var b=r.type(a);return(\"number\"===b||\"string\"===b)&&!isNaN(a-parseFloat(a))},isPlainObject:function(a){var b,c;return!(!a||\"[object Object]\"!==k.call(a))&&(!(b=e(a))||(c=l.call(b,\"constructor\")&&b.constructor,\"function\"==typeof c&&m.call(c)===n))},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},type:function(a){return null==a?a+\"\":\"object\"==typeof a||\"function\"==typeof a?j[k.call(a)]||\"object\":typeof a},globalEval:function(a){p(a)},camelCase:function(a){return a.replace(t,\"ms-\").replace(u,v)},each:function(a,b){var c,d=0;if(w(a)){for(c=a.length;d<c;d++)if(b.call(a[d],d,a[d])===!1)break}else for(d in a)if(b.call(a[d],d,a[d])===!1)break;return a},trim:function(a){return null==a?\"\":(a+\"\").replace(s,\"\")},makeArray:function(a,b){var c=b||[];return null!=a&&(w(Object(a))?r.merge(c,\"string\"==typeof a?[a]:a):h.call(c,a)),c},inArray:function(a,b,c){return null==b?-1:i.call(b,a,c)},merge:function(a,b){for(var c=+b.length,d=0,e=a.length;d<c;d++)a[e++]=b[d];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;f<g;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,e,f=0,h=[];if(w(a))for(d=a.length;f<d;f++)e=b(a[f],f,c),null!=e&&h.push(e);else for(f in a)e=b(a[f],f,c),null!=e&&h.push(e);return g.apply([],h)},guid:1,proxy:function(a,b){var c,d,e;if(\"string\"==typeof b&&(c=a[b],b=a,a=c),r.isFunction(a))return d=f.call(arguments,2),e=function(){return a.apply(b||this,d.concat(f.call(arguments)))},e.guid=a.guid=a.guid||r.guid++,e},now:Date.now,support:o}),\"function\"==typeof Symbol&&(r.fn[Symbol.iterator]=c[Symbol.iterator]),r.each(\"Boolean Number String Function Array Date RegExp Object Error Symbol\".split(\" \"),function(a,b){j[\"[object \"+b+\"]\"]=b.toLowerCase()});function w(a){var b=!!a&&\"length\"in a&&a.length,c=r.type(a);return\"function\"!==c&&!r.isWindow(a)&&(\"array\"===c||0===b||\"number\"==typeof b&&b>0&&b-1 in a)}var x=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u=\"sizzle\"+1*new Date,v=a.document,w=0,x=0,y=ha(),z=ha(),A=ha(),B=function(a,b){return a===b&&(l=!0),0},C={}.hasOwnProperty,D=[],E=D.pop,F=D.push,G=D.push,H=D.slice,I=function(a,b){for(var c=0,d=a.length;c<d;c++)if(a[c]===b)return c;return-1},J=\"checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped\",K=\"[\\\\x20\\\\t\\\\r\\\\n\\\\f]\",L=\"(?:\\\\\\\\.|[\\\\w-]|[^\\0-\\\\xa0])+\",M=\"\\\\[\"+K+\"*(\"+L+\")(?:\"+K+\"*([*^$|!~]?=)\"+K+\"*(?:'((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\"|(\"+L+\"))|)\"+K+\"*\\\\]\",N=\":(\"+L+\")(?:\\\\((('((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\")|((?:\\\\\\\\.|[^\\\\\\\\()[\\\\]]|\"+M+\")*)|.*)\\\\)|)\",O=new RegExp(K+\"+\",\"g\"),P=new RegExp(\"^\"+K+\"+|((?:^|[^\\\\\\\\])(?:\\\\\\\\.)*)\"+K+\"+$\",\"g\"),Q=new RegExp(\"^\"+K+\"*,\"+K+\"*\"),R=new RegExp(\"^\"+K+\"*([>+~]|\"+K+\")\"+K+\"*\"),S=new RegExp(\"=\"+K+\"*([^\\\\]'\\\"]*?)\"+K+\"*\\\\]\",\"g\"),T=new RegExp(N),U=new RegExp(\"^\"+L+\"$\"),V={ID:new RegExp(\"^#(\"+L+\")\"),CLASS:new RegExp(\"^\\\\.(\"+L+\")\"),TAG:new RegExp(\"^(\"+L+\"|[*])\"),ATTR:new RegExp(\"^\"+M),PSEUDO:new RegExp(\"^\"+N),CHILD:new RegExp(\"^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\\\(\"+K+\"*(even|odd|(([+-]|)(\\\\d*)n|)\"+K+\"*(?:([+-]|)\"+K+\"*(\\\\d+)|))\"+K+\"*\\\\)|)\",\"i\"),bool:new RegExp(\"^(?:\"+J+\")$\",\"i\"),needsContext:new RegExp(\"^\"+K+\"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\\\(\"+K+\"*((?:-\\\\d)?\\\\d*)\"+K+\"*\\\\)|)(?=[^-]|$)\",\"i\")},W=/^(?:input|select|textarea|button)$/i,X=/^h\\d$/i,Y=/^[^{]+\\{\\s*\\[native \\w/,Z=/^(?:#([\\w-]+)|(\\w+)|\\.([\\w-]+))$/,$=/[+~]/,_=new RegExp(\"\\\\\\\\([\\\\da-f]{1,6}\"+K+\"?|(\"+K+\")|.)\",\"ig\"),aa=function(a,b,c){var d=\"0x\"+b-65536;return d!==d||c?b:d<0?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},ba=/([\\0-\\x1f\\x7f]|^-?\\d)|^-$|[^\\0-\\x1f\\x7f-\\uFFFF\\w-]/g,ca=function(a,b){return b?\"\\0\"===a?\"\\ufffd\":a.slice(0,-1)+\"\\\\\"+a.charCodeAt(a.length-1).toString(16)+\" \":\"\\\\\"+a},da=function(){m()},ea=ta(function(a){return a.disabled===!0&&(\"form\"in a||\"label\"in a)},{dir:\"parentNode\",next:\"legend\"});try{G.apply(D=H.call(v.childNodes),v.childNodes),D[v.childNodes.length].nodeType}catch(fa){G={apply:D.length?function(a,b){F.apply(a,H.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function ga(a,b,d,e){var f,h,j,k,l,o,r,s=b&&b.ownerDocument,w=b?b.nodeType:9;if(d=d||[],\"string\"!=typeof a||!a||1!==w&&9!==w&&11!==w)return d;if(!e&&((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,p)){if(11!==w&&(l=Z.exec(a)))if(f=l[1]){if(9===w){if(!(j=b.getElementById(f)))return d;if(j.id===f)return d.push(j),d}else if(s&&(j=s.getElementById(f))&&t(b,j)&&j.id===f)return d.push(j),d}else{if(l[2])return G.apply(d,b.getElementsByTagName(a)),d;if((f=l[3])&&c.getElementsByClassName&&b.getElementsByClassName)return G.apply(d,b.getElementsByClassName(f)),d}if(c.qsa&&!A[a+\" \"]&&(!q||!q.test(a))){if(1!==w)s=b,r=a;else if(\"object\"!==b.nodeName.toLowerCase()){(k=b.getAttribute(\"id\"))?k=k.replace(ba,ca):b.setAttribute(\"id\",k=u),o=g(a),h=o.length;while(h--)o[h]=\"#\"+k+\" \"+sa(o[h]);r=o.join(\",\"),s=$.test(a)&&qa(b.parentNode)||b}if(r)try{return G.apply(d,s.querySelectorAll(r)),d}catch(x){}finally{k===u&&b.removeAttribute(\"id\")}}}return i(a.replace(P,\"$1\"),b,d,e)}function ha(){var a=[];function b(c,e){return a.push(c+\" \")>d.cacheLength&&delete b[a.shift()],b[c+\" \"]=e}return b}function ia(a){return a[u]=!0,a}function ja(a){var b=n.createElement(\"fieldset\");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function ka(a,b){var c=a.split(\"|\"),e=c.length;while(e--)d.attrHandle[c[e]]=b}function la(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&a.sourceIndex-b.sourceIndex;if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function ma(a){return function(b){var c=b.nodeName.toLowerCase();return\"input\"===c&&b.type===a}}function na(a){return function(b){var c=b.nodeName.toLowerCase();return(\"input\"===c||\"button\"===c)&&b.type===a}}function oa(a){return function(b){return\"form\"in b?b.parentNode&&b.disabled===!1?\"label\"in b?\"label\"in b.parentNode?b.parentNode.disabled===a:b.disabled===a:b.isDisabled===a||b.isDisabled!==!a&&ea(b)===a:b.disabled===a:\"label\"in b&&b.disabled===a}}function pa(a){return ia(function(b){return b=+b,ia(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function qa(a){return a&&\"undefined\"!=typeof a.getElementsByTagName&&a}c=ga.support={},f=ga.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return!!b&&\"HTML\"!==b.nodeName},m=ga.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=n.documentElement,p=!f(n),v!==n&&(e=n.defaultView)&&e.top!==e&&(e.addEventListener?e.addEventListener(\"unload\",da,!1):e.attachEvent&&e.attachEvent(\"onunload\",da)),c.attributes=ja(function(a){return a.className=\"i\",!a.getAttribute(\"className\")}),c.getElementsByTagName=ja(function(a){return a.appendChild(n.createComment(\"\")),!a.getElementsByTagName(\"*\").length}),c.getElementsByClassName=Y.test(n.getElementsByClassName),c.getById=ja(function(a){return o.appendChild(a).id=u,!n.getElementsByName||!n.getElementsByName(u).length}),c.getById?(d.filter.ID=function(a){var b=a.replace(_,aa);return function(a){return a.getAttribute(\"id\")===b}},d.find.ID=function(a,b){if(\"undefined\"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c?[c]:[]}}):(d.filter.ID=function(a){var b=a.replace(_,aa);return function(a){var c=\"undefined\"!=typeof a.getAttributeNode&&a.getAttributeNode(\"id\");return c&&c.value===b}},d.find.ID=function(a,b){if(\"undefined\"!=typeof b.getElementById&&p){var c,d,e,f=b.getElementById(a);if(f){if(c=f.getAttributeNode(\"id\"),c&&c.value===a)return[f];e=b.getElementsByName(a),d=0;while(f=e[d++])if(c=f.getAttributeNode(\"id\"),c&&c.value===a)return[f]}return[]}}),d.find.TAG=c.getElementsByTagName?function(a,b){return\"undefined\"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if(\"*\"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){if(\"undefined\"!=typeof b.getElementsByClassName&&p)return b.getElementsByClassName(a)},r=[],q=[],(c.qsa=Y.test(n.querySelectorAll))&&(ja(function(a){o.appendChild(a).innerHTML=\"<a id='\"+u+\"'></a><select id='\"+u+\"-\\r\\\\' msallowcapture=''><option selected=''></option></select>\",a.querySelectorAll(\"[msallowcapture^='']\").length&&q.push(\"[*^$]=\"+K+\"*(?:''|\\\"\\\")\"),a.querySelectorAll(\"[selected]\").length||q.push(\"\\\\[\"+K+\"*(?:value|\"+J+\")\"),a.querySelectorAll(\"[id~=\"+u+\"-]\").length||q.push(\"~=\"),a.querySelectorAll(\":checked\").length||q.push(\":checked\"),a.querySelectorAll(\"a#\"+u+\"+*\").length||q.push(\".#.+[+~]\")}),ja(function(a){a.innerHTML=\"<a href='' disabled='disabled'></a><select disabled='disabled'><option/></select>\";var b=n.createElement(\"input\");b.setAttribute(\"type\",\"hidden\"),a.appendChild(b).setAttribute(\"name\",\"D\"),a.querySelectorAll(\"[name=d]\").length&&q.push(\"name\"+K+\"*[*^$|!~]?=\"),2!==a.querySelectorAll(\":enabled\").length&&q.push(\":enabled\",\":disabled\"),o.appendChild(a).disabled=!0,2!==a.querySelectorAll(\":disabled\").length&&q.push(\":enabled\",\":disabled\"),a.querySelectorAll(\"*,:x\"),q.push(\",.*:\")})),(c.matchesSelector=Y.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ja(function(a){c.disconnectedMatch=s.call(a,\"*\"),s.call(a,\"[s!='']:x\"),r.push(\"!=\",N)}),q=q.length&&new RegExp(q.join(\"|\")),r=r.length&&new RegExp(r.join(\"|\")),b=Y.test(o.compareDocumentPosition),t=b||Y.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===n||a.ownerDocument===v&&t(v,a)?-1:b===n||b.ownerDocument===v&&t(v,b)?1:k?I(k,a)-I(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,g=[a],h=[b];if(!e||!f)return a===n?-1:b===n?1:e?-1:f?1:k?I(k,a)-I(k,b):0;if(e===f)return la(a,b);c=a;while(c=c.parentNode)g.unshift(c);c=b;while(c=c.parentNode)h.unshift(c);while(g[d]===h[d])d++;return d?la(g[d],h[d]):g[d]===v?-1:h[d]===v?1:0},n):n},ga.matches=function(a,b){return ga(a,null,null,b)},ga.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(S,\"='$1']\"),c.matchesSelector&&p&&!A[b+\" \"]&&(!r||!r.test(b))&&(!q||!q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return ga(b,n,null,[a]).length>0},ga.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},ga.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&C.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},ga.escape=function(a){return(a+\"\").replace(ba,ca)},ga.error=function(a){throw new Error(\"Syntax error, unrecognized expression: \"+a)},ga.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=ga.getText=function(a){var b,c=\"\",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if(\"string\"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=ga.selectors={cacheLength:50,createPseudo:ia,match:V,attrHandle:{},find:{},relative:{\">\":{dir:\"parentNode\",first:!0},\" \":{dir:\"parentNode\"},\"+\":{dir:\"previousSibling\",first:!0},\"~\":{dir:\"previousSibling\"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(_,aa),a[3]=(a[3]||a[4]||a[5]||\"\").replace(_,aa),\"~=\"===a[2]&&(a[3]=\" \"+a[3]+\" \"),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),\"nth\"===a[1].slice(0,3)?(a[3]||ga.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*(\"even\"===a[3]||\"odd\"===a[3])),a[5]=+(a[7]+a[8]||\"odd\"===a[3])):a[3]&&ga.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return V.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||\"\":c&&T.test(c)&&(b=g(c,!0))&&(b=c.indexOf(\")\",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(_,aa).toLowerCase();return\"*\"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+\" \"];return b||(b=new RegExp(\"(^|\"+K+\")\"+a+\"(\"+K+\"|$)\"))&&y(a,function(a){return b.test(\"string\"==typeof a.className&&a.className||\"undefined\"!=typeof a.getAttribute&&a.getAttribute(\"class\")||\"\")})},ATTR:function(a,b,c){return function(d){var e=ga.attr(d,a);return null==e?\"!=\"===b:!b||(e+=\"\",\"=\"===b?e===c:\"!=\"===b?e!==c:\"^=\"===b?c&&0===e.indexOf(c):\"*=\"===b?c&&e.indexOf(c)>-1:\"$=\"===b?c&&e.slice(-c.length)===c:\"~=\"===b?(\" \"+e.replace(O,\" \")+\" \").indexOf(c)>-1:\"|=\"===b&&(e===c||e.slice(0,c.length+1)===c+\"-\"))}},CHILD:function(a,b,c,d,e){var f=\"nth\"!==a.slice(0,3),g=\"last\"!==a.slice(-4),h=\"of-type\"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?\"nextSibling\":\"previousSibling\",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h,t=!1;if(q){if(f){while(p){m=b;while(m=m[p])if(h?m.nodeName.toLowerCase()===r:1===m.nodeType)return!1;o=p=\"only\"===a&&!o&&\"nextSibling\"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){m=q,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n&&j[2],m=n&&q.childNodes[n];while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if(1===m.nodeType&&++t&&m===b){k[a]=[w,n,t];break}}else if(s&&(m=b,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n),t===!1)while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if((h?m.nodeName.toLowerCase()===r:1===m.nodeType)&&++t&&(s&&(l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),k[a]=[w,t]),m===b))break;return t-=e,t===d||t%d===0&&t/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||ga.error(\"unsupported pseudo: \"+a);return e[u]?e(b):e.length>1?(c=[a,a,\"\",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ia(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=I(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ia(function(a){var b=[],c=[],d=h(a.replace(P,\"$1\"));return d[u]?ia(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ia(function(a){return function(b){return ga(a,b).length>0}}),contains:ia(function(a){return a=a.replace(_,aa),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ia(function(a){return U.test(a||\"\")||ga.error(\"unsupported lang: \"+a),a=a.replace(_,aa).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute(\"xml:lang\")||b.getAttribute(\"lang\"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+\"-\");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:oa(!1),disabled:oa(!0),checked:function(a){var b=a.nodeName.toLowerCase();return\"input\"===b&&!!a.checked||\"option\"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return X.test(a.nodeName)},input:function(a){return W.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return\"input\"===b&&\"button\"===a.type||\"button\"===b},text:function(a){var b;return\"input\"===a.nodeName.toLowerCase()&&\"text\"===a.type&&(null==(b=a.getAttribute(\"type\"))||\"text\"===b.toLowerCase())},first:pa(function(){return[0]}),last:pa(function(a,b){return[b-1]}),eq:pa(function(a,b,c){return[c<0?c+b:c]}),even:pa(function(a,b){for(var c=0;c<b;c+=2)a.push(c);return a}),odd:pa(function(a,b){for(var c=1;c<b;c+=2)a.push(c);return a}),lt:pa(function(a,b,c){for(var d=c<0?c+b:c;--d>=0;)a.push(d);return a}),gt:pa(function(a,b,c){for(var d=c<0?c+b:c;++d<b;)a.push(d);return a})}},d.pseudos.nth=d.pseudos.eq;for(b in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})d.pseudos[b]=ma(b);for(b in{submit:!0,reset:!0})d.pseudos[b]=na(b);function ra(){}ra.prototype=d.filters=d.pseudos,d.setFilters=new ra,g=ga.tokenize=function(a,b){var c,e,f,g,h,i,j,k=z[a+\" \"];if(k)return b?0:k.slice(0);h=a,i=[],j=d.preFilter;while(h){c&&!(e=Q.exec(h))||(e&&(h=h.slice(e[0].length)||h),i.push(f=[])),c=!1,(e=R.exec(h))&&(c=e.shift(),f.push({value:c,type:e[0].replace(P,\" \")}),h=h.slice(c.length));for(g in d.filter)!(e=V[g].exec(h))||j[g]&&!(e=j[g](e))||(c=e.shift(),f.push({value:c,type:g,matches:e}),h=h.slice(c.length));if(!c)break}return b?h.length:h?ga.error(a):z(a,i).slice(0)};function sa(a){for(var b=0,c=a.length,d=\"\";b<c;b++)d+=a[b].value;return d}function ta(a,b,c){var d=b.dir,e=b.next,f=e||d,g=c&&\"parentNode\"===f,h=x++;return b.first?function(b,c,e){while(b=b[d])if(1===b.nodeType||g)return a(b,c,e);return!1}:function(b,c,i){var j,k,l,m=[w,h];if(i){while(b=b[d])if((1===b.nodeType||g)&&a(b,c,i))return!0}else while(b=b[d])if(1===b.nodeType||g)if(l=b[u]||(b[u]={}),k=l[b.uniqueID]||(l[b.uniqueID]={}),e&&e===b.nodeName.toLowerCase())b=b[d]||b;else{if((j=k[f])&&j[0]===w&&j[1]===h)return m[2]=j[2];if(k[f]=m,m[2]=a(b,c,i))return!0}return!1}}function ua(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function va(a,b,c){for(var d=0,e=b.length;d<e;d++)ga(a,b[d],c);return c}function wa(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;h<i;h++)(f=a[h])&&(c&&!c(f,d,e)||(g.push(f),j&&b.push(h)));return g}function xa(a,b,c,d,e,f){return d&&!d[u]&&(d=xa(d)),e&&!e[u]&&(e=xa(e,f)),ia(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||va(b||\"*\",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:wa(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=wa(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?I(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=wa(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):G.apply(g,r)})}function ya(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[\" \"],i=g?1:0,k=ta(function(a){return a===b},h,!0),l=ta(function(a){return I(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];i<f;i++)if(c=d.relative[a[i].type])m=[ta(ua(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;e<f;e++)if(d.relative[a[e].type])break;return xa(i>1&&ua(m),i>1&&sa(a.slice(0,i-1).concat({value:\" \"===a[i-2].type?\"*\":\"\"})).replace(P,\"$1\"),c,i<e&&ya(a.slice(i,e)),e<f&&ya(a=a.slice(e)),e<f&&sa(a))}m.push(c)}return ua(m)}function za(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,o,q,r=0,s=\"0\",t=f&&[],u=[],v=j,x=f||e&&d.find.TAG(\"*\",k),y=w+=null==v?1:Math.random()||.1,z=x.length;for(k&&(j=g===n||g||k);s!==z&&null!=(l=x[s]);s++){if(e&&l){o=0,g||l.ownerDocument===n||(m(l),h=!p);while(q=a[o++])if(q(l,g||n,h)){i.push(l);break}k&&(w=y)}c&&((l=!q&&l)&&r--,f&&t.push(l))}if(r+=s,c&&s!==r){o=0;while(q=b[o++])q(t,u,g,h);if(f){if(r>0)while(s--)t[s]||u[s]||(u[s]=E.call(i));u=wa(u)}G.apply(i,u),k&&!f&&u.length>0&&r+b.length>1&&ga.uniqueSort(i)}return k&&(w=y,j=v),t};return c?ia(f):f}return h=ga.compile=function(a,b){var c,d=[],e=[],f=A[a+\" \"];if(!f){b||(b=g(a)),c=b.length;while(c--)f=ya(b[c]),f[u]?d.push(f):e.push(f);f=A(a,za(e,d)),f.selector=a}return f},i=ga.select=function(a,b,c,e){var f,i,j,k,l,m=\"function\"==typeof a&&a,n=!e&&g(a=m.selector||a);if(c=c||[],1===n.length){if(i=n[0]=n[0].slice(0),i.length>2&&\"ID\"===(j=i[0]).type&&9===b.nodeType&&p&&d.relative[i[1].type]){if(b=(d.find.ID(j.matches[0].replace(_,aa),b)||[])[0],!b)return c;m&&(b=b.parentNode),a=a.slice(i.shift().value.length)}f=V.needsContext.test(a)?0:i.length;while(f--){if(j=i[f],d.relative[k=j.type])break;if((l=d.find[k])&&(e=l(j.matches[0].replace(_,aa),$.test(i[0].type)&&qa(b.parentNode)||b))){if(i.splice(f,1),a=e.length&&sa(i),!a)return G.apply(c,e),c;break}}}return(m||h(a,n))(e,b,!p,c,!b||$.test(a)&&qa(b.parentNode)||b),c},c.sortStable=u.split(\"\").sort(B).join(\"\")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ja(function(a){return 1&a.compareDocumentPosition(n.createElement(\"fieldset\"))}),ja(function(a){return a.innerHTML=\"<a href='#'></a>\",\"#\"===a.firstChild.getAttribute(\"href\")})||ka(\"type|href|height|width\",function(a,b,c){if(!c)return a.getAttribute(b,\"type\"===b.toLowerCase()?1:2)}),c.attributes&&ja(function(a){return a.innerHTML=\"<input/>\",a.firstChild.setAttribute(\"value\",\"\"),\"\"===a.firstChild.getAttribute(\"value\")})||ka(\"value\",function(a,b,c){if(!c&&\"input\"===a.nodeName.toLowerCase())return a.defaultValue}),ja(function(a){return null==a.getAttribute(\"disabled\")})||ka(J,function(a,b,c){var d;if(!c)return a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),ga}(a);r.find=x,r.expr=x.selectors,r.expr[\":\"]=r.expr.pseudos,r.uniqueSort=r.unique=x.uniqueSort,r.text=x.getText,r.isXMLDoc=x.isXML,r.contains=x.contains,r.escapeSelector=x.escape;var y=function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&r(a).is(c))break;d.push(a)}return d},z=function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c},A=r.expr.match.needsContext;function B(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()}var C=/^<([a-z][^\\/\\0>:\\x20\\t\\r\\n\\f]*)[\\x20\\t\\r\\n\\f]*\\/?>(?:<\\/\\1>|)$/i,D=/^.[^:#\\[\\.,]*$/;function E(a,b,c){return r.isFunction(b)?r.grep(a,function(a,d){return!!b.call(a,d,a)!==c}):b.nodeType?r.grep(a,function(a){return a===b!==c}):\"string\"!=typeof b?r.grep(a,function(a){return i.call(b,a)>-1!==c}):D.test(b)?r.filter(b,a,c):(b=r.filter(b,a),r.grep(a,function(a){return i.call(b,a)>-1!==c&&1===a.nodeType}))}r.filter=function(a,b,c){var d=b[0];return c&&(a=\":not(\"+a+\")\"),1===b.length&&1===d.nodeType?r.find.matchesSelector(d,a)?[d]:[]:r.find.matches(a,r.grep(b,function(a){return 1===a.nodeType}))},r.fn.extend({find:function(a){var b,c,d=this.length,e=this;if(\"string\"!=typeof a)return this.pushStack(r(a).filter(function(){for(b=0;b<d;b++)if(r.contains(e[b],this))return!0}));for(c=this.pushStack([]),b=0;b<d;b++)r.find(a,e[b],c);return d>1?r.uniqueSort(c):c},filter:function(a){return this.pushStack(E(this,a||[],!1))},not:function(a){return this.pushStack(E(this,a||[],!0))},is:function(a){return!!E(this,\"string\"==typeof a&&A.test(a)?r(a):a||[],!1).length}});var F,G=/^(?:\\s*(<[\\w\\W]+>)[^>]*|#([\\w-]+))$/,H=r.fn.init=function(a,b,c){var e,f;if(!a)return this;if(c=c||F,\"string\"==typeof a){if(e=\"<\"===a[0]&&\">\"===a[a.length-1]&&a.length>=3?[null,a,null]:G.exec(a),!e||!e[1]&&b)return!b||b.jquery?(b||c).find(a):this.constructor(b).find(a);if(e[1]){if(b=b instanceof r?b[0]:b,r.merge(this,r.parseHTML(e[1],b&&b.nodeType?b.ownerDocument||b:d,!0)),C.test(e[1])&&r.isPlainObject(b))for(e in b)r.isFunction(this[e])?this[e](b[e]):this.attr(e,b[e]);return this}return f=d.getElementById(e[2]),f&&(this[0]=f,this.length=1),this}return a.nodeType?(this[0]=a,this.length=1,this):r.isFunction(a)?void 0!==c.ready?c.ready(a):a(r):r.makeArray(a,this)};H.prototype=r.fn,F=r(d);var I=/^(?:parents|prev(?:Until|All))/,J={children:!0,contents:!0,next:!0,prev:!0};r.fn.extend({has:function(a){var b=r(a,this),c=b.length;return this.filter(function(){for(var a=0;a<c;a++)if(r.contains(this,b[a]))return!0})},closest:function(a,b){var c,d=0,e=this.length,f=[],g=\"string\"!=typeof a&&r(a);if(!A.test(a))for(;d<e;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&r.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?r.uniqueSort(f):f)},index:function(a){return a?\"string\"==typeof a?i.call(r(a),this[0]):i.call(this,a.jquery?a[0]:a):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(r.uniqueSort(r.merge(this.get(),r(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function K(a,b){while((a=a[b])&&1!==a.nodeType);return a}r.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return y(a,\"parentNode\")},parentsUntil:function(a,b,c){return y(a,\"parentNode\",c)},next:function(a){return K(a,\"nextSibling\")},prev:function(a){return K(a,\"previousSibling\")},nextAll:function(a){return y(a,\"nextSibling\")},prevAll:function(a){return y(a,\"previousSibling\")},nextUntil:function(a,b,c){return y(a,\"nextSibling\",c)},prevUntil:function(a,b,c){return y(a,\"previousSibling\",c)},siblings:function(a){return z((a.parentNode||{}).firstChild,a)},children:function(a){return z(a.firstChild)},contents:function(a){return B(a,\"iframe\")?a.contentDocument:(B(a,\"template\")&&(a=a.content||a),r.merge([],a.childNodes))}},function(a,b){r.fn[a]=function(c,d){var e=r.map(this,b,c);return\"Until\"!==a.slice(-5)&&(d=c),d&&\"string\"==typeof d&&(e=r.filter(d,e)),this.length>1&&(J[a]||r.uniqueSort(e),I.test(a)&&e.reverse()),this.pushStack(e)}});var L=/[^\\x20\\t\\r\\n\\f]+/g;function M(a){var b={};return r.each(a.match(L)||[],function(a,c){b[c]=!0}),b}r.Callbacks=function(a){a=\"string\"==typeof a?M(a):r.extend({},a);var b,c,d,e,f=[],g=[],h=-1,i=function(){for(e=e||a.once,d=b=!0;g.length;h=-1){c=g.shift();while(++h<f.length)f[h].apply(c[0],c[1])===!1&&a.stopOnFalse&&(h=f.length,c=!1)}a.memory||(c=!1),b=!1,e&&(f=c?[]:\"\")},j={add:function(){return f&&(c&&!b&&(h=f.length-1,g.push(c)),function d(b){r.each(b,function(b,c){r.isFunction(c)?a.unique&&j.has(c)||f.push(c):c&&c.length&&\"string\"!==r.type(c)&&d(c)})}(arguments),c&&!b&&i()),this},remove:function(){return r.each(arguments,function(a,b){var c;while((c=r.inArray(b,f,c))>-1)f.splice(c,1),c<=h&&h--}),this},has:function(a){return a?r.inArray(a,f)>-1:f.length>0},empty:function(){return f&&(f=[]),this},disable:function(){return e=g=[],f=c=\"\",this},disabled:function(){return!f},lock:function(){return e=g=[],c||b||(f=c=\"\"),this},locked:function(){return!!e},fireWith:function(a,c){return e||(c=c||[],c=[a,c.slice?c.slice():c],g.push(c),b||i()),this},fire:function(){return j.fireWith(this,arguments),this},fired:function(){return!!d}};return j};function N(a){return a}function O(a){throw a}function P(a,b,c,d){var e;try{a&&r.isFunction(e=a.promise)?e.call(a).done(b).fail(c):a&&r.isFunction(e=a.then)?e.call(a,b,c):b.apply(void 0,[a].slice(d))}catch(a){c.apply(void 0,[a])}}r.extend({Deferred:function(b){var c=[[\"notify\",\"progress\",r.Callbacks(\"memory\"),r.Callbacks(\"memory\"),2],[\"resolve\",\"done\",r.Callbacks(\"once memory\"),r.Callbacks(\"once memory\"),0,\"resolved\"],[\"reject\",\"fail\",r.Callbacks(\"once memory\"),r.Callbacks(\"once memory\"),1,\"rejected\"]],d=\"pending\",e={state:function(){return d},always:function(){return f.done(arguments).fail(arguments),this},\"catch\":function(a){return e.then(null,a)},pipe:function(){var a=arguments;return r.Deferred(function(b){r.each(c,function(c,d){var e=r.isFunction(a[d[4]])&&a[d[4]];f[d[1]](function(){var a=e&&e.apply(this,arguments);a&&r.isFunction(a.promise)?a.promise().progress(b.notify).done(b.resolve).fail(b.reject):b[d[0]+\"With\"](this,e?[a]:arguments)})}),a=null}).promise()},then:function(b,d,e){var f=0;function g(b,c,d,e){return function(){var h=this,i=arguments,j=function(){var a,j;if(!(b<f)){if(a=d.apply(h,i),a===c.promise())throw new TypeError(\"Thenable self-resolution\");j=a&&(\"object\"==typeof a||\"function\"==typeof a)&&a.then,r.isFunction(j)?e?j.call(a,g(f,c,N,e),g(f,c,O,e)):(f++,j.call(a,g(f,c,N,e),g(f,c,O,e),g(f,c,N,c.notifyWith))):(d!==N&&(h=void 0,i=[a]),(e||c.resolveWith)(h,i))}},k=e?j:function(){try{j()}catch(a){r.Deferred.exceptionHook&&r.Deferred.exceptionHook(a,k.stackTrace),b+1>=f&&(d!==O&&(h=void 0,i=[a]),c.rejectWith(h,i))}};b?k():(r.Deferred.getStackHook&&(k.stackTrace=r.Deferred.getStackHook()),a.setTimeout(k))}}return r.Deferred(function(a){c[0][3].add(g(0,a,r.isFunction(e)?e:N,a.notifyWith)),c[1][3].add(g(0,a,r.isFunction(b)?b:N)),c[2][3].add(g(0,a,r.isFunction(d)?d:O))}).promise()},promise:function(a){return null!=a?r.extend(a,e):e}},f={};return r.each(c,function(a,b){var g=b[2],h=b[5];e[b[1]]=g.add,h&&g.add(function(){d=h},c[3-a][2].disable,c[0][2].lock),g.add(b[3].fire),f[b[0]]=function(){return f[b[0]+\"With\"](this===f?void 0:this,arguments),this},f[b[0]+\"With\"]=g.fireWith}),e.promise(f),b&&b.call(f,f),f},when:function(a){var b=arguments.length,c=b,d=Array(c),e=f.call(arguments),g=r.Deferred(),h=function(a){return function(c){d[a]=this,e[a]=arguments.length>1?f.call(arguments):c,--b||g.resolveWith(d,e)}};if(b<=1&&(P(a,g.done(h(c)).resolve,g.reject,!b),\"pending\"===g.state()||r.isFunction(e[c]&&e[c].then)))return g.then();while(c--)P(e[c],h(c),g.reject);return g.promise()}});var Q=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;r.Deferred.exceptionHook=function(b,c){a.console&&a.console.warn&&b&&Q.test(b.name)&&a.console.warn(\"jQuery.Deferred exception: \"+b.message,b.stack,c)},r.readyException=function(b){a.setTimeout(function(){throw b})};var R=r.Deferred();r.fn.ready=function(a){return R.then(a)[\"catch\"](function(a){r.readyException(a)}),this},r.extend({isReady:!1,readyWait:1,ready:function(a){(a===!0?--r.readyWait:r.isReady)||(r.isReady=!0,a!==!0&&--r.readyWait>0||R.resolveWith(d,[r]))}}),r.ready.then=R.then;function S(){d.removeEventListener(\"DOMContentLoaded\",S),\na.removeEventListener(\"load\",S),r.ready()}\"complete\"===d.readyState||\"loading\"!==d.readyState&&!d.documentElement.doScroll?a.setTimeout(r.ready):(d.addEventListener(\"DOMContentLoaded\",S),a.addEventListener(\"load\",S));var T=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if(\"object\"===r.type(c)){e=!0;for(h in c)T(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,r.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(r(a),c)})),b))for(;h<i;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},U=function(a){return 1===a.nodeType||9===a.nodeType||!+a.nodeType};function V(){this.expando=r.expando+V.uid++}V.uid=1,V.prototype={cache:function(a){var b=a[this.expando];return b||(b={},U(a)&&(a.nodeType?a[this.expando]=b:Object.defineProperty(a,this.expando,{value:b,configurable:!0}))),b},set:function(a,b,c){var d,e=this.cache(a);if(\"string\"==typeof b)e[r.camelCase(b)]=c;else for(d in b)e[r.camelCase(d)]=b[d];return e},get:function(a,b){return void 0===b?this.cache(a):a[this.expando]&&a[this.expando][r.camelCase(b)]},access:function(a,b,c){return void 0===b||b&&\"string\"==typeof b&&void 0===c?this.get(a,b):(this.set(a,b,c),void 0!==c?c:b)},remove:function(a,b){var c,d=a[this.expando];if(void 0!==d){if(void 0!==b){Array.isArray(b)?b=b.map(r.camelCase):(b=r.camelCase(b),b=b in d?[b]:b.match(L)||[]),c=b.length;while(c--)delete d[b[c]]}(void 0===b||r.isEmptyObject(d))&&(a.nodeType?a[this.expando]=void 0:delete a[this.expando])}},hasData:function(a){var b=a[this.expando];return void 0!==b&&!r.isEmptyObject(b)}};var W=new V,X=new V,Y=/^(?:\\{[\\w\\W]*\\}|\\[[\\w\\W]*\\])$/,Z=/[A-Z]/g;function $(a){return\"true\"===a||\"false\"!==a&&(\"null\"===a?null:a===+a+\"\"?+a:Y.test(a)?JSON.parse(a):a)}function _(a,b,c){var d;if(void 0===c&&1===a.nodeType)if(d=\"data-\"+b.replace(Z,\"-$&\").toLowerCase(),c=a.getAttribute(d),\"string\"==typeof c){try{c=$(c)}catch(e){}X.set(a,b,c)}else c=void 0;return c}r.extend({hasData:function(a){return X.hasData(a)||W.hasData(a)},data:function(a,b,c){return X.access(a,b,c)},removeData:function(a,b){X.remove(a,b)},_data:function(a,b,c){return W.access(a,b,c)},_removeData:function(a,b){W.remove(a,b)}}),r.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=X.get(f),1===f.nodeType&&!W.get(f,\"hasDataAttrs\"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf(\"data-\")&&(d=r.camelCase(d.slice(5)),_(f,d,e[d])));W.set(f,\"hasDataAttrs\",!0)}return e}return\"object\"==typeof a?this.each(function(){X.set(this,a)}):T(this,function(b){var c;if(f&&void 0===b){if(c=X.get(f,a),void 0!==c)return c;if(c=_(f,a),void 0!==c)return c}else this.each(function(){X.set(this,a,b)})},null,b,arguments.length>1,null,!0)},removeData:function(a){return this.each(function(){X.remove(this,a)})}}),r.extend({queue:function(a,b,c){var d;if(a)return b=(b||\"fx\")+\"queue\",d=W.get(a,b),c&&(!d||Array.isArray(c)?d=W.access(a,b,r.makeArray(c)):d.push(c)),d||[]},dequeue:function(a,b){b=b||\"fx\";var c=r.queue(a,b),d=c.length,e=c.shift(),f=r._queueHooks(a,b),g=function(){r.dequeue(a,b)};\"inprogress\"===e&&(e=c.shift(),d--),e&&(\"fx\"===b&&c.unshift(\"inprogress\"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+\"queueHooks\";return W.get(a,c)||W.access(a,c,{empty:r.Callbacks(\"once memory\").add(function(){W.remove(a,[b+\"queue\",c])})})}}),r.fn.extend({queue:function(a,b){var c=2;return\"string\"!=typeof a&&(b=a,a=\"fx\",c--),arguments.length<c?r.queue(this[0],a):void 0===b?this:this.each(function(){var c=r.queue(this,a,b);r._queueHooks(this,a),\"fx\"===a&&\"inprogress\"!==c[0]&&r.dequeue(this,a)})},dequeue:function(a){return this.each(function(){r.dequeue(this,a)})},clearQueue:function(a){return this.queue(a||\"fx\",[])},promise:function(a,b){var c,d=1,e=r.Deferred(),f=this,g=this.length,h=function(){--d||e.resolveWith(f,[f])};\"string\"!=typeof a&&(b=a,a=void 0),a=a||\"fx\";while(g--)c=W.get(f[g],a+\"queueHooks\"),c&&c.empty&&(d++,c.empty.add(h));return h(),e.promise(b)}});var aa=/[+-]?(?:\\d*\\.|)\\d+(?:[eE][+-]?\\d+|)/.source,ba=new RegExp(\"^(?:([+-])=|)(\"+aa+\")([a-z%]*)$\",\"i\"),ca=[\"Top\",\"Right\",\"Bottom\",\"Left\"],da=function(a,b){return a=b||a,\"none\"===a.style.display||\"\"===a.style.display&&r.contains(a.ownerDocument,a)&&\"none\"===r.css(a,\"display\")},ea=function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e};function fa(a,b,c,d){var e,f=1,g=20,h=d?function(){return d.cur()}:function(){return r.css(a,b,\"\")},i=h(),j=c&&c[3]||(r.cssNumber[b]?\"\":\"px\"),k=(r.cssNumber[b]||\"px\"!==j&&+i)&&ba.exec(r.css(a,b));if(k&&k[3]!==j){j=j||k[3],c=c||[],k=+i||1;do f=f||\".5\",k/=f,r.style(a,b,k+j);while(f!==(f=h()/i)&&1!==f&&--g)}return c&&(k=+k||+i||0,e=c[1]?k+(c[1]+1)*c[2]:+c[2],d&&(d.unit=j,d.start=k,d.end=e)),e}var ga={};function ha(a){var b,c=a.ownerDocument,d=a.nodeName,e=ga[d];return e?e:(b=c.body.appendChild(c.createElement(d)),e=r.css(b,\"display\"),b.parentNode.removeChild(b),\"none\"===e&&(e=\"block\"),ga[d]=e,e)}function ia(a,b){for(var c,d,e=[],f=0,g=a.length;f<g;f++)d=a[f],d.style&&(c=d.style.display,b?(\"none\"===c&&(e[f]=W.get(d,\"display\")||null,e[f]||(d.style.display=\"\")),\"\"===d.style.display&&da(d)&&(e[f]=ha(d))):\"none\"!==c&&(e[f]=\"none\",W.set(d,\"display\",c)));for(f=0;f<g;f++)null!=e[f]&&(a[f].style.display=e[f]);return a}r.fn.extend({show:function(){return ia(this,!0)},hide:function(){return ia(this)},toggle:function(a){return\"boolean\"==typeof a?a?this.show():this.hide():this.each(function(){da(this)?r(this).show():r(this).hide()})}});var ja=/^(?:checkbox|radio)$/i,ka=/<([a-z][^\\/\\0>\\x20\\t\\r\\n\\f]+)/i,la=/^$|\\/(?:java|ecma)script/i,ma={option:[1,\"<select multiple='multiple'>\",\"</select>\"],thead:[1,\"<table>\",\"</table>\"],col:[2,\"<table><colgroup>\",\"</colgroup></table>\"],tr:[2,\"<table><tbody>\",\"</tbody></table>\"],td:[3,\"<table><tbody><tr>\",\"</tr></tbody></table>\"],_default:[0,\"\",\"\"]};ma.optgroup=ma.option,ma.tbody=ma.tfoot=ma.colgroup=ma.caption=ma.thead,ma.th=ma.td;function na(a,b){var c;return c=\"undefined\"!=typeof a.getElementsByTagName?a.getElementsByTagName(b||\"*\"):\"undefined\"!=typeof a.querySelectorAll?a.querySelectorAll(b||\"*\"):[],void 0===b||b&&B(a,b)?r.merge([a],c):c}function oa(a,b){for(var c=0,d=a.length;c<d;c++)W.set(a[c],\"globalEval\",!b||W.get(b[c],\"globalEval\"))}var pa=/<|&#?\\w+;/;function qa(a,b,c,d,e){for(var f,g,h,i,j,k,l=b.createDocumentFragment(),m=[],n=0,o=a.length;n<o;n++)if(f=a[n],f||0===f)if(\"object\"===r.type(f))r.merge(m,f.nodeType?[f]:f);else if(pa.test(f)){g=g||l.appendChild(b.createElement(\"div\")),h=(ka.exec(f)||[\"\",\"\"])[1].toLowerCase(),i=ma[h]||ma._default,g.innerHTML=i[1]+r.htmlPrefilter(f)+i[2],k=i[0];while(k--)g=g.lastChild;r.merge(m,g.childNodes),g=l.firstChild,g.textContent=\"\"}else m.push(b.createTextNode(f));l.textContent=\"\",n=0;while(f=m[n++])if(d&&r.inArray(f,d)>-1)e&&e.push(f);else if(j=r.contains(f.ownerDocument,f),g=na(l.appendChild(f),\"script\"),j&&oa(g),c){k=0;while(f=g[k++])la.test(f.type||\"\")&&c.push(f)}return l}!function(){var a=d.createDocumentFragment(),b=a.appendChild(d.createElement(\"div\")),c=d.createElement(\"input\");c.setAttribute(\"type\",\"radio\"),c.setAttribute(\"checked\",\"checked\"),c.setAttribute(\"name\",\"t\"),b.appendChild(c),o.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,b.innerHTML=\"<textarea>x</textarea>\",o.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var ra=d.documentElement,sa=/^key/,ta=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,ua=/^([^.]*)(?:\\.(.+)|)/;function va(){return!0}function wa(){return!1}function xa(){try{return d.activeElement}catch(a){}}function ya(a,b,c,d,e,f){var g,h;if(\"object\"==typeof b){\"string\"!=typeof c&&(d=d||c,c=void 0);for(h in b)ya(a,h,c,d,b[h],f);return a}if(null==d&&null==e?(e=c,d=c=void 0):null==e&&(\"string\"==typeof c?(e=d,d=void 0):(e=d,d=c,c=void 0)),e===!1)e=wa;else if(!e)return a;return 1===f&&(g=e,e=function(a){return r().off(a),g.apply(this,arguments)},e.guid=g.guid||(g.guid=r.guid++)),a.each(function(){r.event.add(this,b,e,d,c)})}r.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,o,p,q=W.get(a);if(q){c.handler&&(f=c,c=f.handler,e=f.selector),e&&r.find.matchesSelector(ra,e),c.guid||(c.guid=r.guid++),(i=q.events)||(i=q.events={}),(g=q.handle)||(g=q.handle=function(b){return\"undefined\"!=typeof r&&r.event.triggered!==b.type?r.event.dispatch.apply(a,arguments):void 0}),b=(b||\"\").match(L)||[\"\"],j=b.length;while(j--)h=ua.exec(b[j])||[],n=p=h[1],o=(h[2]||\"\").split(\".\").sort(),n&&(l=r.event.special[n]||{},n=(e?l.delegateType:l.bindType)||n,l=r.event.special[n]||{},k=r.extend({type:n,origType:p,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&r.expr.match.needsContext.test(e),namespace:o.join(\".\")},f),(m=i[n])||(m=i[n]=[],m.delegateCount=0,l.setup&&l.setup.call(a,d,o,g)!==!1||a.addEventListener&&a.addEventListener(n,g)),l.add&&(l.add.call(a,k),k.handler.guid||(k.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,k):m.push(k),r.event.global[n]=!0)}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,o,p,q=W.hasData(a)&&W.get(a);if(q&&(i=q.events)){b=(b||\"\").match(L)||[\"\"],j=b.length;while(j--)if(h=ua.exec(b[j])||[],n=p=h[1],o=(h[2]||\"\").split(\".\").sort(),n){l=r.event.special[n]||{},n=(d?l.delegateType:l.bindType)||n,m=i[n]||[],h=h[2]&&new RegExp(\"(^|\\\\.)\"+o.join(\"\\\\.(?:.*\\\\.|)\")+\"(\\\\.|$)\"),g=f=m.length;while(f--)k=m[f],!e&&p!==k.origType||c&&c.guid!==k.guid||h&&!h.test(k.namespace)||d&&d!==k.selector&&(\"**\"!==d||!k.selector)||(m.splice(f,1),k.selector&&m.delegateCount--,l.remove&&l.remove.call(a,k));g&&!m.length&&(l.teardown&&l.teardown.call(a,o,q.handle)!==!1||r.removeEvent(a,n,q.handle),delete i[n])}else for(n in i)r.event.remove(a,n+b[j],c,d,!0);r.isEmptyObject(i)&&W.remove(a,\"handle events\")}},dispatch:function(a){var b=r.event.fix(a),c,d,e,f,g,h,i=new Array(arguments.length),j=(W.get(this,\"events\")||{})[b.type]||[],k=r.event.special[b.type]||{};for(i[0]=b,c=1;c<arguments.length;c++)i[c]=arguments[c];if(b.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,b)!==!1){h=r.event.handlers.call(this,b,j),c=0;while((f=h[c++])&&!b.isPropagationStopped()){b.currentTarget=f.elem,d=0;while((g=f.handlers[d++])&&!b.isImmediatePropagationStopped())b.rnamespace&&!b.rnamespace.test(g.namespace)||(b.handleObj=g,b.data=g.data,e=((r.event.special[g.origType]||{}).handle||g.handler).apply(f.elem,i),void 0!==e&&(b.result=e)===!1&&(b.preventDefault(),b.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,b),b.result}},handlers:function(a,b){var c,d,e,f,g,h=[],i=b.delegateCount,j=a.target;if(i&&j.nodeType&&!(\"click\"===a.type&&a.button>=1))for(;j!==this;j=j.parentNode||this)if(1===j.nodeType&&(\"click\"!==a.type||j.disabled!==!0)){for(f=[],g={},c=0;c<i;c++)d=b[c],e=d.selector+\" \",void 0===g[e]&&(g[e]=d.needsContext?r(e,this).index(j)>-1:r.find(e,this,null,[j]).length),g[e]&&f.push(d);f.length&&h.push({elem:j,handlers:f})}return j=this,i<b.length&&h.push({elem:j,handlers:b.slice(i)}),h},addProp:function(a,b){Object.defineProperty(r.Event.prototype,a,{enumerable:!0,configurable:!0,get:r.isFunction(b)?function(){if(this.originalEvent)return b(this.originalEvent)}:function(){if(this.originalEvent)return this.originalEvent[a]},set:function(b){Object.defineProperty(this,a,{enumerable:!0,configurable:!0,writable:!0,value:b})}})},fix:function(a){return a[r.expando]?a:new r.Event(a)},special:{load:{noBubble:!0},focus:{trigger:function(){if(this!==xa()&&this.focus)return this.focus(),!1},delegateType:\"focusin\"},blur:{trigger:function(){if(this===xa()&&this.blur)return this.blur(),!1},delegateType:\"focusout\"},click:{trigger:function(){if(\"checkbox\"===this.type&&this.click&&B(this,\"input\"))return this.click(),!1},_default:function(a){return B(a.target,\"a\")}},beforeunload:{postDispatch:function(a){void 0!==a.result&&a.originalEvent&&(a.originalEvent.returnValue=a.result)}}}},r.removeEvent=function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c)},r.Event=function(a,b){return this instanceof r.Event?(a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||void 0===a.defaultPrevented&&a.returnValue===!1?va:wa,this.target=a.target&&3===a.target.nodeType?a.target.parentNode:a.target,this.currentTarget=a.currentTarget,this.relatedTarget=a.relatedTarget):this.type=a,b&&r.extend(this,b),this.timeStamp=a&&a.timeStamp||r.now(),void(this[r.expando]=!0)):new r.Event(a,b)},r.Event.prototype={constructor:r.Event,isDefaultPrevented:wa,isPropagationStopped:wa,isImmediatePropagationStopped:wa,isSimulated:!1,preventDefault:function(){var a=this.originalEvent;this.isDefaultPrevented=va,a&&!this.isSimulated&&a.preventDefault()},stopPropagation:function(){var a=this.originalEvent;this.isPropagationStopped=va,a&&!this.isSimulated&&a.stopPropagation()},stopImmediatePropagation:function(){var a=this.originalEvent;this.isImmediatePropagationStopped=va,a&&!this.isSimulated&&a.stopImmediatePropagation(),this.stopPropagation()}},r.each({altKey:!0,bubbles:!0,cancelable:!0,changedTouches:!0,ctrlKey:!0,detail:!0,eventPhase:!0,metaKey:!0,pageX:!0,pageY:!0,shiftKey:!0,view:!0,\"char\":!0,charCode:!0,key:!0,keyCode:!0,button:!0,buttons:!0,clientX:!0,clientY:!0,offsetX:!0,offsetY:!0,pointerId:!0,pointerType:!0,screenX:!0,screenY:!0,targetTouches:!0,toElement:!0,touches:!0,which:function(a){var b=a.button;return null==a.which&&sa.test(a.type)?null!=a.charCode?a.charCode:a.keyCode:!a.which&&void 0!==b&&ta.test(a.type)?1&b?1:2&b?3:4&b?2:0:a.which}},r.event.addProp),r.each({mouseenter:\"mouseover\",mouseleave:\"mouseout\",pointerenter:\"pointerover\",pointerleave:\"pointerout\"},function(a,b){r.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c,d=this,e=a.relatedTarget,f=a.handleObj;return e&&(e===d||r.contains(d,e))||(a.type=f.origType,c=f.handler.apply(this,arguments),a.type=b),c}}}),r.fn.extend({on:function(a,b,c,d){return ya(this,a,b,c,d)},one:function(a,b,c,d){return ya(this,a,b,c,d,1)},off:function(a,b,c){var d,e;if(a&&a.preventDefault&&a.handleObj)return d=a.handleObj,r(a.delegateTarget).off(d.namespace?d.origType+\".\"+d.namespace:d.origType,d.selector,d.handler),this;if(\"object\"==typeof a){for(e in a)this.off(e,b,a[e]);return this}return b!==!1&&\"function\"!=typeof b||(c=b,b=void 0),c===!1&&(c=wa),this.each(function(){r.event.remove(this,a,c,b)})}});var za=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\\/\\0>\\x20\\t\\r\\n\\f]*)[^>]*)\\/>/gi,Aa=/<script|<style|<link/i,Ba=/checked\\s*(?:[^=]|=\\s*.checked.)/i,Ca=/^true\\/(.*)/,Da=/^\\s*<!(?:\\[CDATA\\[|--)|(?:\\]\\]|--)>\\s*$/g;function Ea(a,b){return B(a,\"table\")&&B(11!==b.nodeType?b:b.firstChild,\"tr\")?r(\">tbody\",a)[0]||a:a}function Fa(a){return a.type=(null!==a.getAttribute(\"type\"))+\"/\"+a.type,a}function Ga(a){var b=Ca.exec(a.type);return b?a.type=b[1]:a.removeAttribute(\"type\"),a}function Ha(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(W.hasData(a)&&(f=W.access(a),g=W.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;c<d;c++)r.event.add(b,e,j[e][c])}X.hasData(a)&&(h=X.access(a),i=r.extend({},h),X.set(b,i))}}function Ia(a,b){var c=b.nodeName.toLowerCase();\"input\"===c&&ja.test(a.type)?b.checked=a.checked:\"input\"!==c&&\"textarea\"!==c||(b.defaultValue=a.defaultValue)}function Ja(a,b,c,d){b=g.apply([],b);var e,f,h,i,j,k,l=0,m=a.length,n=m-1,q=b[0],s=r.isFunction(q);if(s||m>1&&\"string\"==typeof q&&!o.checkClone&&Ba.test(q))return a.each(function(e){var f=a.eq(e);s&&(b[0]=q.call(this,e,f.html())),Ja(f,b,c,d)});if(m&&(e=qa(b,a[0].ownerDocument,!1,a,d),f=e.firstChild,1===e.childNodes.length&&(e=f),f||d)){for(h=r.map(na(e,\"script\"),Fa),i=h.length;l<m;l++)j=e,l!==n&&(j=r.clone(j,!0,!0),i&&r.merge(h,na(j,\"script\"))),c.call(a[l],j,l);if(i)for(k=h[h.length-1].ownerDocument,r.map(h,Ga),l=0;l<i;l++)j=h[l],la.test(j.type||\"\")&&!W.access(j,\"globalEval\")&&r.contains(k,j)&&(j.src?r._evalUrl&&r._evalUrl(j.src):p(j.textContent.replace(Da,\"\"),k))}return a}function Ka(a,b,c){for(var d,e=b?r.filter(b,a):a,f=0;null!=(d=e[f]);f++)c||1!==d.nodeType||r.cleanData(na(d)),d.parentNode&&(c&&r.contains(d.ownerDocument,d)&&oa(na(d,\"script\")),d.parentNode.removeChild(d));return a}r.extend({htmlPrefilter:function(a){return a.replace(za,\"<$1></$2>\")},clone:function(a,b,c){var d,e,f,g,h=a.cloneNode(!0),i=r.contains(a.ownerDocument,a);if(!(o.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||r.isXMLDoc(a)))for(g=na(h),f=na(a),d=0,e=f.length;d<e;d++)Ia(f[d],g[d]);if(b)if(c)for(f=f||na(a),g=g||na(h),d=0,e=f.length;d<e;d++)Ha(f[d],g[d]);else Ha(a,h);return g=na(h,\"script\"),g.length>0&&oa(g,!i&&na(a,\"script\")),h},cleanData:function(a){for(var b,c,d,e=r.event.special,f=0;void 0!==(c=a[f]);f++)if(U(c)){if(b=c[W.expando]){if(b.events)for(d in b.events)e[d]?r.event.remove(c,d):r.removeEvent(c,d,b.handle);c[W.expando]=void 0}c[X.expando]&&(c[X.expando]=void 0)}}}),r.fn.extend({detach:function(a){return Ka(this,a,!0)},remove:function(a){return Ka(this,a)},text:function(a){return T(this,function(a){return void 0===a?r.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=a)})},null,a,arguments.length)},append:function(){return Ja(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=Ea(this,a);b.appendChild(a)}})},prepend:function(){return Ja(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=Ea(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return Ja(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return Ja(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)1===a.nodeType&&(r.cleanData(na(a,!1)),a.textContent=\"\");return this},clone:function(a,b){return a=null!=a&&a,b=null==b?a:b,this.map(function(){return r.clone(this,a,b)})},html:function(a){return T(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a&&1===b.nodeType)return b.innerHTML;if(\"string\"==typeof a&&!Aa.test(a)&&!ma[(ka.exec(a)||[\"\",\"\"])[1].toLowerCase()]){a=r.htmlPrefilter(a);try{for(;c<d;c++)b=this[c]||{},1===b.nodeType&&(r.cleanData(na(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=[];return Ja(this,arguments,function(b){var c=this.parentNode;r.inArray(this,a)<0&&(r.cleanData(na(this)),c&&c.replaceChild(b,this))},a)}}),r.each({appendTo:\"append\",prependTo:\"prepend\",insertBefore:\"before\",insertAfter:\"after\",replaceAll:\"replaceWith\"},function(a,b){r.fn[a]=function(a){for(var c,d=[],e=r(a),f=e.length-1,g=0;g<=f;g++)c=g===f?this:this.clone(!0),r(e[g])[b](c),h.apply(d,c.get());return this.pushStack(d)}});var La=/^margin/,Ma=new RegExp(\"^(\"+aa+\")(?!px)[a-z%]+$\",\"i\"),Na=function(b){var c=b.ownerDocument.defaultView;return c&&c.opener||(c=a),c.getComputedStyle(b)};!function(){function b(){if(i){i.style.cssText=\"box-sizing:border-box;position:relative;display:block;margin:auto;border:1px;padding:1px;top:1%;width:50%\",i.innerHTML=\"\",ra.appendChild(h);var b=a.getComputedStyle(i);c=\"1%\"!==b.top,g=\"2px\"===b.marginLeft,e=\"4px\"===b.width,i.style.marginRight=\"50%\",f=\"4px\"===b.marginRight,ra.removeChild(h),i=null}}var c,e,f,g,h=d.createElement(\"div\"),i=d.createElement(\"div\");i.style&&(i.style.backgroundClip=\"content-box\",i.cloneNode(!0).style.backgroundClip=\"\",o.clearCloneStyle=\"content-box\"===i.style.backgroundClip,h.style.cssText=\"border:0;width:8px;height:0;top:0;left:-9999px;padding:0;margin-top:1px;position:absolute\",h.appendChild(i),r.extend(o,{pixelPosition:function(){return b(),c},boxSizingReliable:function(){return b(),e},pixelMarginRight:function(){return b(),f},reliableMarginLeft:function(){return b(),g}}))}();function Oa(a,b,c){var d,e,f,g,h=a.style;return c=c||Na(a),c&&(g=c.getPropertyValue(b)||c[b],\"\"!==g||r.contains(a.ownerDocument,a)||(g=r.style(a,b)),!o.pixelMarginRight()&&Ma.test(g)&&La.test(b)&&(d=h.width,e=h.minWidth,f=h.maxWidth,h.minWidth=h.maxWidth=h.width=g,g=c.width,h.width=d,h.minWidth=e,h.maxWidth=f)),void 0!==g?g+\"\":g}function Pa(a,b){return{get:function(){return a()?void delete this.get:(this.get=b).apply(this,arguments)}}}var Qa=/^(none|table(?!-c[ea]).+)/,Ra=/^--/,Sa={position:\"absolute\",visibility:\"hidden\",display:\"block\"},Ta={letterSpacing:\"0\",fontWeight:\"400\"},Ua=[\"Webkit\",\"Moz\",\"ms\"],Va=d.createElement(\"div\").style;function Wa(a){if(a in Va)return a;var b=a[0].toUpperCase()+a.slice(1),c=Ua.length;while(c--)if(a=Ua[c]+b,a in Va)return a}function Xa(a){var b=r.cssProps[a];return b||(b=r.cssProps[a]=Wa(a)||a),b}function Ya(a,b,c){var d=ba.exec(b);return d?Math.max(0,d[2]-(c||0))+(d[3]||\"px\"):b}function Za(a,b,c,d,e){var f,g=0;for(f=c===(d?\"border\":\"content\")?4:\"width\"===b?1:0;f<4;f+=2)\"margin\"===c&&(g+=r.css(a,c+ca[f],!0,e)),d?(\"content\"===c&&(g-=r.css(a,\"padding\"+ca[f],!0,e)),\"margin\"!==c&&(g-=r.css(a,\"border\"+ca[f]+\"Width\",!0,e))):(g+=r.css(a,\"padding\"+ca[f],!0,e),\"padding\"!==c&&(g+=r.css(a,\"border\"+ca[f]+\"Width\",!0,e)));return g}function $a(a,b,c){var d,e=Na(a),f=Oa(a,b,e),g=\"border-box\"===r.css(a,\"boxSizing\",!1,e);return Ma.test(f)?f:(d=g&&(o.boxSizingReliable()||f===a.style[b]),\"auto\"===f&&(f=a[\"offset\"+b[0].toUpperCase()+b.slice(1)]),f=parseFloat(f)||0,f+Za(a,b,c||(g?\"border\":\"content\"),d,e)+\"px\")}r.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=Oa(a,\"opacity\");return\"\"===c?\"1\":c}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{\"float\":\"cssFloat\"},style:function(a,b,c,d){if(a&&3!==a.nodeType&&8!==a.nodeType&&a.style){var e,f,g,h=r.camelCase(b),i=Ra.test(b),j=a.style;return i||(b=Xa(h)),g=r.cssHooks[b]||r.cssHooks[h],void 0===c?g&&\"get\"in g&&void 0!==(e=g.get(a,!1,d))?e:j[b]:(f=typeof c,\"string\"===f&&(e=ba.exec(c))&&e[1]&&(c=fa(a,b,e),f=\"number\"),null!=c&&c===c&&(\"number\"===f&&(c+=e&&e[3]||(r.cssNumber[h]?\"\":\"px\")),o.clearCloneStyle||\"\"!==c||0!==b.indexOf(\"background\")||(j[b]=\"inherit\"),g&&\"set\"in g&&void 0===(c=g.set(a,c,d))||(i?j.setProperty(b,c):j[b]=c)),void 0)}},css:function(a,b,c,d){var e,f,g,h=r.camelCase(b),i=Ra.test(b);return i||(b=Xa(h)),g=r.cssHooks[b]||r.cssHooks[h],g&&\"get\"in g&&(e=g.get(a,!0,c)),void 0===e&&(e=Oa(a,b,d)),\"normal\"===e&&b in Ta&&(e=Ta[b]),\"\"===c||c?(f=parseFloat(e),c===!0||isFinite(f)?f||0:e):e}}),r.each([\"height\",\"width\"],function(a,b){r.cssHooks[b]={get:function(a,c,d){if(c)return!Qa.test(r.css(a,\"display\"))||a.getClientRects().length&&a.getBoundingClientRect().width?$a(a,b,d):ea(a,Sa,function(){return $a(a,b,d)})},set:function(a,c,d){var e,f=d&&Na(a),g=d&&Za(a,b,d,\"border-box\"===r.css(a,\"boxSizing\",!1,f),f);return g&&(e=ba.exec(c))&&\"px\"!==(e[3]||\"px\")&&(a.style[b]=c,c=r.css(a,b)),Ya(a,c,g)}}}),r.cssHooks.marginLeft=Pa(o.reliableMarginLeft,function(a,b){if(b)return(parseFloat(Oa(a,\"marginLeft\"))||a.getBoundingClientRect().left-ea(a,{marginLeft:0},function(){return a.getBoundingClientRect().left}))+\"px\"}),r.each({margin:\"\",padding:\"\",border:\"Width\"},function(a,b){r.cssHooks[a+b]={expand:function(c){for(var d=0,e={},f=\"string\"==typeof c?c.split(\" \"):[c];d<4;d++)e[a+ca[d]+b]=f[d]||f[d-2]||f[0];return e}},La.test(a)||(r.cssHooks[a+b].set=Ya)}),r.fn.extend({css:function(a,b){return T(this,function(a,b,c){var d,e,f={},g=0;if(Array.isArray(b)){for(d=Na(a),e=b.length;g<e;g++)f[b[g]]=r.css(a,b[g],!1,d);return f}return void 0!==c?r.style(a,b,c):r.css(a,b)},a,b,arguments.length>1)}});function _a(a,b,c,d,e){return new _a.prototype.init(a,b,c,d,e)}r.Tween=_a,_a.prototype={constructor:_a,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||r.easing._default,this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(r.cssNumber[c]?\"\":\"px\")},cur:function(){var a=_a.propHooks[this.prop];return a&&a.get?a.get(this):_a.propHooks._default.get(this)},run:function(a){var b,c=_a.propHooks[this.prop];return this.options.duration?this.pos=b=r.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):this.pos=b=a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):_a.propHooks._default.set(this),this}},_a.prototype.init.prototype=_a.prototype,_a.propHooks={_default:{get:function(a){var b;return 1!==a.elem.nodeType||null!=a.elem[a.prop]&&null==a.elem.style[a.prop]?a.elem[a.prop]:(b=r.css(a.elem,a.prop,\"\"),b&&\"auto\"!==b?b:0)},set:function(a){r.fx.step[a.prop]?r.fx.step[a.prop](a):1!==a.elem.nodeType||null==a.elem.style[r.cssProps[a.prop]]&&!r.cssHooks[a.prop]?a.elem[a.prop]=a.now:r.style(a.elem,a.prop,a.now+a.unit)}}},_a.propHooks.scrollTop=_a.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},r.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2},_default:\"swing\"},r.fx=_a.prototype.init,r.fx.step={};var ab,bb,cb=/^(?:toggle|show|hide)$/,db=/queueHooks$/;function eb(){bb&&(d.hidden===!1&&a.requestAnimationFrame?a.requestAnimationFrame(eb):a.setTimeout(eb,r.fx.interval),r.fx.tick())}function fb(){return a.setTimeout(function(){ab=void 0}),ab=r.now()}function gb(a,b){var c,d=0,e={height:a};for(b=b?1:0;d<4;d+=2-b)c=ca[d],e[\"margin\"+c]=e[\"padding\"+c]=a;return b&&(e.opacity=e.width=a),e}function hb(a,b,c){for(var d,e=(kb.tweeners[b]||[]).concat(kb.tweeners[\"*\"]),f=0,g=e.length;f<g;f++)if(d=e[f].call(c,b,a))return d}function ib(a,b,c){var d,e,f,g,h,i,j,k,l=\"width\"in b||\"height\"in b,m=this,n={},o=a.style,p=a.nodeType&&da(a),q=W.get(a,\"fxshow\");c.queue||(g=r._queueHooks(a,\"fx\"),null==g.unqueued&&(g.unqueued=0,h=g.empty.fire,g.empty.fire=function(){g.unqueued||h()}),g.unqueued++,m.always(function(){m.always(function(){g.unqueued--,r.queue(a,\"fx\").length||g.empty.fire()})}));for(d in b)if(e=b[d],cb.test(e)){if(delete b[d],f=f||\"toggle\"===e,e===(p?\"hide\":\"show\")){if(\"show\"!==e||!q||void 0===q[d])continue;p=!0}n[d]=q&&q[d]||r.style(a,d)}if(i=!r.isEmptyObject(b),i||!r.isEmptyObject(n)){l&&1===a.nodeType&&(c.overflow=[o.overflow,o.overflowX,o.overflowY],j=q&&q.display,null==j&&(j=W.get(a,\"display\")),k=r.css(a,\"display\"),\"none\"===k&&(j?k=j:(ia([a],!0),j=a.style.display||j,k=r.css(a,\"display\"),ia([a]))),(\"inline\"===k||\"inline-block\"===k&&null!=j)&&\"none\"===r.css(a,\"float\")&&(i||(m.done(function(){o.display=j}),null==j&&(k=o.display,j=\"none\"===k?\"\":k)),o.display=\"inline-block\")),c.overflow&&(o.overflow=\"hidden\",m.always(function(){o.overflow=c.overflow[0],o.overflowX=c.overflow[1],o.overflowY=c.overflow[2]})),i=!1;for(d in n)i||(q?\"hidden\"in q&&(p=q.hidden):q=W.access(a,\"fxshow\",{display:j}),f&&(q.hidden=!p),p&&ia([a],!0),m.done(function(){p||ia([a]),W.remove(a,\"fxshow\");for(d in n)r.style(a,d,n[d])})),i=hb(p?q[d]:0,d,m),d in q||(q[d]=i.start,p&&(i.end=i.start,i.start=0))}}function jb(a,b){var c,d,e,f,g;for(c in a)if(d=r.camelCase(c),e=b[d],f=a[c],Array.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=r.cssHooks[d],g&&\"expand\"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}function kb(a,b,c){var d,e,f=0,g=kb.prefilters.length,h=r.Deferred().always(function(){delete i.elem}),i=function(){if(e)return!1;for(var b=ab||fb(),c=Math.max(0,j.startTime+j.duration-b),d=c/j.duration||0,f=1-d,g=0,i=j.tweens.length;g<i;g++)j.tweens[g].run(f);return h.notifyWith(a,[j,f,c]),f<1&&i?c:(i||h.notifyWith(a,[j,1,0]),h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:r.extend({},b),opts:r.extend(!0,{specialEasing:{},easing:r.easing._default},c),originalProperties:b,originalOptions:c,startTime:ab||fb(),duration:c.duration,tweens:[],createTween:function(b,c){var d=r.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(d),d},stop:function(b){var c=0,d=b?j.tweens.length:0;if(e)return this;for(e=!0;c<d;c++)j.tweens[c].run(1);return b?(h.notifyWith(a,[j,1,0]),h.resolveWith(a,[j,b])):h.rejectWith(a,[j,b]),this}}),k=j.props;for(jb(k,j.opts.specialEasing);f<g;f++)if(d=kb.prefilters[f].call(j,a,k,j.opts))return r.isFunction(d.stop)&&(r._queueHooks(j.elem,j.opts.queue).stop=r.proxy(d.stop,d)),d;return r.map(k,hb,j),r.isFunction(j.opts.start)&&j.opts.start.call(a,j),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always),r.fx.timer(r.extend(i,{elem:a,anim:j,queue:j.opts.queue})),j}r.Animation=r.extend(kb,{tweeners:{\"*\":[function(a,b){var c=this.createTween(a,b);return fa(c.elem,a,ba.exec(b),c),c}]},tweener:function(a,b){r.isFunction(a)?(b=a,a=[\"*\"]):a=a.match(L);for(var c,d=0,e=a.length;d<e;d++)c=a[d],kb.tweeners[c]=kb.tweeners[c]||[],kb.tweeners[c].unshift(b)},prefilters:[ib],prefilter:function(a,b){b?kb.prefilters.unshift(a):kb.prefilters.push(a)}}),r.speed=function(a,b,c){var d=a&&\"object\"==typeof a?r.extend({},a):{complete:c||!c&&b||r.isFunction(a)&&a,duration:a,easing:c&&b||b&&!r.isFunction(b)&&b};return r.fx.off?d.duration=0:\"number\"!=typeof d.duration&&(d.duration in r.fx.speeds?d.duration=r.fx.speeds[d.duration]:d.duration=r.fx.speeds._default),null!=d.queue&&d.queue!==!0||(d.queue=\"fx\"),d.old=d.complete,d.complete=function(){r.isFunction(d.old)&&d.old.call(this),d.queue&&r.dequeue(this,d.queue)},d},r.fn.extend({fadeTo:function(a,b,c,d){return this.filter(da).css(\"opacity\",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=r.isEmptyObject(a),f=r.speed(b,c,d),g=function(){var b=kb(this,r.extend({},a),f);(e||W.get(this,\"finish\"))&&b.stop(!0)};return g.finish=g,e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,b,c){var d=function(a){var b=a.stop;delete a.stop,b(c)};return\"string\"!=typeof a&&(c=b,b=a,a=void 0),b&&a!==!1&&this.queue(a||\"fx\",[]),this.each(function(){var b=!0,e=null!=a&&a+\"queueHooks\",f=r.timers,g=W.get(this);if(e)g[e]&&g[e].stop&&d(g[e]);else for(e in g)g[e]&&g[e].stop&&db.test(e)&&d(g[e]);for(e=f.length;e--;)f[e].elem!==this||null!=a&&f[e].queue!==a||(f[e].anim.stop(c),b=!1,f.splice(e,1));!b&&c||r.dequeue(this,a)})},finish:function(a){return a!==!1&&(a=a||\"fx\"),this.each(function(){var b,c=W.get(this),d=c[a+\"queue\"],e=c[a+\"queueHooks\"],f=r.timers,g=d?d.length:0;for(c.finish=!0,r.queue(this,a,[]),e&&e.stop&&e.stop.call(this,!0),b=f.length;b--;)f[b].elem===this&&f[b].queue===a&&(f[b].anim.stop(!0),f.splice(b,1));for(b=0;b<g;b++)d[b]&&d[b].finish&&d[b].finish.call(this);delete c.finish})}}),r.each([\"toggle\",\"show\",\"hide\"],function(a,b){var c=r.fn[b];r.fn[b]=function(a,d,e){return null==a||\"boolean\"==typeof a?c.apply(this,arguments):this.animate(gb(b,!0),a,d,e)}}),r.each({slideDown:gb(\"show\"),slideUp:gb(\"hide\"),slideToggle:gb(\"toggle\"),fadeIn:{opacity:\"show\"},fadeOut:{opacity:\"hide\"},fadeToggle:{opacity:\"toggle\"}},function(a,b){r.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),r.timers=[],r.fx.tick=function(){var a,b=0,c=r.timers;for(ab=r.now();b<c.length;b++)a=c[b],a()||c[b]!==a||c.splice(b--,1);c.length||r.fx.stop(),ab=void 0},r.fx.timer=function(a){r.timers.push(a),r.fx.start()},r.fx.interval=13,r.fx.start=function(){bb||(bb=!0,eb())},r.fx.stop=function(){bb=null},r.fx.speeds={slow:600,fast:200,_default:400},r.fn.delay=function(b,c){return b=r.fx?r.fx.speeds[b]||b:b,c=c||\"fx\",this.queue(c,function(c,d){var e=a.setTimeout(c,b);d.stop=function(){a.clearTimeout(e)}})},function(){var a=d.createElement(\"input\"),b=d.createElement(\"select\"),c=b.appendChild(d.createElement(\"option\"));a.type=\"checkbox\",o.checkOn=\"\"!==a.value,o.optSelected=c.selected,a=d.createElement(\"input\"),a.value=\"t\",a.type=\"radio\",o.radioValue=\"t\"===a.value}();var lb,mb=r.expr.attrHandle;r.fn.extend({attr:function(a,b){return T(this,r.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){r.removeAttr(this,a)})}}),r.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(3!==f&&8!==f&&2!==f)return\"undefined\"==typeof a.getAttribute?r.prop(a,b,c):(1===f&&r.isXMLDoc(a)||(e=r.attrHooks[b.toLowerCase()]||(r.expr.match.bool.test(b)?lb:void 0)),void 0!==c?null===c?void r.removeAttr(a,b):e&&\"set\"in e&&void 0!==(d=e.set(a,c,b))?d:(a.setAttribute(b,c+\"\"),c):e&&\"get\"in e&&null!==(d=e.get(a,b))?d:(d=r.find.attr(a,b),\nnull==d?void 0:d))},attrHooks:{type:{set:function(a,b){if(!o.radioValue&&\"radio\"===b&&B(a,\"input\")){var c=a.value;return a.setAttribute(\"type\",b),c&&(a.value=c),b}}}},removeAttr:function(a,b){var c,d=0,e=b&&b.match(L);if(e&&1===a.nodeType)while(c=e[d++])a.removeAttribute(c)}}),lb={set:function(a,b,c){return b===!1?r.removeAttr(a,c):a.setAttribute(c,c),c}},r.each(r.expr.match.bool.source.match(/\\w+/g),function(a,b){var c=mb[b]||r.find.attr;mb[b]=function(a,b,d){var e,f,g=b.toLowerCase();return d||(f=mb[g],mb[g]=e,e=null!=c(a,b,d)?g:null,mb[g]=f),e}});var nb=/^(?:input|select|textarea|button)$/i,ob=/^(?:a|area)$/i;r.fn.extend({prop:function(a,b){return T(this,r.prop,a,b,arguments.length>1)},removeProp:function(a){return this.each(function(){delete this[r.propFix[a]||a]})}}),r.extend({prop:function(a,b,c){var d,e,f=a.nodeType;if(3!==f&&8!==f&&2!==f)return 1===f&&r.isXMLDoc(a)||(b=r.propFix[b]||b,e=r.propHooks[b]),void 0!==c?e&&\"set\"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&\"get\"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){var b=r.find.attr(a,\"tabindex\");return b?parseInt(b,10):nb.test(a.nodeName)||ob.test(a.nodeName)&&a.href?0:-1}}},propFix:{\"for\":\"htmlFor\",\"class\":\"className\"}}),o.optSelected||(r.propHooks.selected={get:function(a){var b=a.parentNode;return b&&b.parentNode&&b.parentNode.selectedIndex,null},set:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex)}}),r.each([\"tabIndex\",\"readOnly\",\"maxLength\",\"cellSpacing\",\"cellPadding\",\"rowSpan\",\"colSpan\",\"useMap\",\"frameBorder\",\"contentEditable\"],function(){r.propFix[this.toLowerCase()]=this});function pb(a){var b=a.match(L)||[];return b.join(\" \")}function qb(a){return a.getAttribute&&a.getAttribute(\"class\")||\"\"}r.fn.extend({addClass:function(a){var b,c,d,e,f,g,h,i=0;if(r.isFunction(a))return this.each(function(b){r(this).addClass(a.call(this,b,qb(this)))});if(\"string\"==typeof a&&a){b=a.match(L)||[];while(c=this[i++])if(e=qb(c),d=1===c.nodeType&&\" \"+pb(e)+\" \"){g=0;while(f=b[g++])d.indexOf(\" \"+f+\" \")<0&&(d+=f+\" \");h=pb(d),e!==h&&c.setAttribute(\"class\",h)}}return this},removeClass:function(a){var b,c,d,e,f,g,h,i=0;if(r.isFunction(a))return this.each(function(b){r(this).removeClass(a.call(this,b,qb(this)))});if(!arguments.length)return this.attr(\"class\",\"\");if(\"string\"==typeof a&&a){b=a.match(L)||[];while(c=this[i++])if(e=qb(c),d=1===c.nodeType&&\" \"+pb(e)+\" \"){g=0;while(f=b[g++])while(d.indexOf(\" \"+f+\" \")>-1)d=d.replace(\" \"+f+\" \",\" \");h=pb(d),e!==h&&c.setAttribute(\"class\",h)}}return this},toggleClass:function(a,b){var c=typeof a;return\"boolean\"==typeof b&&\"string\"===c?b?this.addClass(a):this.removeClass(a):r.isFunction(a)?this.each(function(c){r(this).toggleClass(a.call(this,c,qb(this),b),b)}):this.each(function(){var b,d,e,f;if(\"string\"===c){d=0,e=r(this),f=a.match(L)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else void 0!==a&&\"boolean\"!==c||(b=qb(this),b&&W.set(this,\"__className__\",b),this.setAttribute&&this.setAttribute(\"class\",b||a===!1?\"\":W.get(this,\"__className__\")||\"\"))})},hasClass:function(a){var b,c,d=0;b=\" \"+a+\" \";while(c=this[d++])if(1===c.nodeType&&(\" \"+pb(qb(c))+\" \").indexOf(b)>-1)return!0;return!1}});var rb=/\\r/g;r.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=r.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,r(this).val()):a,null==e?e=\"\":\"number\"==typeof e?e+=\"\":Array.isArray(e)&&(e=r.map(e,function(a){return null==a?\"\":a+\"\"})),b=r.valHooks[this.type]||r.valHooks[this.nodeName.toLowerCase()],b&&\"set\"in b&&void 0!==b.set(this,e,\"value\")||(this.value=e))});if(e)return b=r.valHooks[e.type]||r.valHooks[e.nodeName.toLowerCase()],b&&\"get\"in b&&void 0!==(c=b.get(e,\"value\"))?c:(c=e.value,\"string\"==typeof c?c.replace(rb,\"\"):null==c?\"\":c)}}}),r.extend({valHooks:{option:{get:function(a){var b=r.find.attr(a,\"value\");return null!=b?b:pb(r.text(a))}},select:{get:function(a){var b,c,d,e=a.options,f=a.selectedIndex,g=\"select-one\"===a.type,h=g?null:[],i=g?f+1:e.length;for(d=f<0?i:g?f:0;d<i;d++)if(c=e[d],(c.selected||d===f)&&!c.disabled&&(!c.parentNode.disabled||!B(c.parentNode,\"optgroup\"))){if(b=r(c).val(),g)return b;h.push(b)}return h},set:function(a,b){var c,d,e=a.options,f=r.makeArray(b),g=e.length;while(g--)d=e[g],(d.selected=r.inArray(r.valHooks.option.get(d),f)>-1)&&(c=!0);return c||(a.selectedIndex=-1),f}}}}),r.each([\"radio\",\"checkbox\"],function(){r.valHooks[this]={set:function(a,b){if(Array.isArray(b))return a.checked=r.inArray(r(a).val(),b)>-1}},o.checkOn||(r.valHooks[this].get=function(a){return null===a.getAttribute(\"value\")?\"on\":a.value})});var sb=/^(?:focusinfocus|focusoutblur)$/;r.extend(r.event,{trigger:function(b,c,e,f){var g,h,i,j,k,m,n,o=[e||d],p=l.call(b,\"type\")?b.type:b,q=l.call(b,\"namespace\")?b.namespace.split(\".\"):[];if(h=i=e=e||d,3!==e.nodeType&&8!==e.nodeType&&!sb.test(p+r.event.triggered)&&(p.indexOf(\".\")>-1&&(q=p.split(\".\"),p=q.shift(),q.sort()),k=p.indexOf(\":\")<0&&\"on\"+p,b=b[r.expando]?b:new r.Event(p,\"object\"==typeof b&&b),b.isTrigger=f?2:3,b.namespace=q.join(\".\"),b.rnamespace=b.namespace?new RegExp(\"(^|\\\\.)\"+q.join(\"\\\\.(?:.*\\\\.|)\")+\"(\\\\.|$)\"):null,b.result=void 0,b.target||(b.target=e),c=null==c?[b]:r.makeArray(c,[b]),n=r.event.special[p]||{},f||!n.trigger||n.trigger.apply(e,c)!==!1)){if(!f&&!n.noBubble&&!r.isWindow(e)){for(j=n.delegateType||p,sb.test(j+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),i=h;i===(e.ownerDocument||d)&&o.push(i.defaultView||i.parentWindow||a)}g=0;while((h=o[g++])&&!b.isPropagationStopped())b.type=g>1?j:n.bindType||p,m=(W.get(h,\"events\")||{})[b.type]&&W.get(h,\"handle\"),m&&m.apply(h,c),m=k&&h[k],m&&m.apply&&U(h)&&(b.result=m.apply(h,c),b.result===!1&&b.preventDefault());return b.type=p,f||b.isDefaultPrevented()||n._default&&n._default.apply(o.pop(),c)!==!1||!U(e)||k&&r.isFunction(e[p])&&!r.isWindow(e)&&(i=e[k],i&&(e[k]=null),r.event.triggered=p,e[p](),r.event.triggered=void 0,i&&(e[k]=i)),b.result}},simulate:function(a,b,c){var d=r.extend(new r.Event,c,{type:a,isSimulated:!0});r.event.trigger(d,null,b)}}),r.fn.extend({trigger:function(a,b){return this.each(function(){r.event.trigger(a,b,this)})},triggerHandler:function(a,b){var c=this[0];if(c)return r.event.trigger(a,b,c,!0)}}),r.each(\"blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu\".split(\" \"),function(a,b){r.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),r.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}}),o.focusin=\"onfocusin\"in a,o.focusin||r.each({focus:\"focusin\",blur:\"focusout\"},function(a,b){var c=function(a){r.event.simulate(b,a.target,r.event.fix(a))};r.event.special[b]={setup:function(){var d=this.ownerDocument||this,e=W.access(d,b);e||d.addEventListener(a,c,!0),W.access(d,b,(e||0)+1)},teardown:function(){var d=this.ownerDocument||this,e=W.access(d,b)-1;e?W.access(d,b,e):(d.removeEventListener(a,c,!0),W.remove(d,b))}}});var tb=a.location,ub=r.now(),vb=/\\?/;r.parseXML=function(b){var c;if(!b||\"string\"!=typeof b)return null;try{c=(new a.DOMParser).parseFromString(b,\"text/xml\")}catch(d){c=void 0}return c&&!c.getElementsByTagName(\"parsererror\").length||r.error(\"Invalid XML: \"+b),c};var wb=/\\[\\]$/,xb=/\\r?\\n/g,yb=/^(?:submit|button|image|reset|file)$/i,zb=/^(?:input|select|textarea|keygen)/i;function Ab(a,b,c,d){var e;if(Array.isArray(b))r.each(b,function(b,e){c||wb.test(a)?d(a,e):Ab(a+\"[\"+(\"object\"==typeof e&&null!=e?b:\"\")+\"]\",e,c,d)});else if(c||\"object\"!==r.type(b))d(a,b);else for(e in b)Ab(a+\"[\"+e+\"]\",b[e],c,d)}r.param=function(a,b){var c,d=[],e=function(a,b){var c=r.isFunction(b)?b():b;d[d.length]=encodeURIComponent(a)+\"=\"+encodeURIComponent(null==c?\"\":c)};if(Array.isArray(a)||a.jquery&&!r.isPlainObject(a))r.each(a,function(){e(this.name,this.value)});else for(c in a)Ab(c,a[c],b,e);return d.join(\"&\")},r.fn.extend({serialize:function(){return r.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=r.prop(this,\"elements\");return a?r.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!r(this).is(\":disabled\")&&zb.test(this.nodeName)&&!yb.test(a)&&(this.checked||!ja.test(a))}).map(function(a,b){var c=r(this).val();return null==c?null:Array.isArray(c)?r.map(c,function(a){return{name:b.name,value:a.replace(xb,\"\\r\\n\")}}):{name:b.name,value:c.replace(xb,\"\\r\\n\")}}).get()}});var Bb=/%20/g,Cb=/#.*$/,Db=/([?&])_=[^&]*/,Eb=/^(.*?):[ \\t]*([^\\r\\n]*)$/gm,Fb=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Gb=/^(?:GET|HEAD)$/,Hb=/^\\/\\//,Ib={},Jb={},Kb=\"*/\".concat(\"*\"),Lb=d.createElement(\"a\");Lb.href=tb.href;function Mb(a){return function(b,c){\"string\"!=typeof b&&(c=b,b=\"*\");var d,e=0,f=b.toLowerCase().match(L)||[];if(r.isFunction(c))while(d=f[e++])\"+\"===d[0]?(d=d.slice(1)||\"*\",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function Nb(a,b,c,d){var e={},f=a===Jb;function g(h){var i;return e[h]=!0,r.each(a[h]||[],function(a,h){var j=h(b,c,d);return\"string\"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e[\"*\"]&&g(\"*\")}function Ob(a,b){var c,d,e=r.ajaxSettings.flatOptions||{};for(c in b)void 0!==b[c]&&((e[c]?a:d||(d={}))[c]=b[c]);return d&&r.extend(!0,a,d),a}function Pb(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while(\"*\"===i[0])i.shift(),void 0===d&&(d=a.mimeType||b.getResponseHeader(\"Content-Type\"));if(d)for(e in h)if(h[e]&&h[e].test(d)){i.unshift(e);break}if(i[0]in c)f=i[0];else{for(e in c){if(!i[0]||a.converters[e+\" \"+i[0]]){f=e;break}g||(g=e)}f=f||g}if(f)return f!==i[0]&&i.unshift(f),c[f]}function Qb(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if(\"*\"===f)f=i;else if(\"*\"!==i&&i!==f){if(g=j[i+\" \"+f]||j[\"* \"+f],!g)for(e in j)if(h=e.split(\" \"),h[1]===f&&(g=j[i+\" \"+h[0]]||j[\"* \"+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a[\"throws\"])b=g(b);else try{b=g(b)}catch(l){return{state:\"parsererror\",error:g?l:\"No conversion from \"+i+\" to \"+f}}}return{state:\"success\",data:b}}r.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:tb.href,type:\"GET\",isLocal:Fb.test(tb.protocol),global:!0,processData:!0,async:!0,contentType:\"application/x-www-form-urlencoded; charset=UTF-8\",accepts:{\"*\":Kb,text:\"text/plain\",html:\"text/html\",xml:\"application/xml, text/xml\",json:\"application/json, text/javascript\"},contents:{xml:/\\bxml\\b/,html:/\\bhtml/,json:/\\bjson\\b/},responseFields:{xml:\"responseXML\",text:\"responseText\",json:\"responseJSON\"},converters:{\"* text\":String,\"text html\":!0,\"text json\":JSON.parse,\"text xml\":r.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?Ob(Ob(a,r.ajaxSettings),b):Ob(r.ajaxSettings,a)},ajaxPrefilter:Mb(Ib),ajaxTransport:Mb(Jb),ajax:function(b,c){\"object\"==typeof b&&(c=b,b=void 0),c=c||{};var e,f,g,h,i,j,k,l,m,n,o=r.ajaxSetup({},c),p=o.context||o,q=o.context&&(p.nodeType||p.jquery)?r(p):r.event,s=r.Deferred(),t=r.Callbacks(\"once memory\"),u=o.statusCode||{},v={},w={},x=\"canceled\",y={readyState:0,getResponseHeader:function(a){var b;if(k){if(!h){h={};while(b=Eb.exec(g))h[b[1].toLowerCase()]=b[2]}b=h[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return k?g:null},setRequestHeader:function(a,b){return null==k&&(a=w[a.toLowerCase()]=w[a.toLowerCase()]||a,v[a]=b),this},overrideMimeType:function(a){return null==k&&(o.mimeType=a),this},statusCode:function(a){var b;if(a)if(k)y.always(a[y.status]);else for(b in a)u[b]=[u[b],a[b]];return this},abort:function(a){var b=a||x;return e&&e.abort(b),A(0,b),this}};if(s.promise(y),o.url=((b||o.url||tb.href)+\"\").replace(Hb,tb.protocol+\"//\"),o.type=c.method||c.type||o.method||o.type,o.dataTypes=(o.dataType||\"*\").toLowerCase().match(L)||[\"\"],null==o.crossDomain){j=d.createElement(\"a\");try{j.href=o.url,j.href=j.href,o.crossDomain=Lb.protocol+\"//\"+Lb.host!=j.protocol+\"//\"+j.host}catch(z){o.crossDomain=!0}}if(o.data&&o.processData&&\"string\"!=typeof o.data&&(o.data=r.param(o.data,o.traditional)),Nb(Ib,o,c,y),k)return y;l=r.event&&o.global,l&&0===r.active++&&r.event.trigger(\"ajaxStart\"),o.type=o.type.toUpperCase(),o.hasContent=!Gb.test(o.type),f=o.url.replace(Cb,\"\"),o.hasContent?o.data&&o.processData&&0===(o.contentType||\"\").indexOf(\"application/x-www-form-urlencoded\")&&(o.data=o.data.replace(Bb,\"+\")):(n=o.url.slice(f.length),o.data&&(f+=(vb.test(f)?\"&\":\"?\")+o.data,delete o.data),o.cache===!1&&(f=f.replace(Db,\"$1\"),n=(vb.test(f)?\"&\":\"?\")+\"_=\"+ub++ +n),o.url=f+n),o.ifModified&&(r.lastModified[f]&&y.setRequestHeader(\"If-Modified-Since\",r.lastModified[f]),r.etag[f]&&y.setRequestHeader(\"If-None-Match\",r.etag[f])),(o.data&&o.hasContent&&o.contentType!==!1||c.contentType)&&y.setRequestHeader(\"Content-Type\",o.contentType),y.setRequestHeader(\"Accept\",o.dataTypes[0]&&o.accepts[o.dataTypes[0]]?o.accepts[o.dataTypes[0]]+(\"*\"!==o.dataTypes[0]?\", \"+Kb+\"; q=0.01\":\"\"):o.accepts[\"*\"]);for(m in o.headers)y.setRequestHeader(m,o.headers[m]);if(o.beforeSend&&(o.beforeSend.call(p,y,o)===!1||k))return y.abort();if(x=\"abort\",t.add(o.complete),y.done(o.success),y.fail(o.error),e=Nb(Jb,o,c,y)){if(y.readyState=1,l&&q.trigger(\"ajaxSend\",[y,o]),k)return y;o.async&&o.timeout>0&&(i=a.setTimeout(function(){y.abort(\"timeout\")},o.timeout));try{k=!1,e.send(v,A)}catch(z){if(k)throw z;A(-1,z)}}else A(-1,\"No Transport\");function A(b,c,d,h){var j,m,n,v,w,x=c;k||(k=!0,i&&a.clearTimeout(i),e=void 0,g=h||\"\",y.readyState=b>0?4:0,j=b>=200&&b<300||304===b,d&&(v=Pb(o,y,d)),v=Qb(o,v,y,j),j?(o.ifModified&&(w=y.getResponseHeader(\"Last-Modified\"),w&&(r.lastModified[f]=w),w=y.getResponseHeader(\"etag\"),w&&(r.etag[f]=w)),204===b||\"HEAD\"===o.type?x=\"nocontent\":304===b?x=\"notmodified\":(x=v.state,m=v.data,n=v.error,j=!n)):(n=x,!b&&x||(x=\"error\",b<0&&(b=0))),y.status=b,y.statusText=(c||x)+\"\",j?s.resolveWith(p,[m,x,y]):s.rejectWith(p,[y,x,n]),y.statusCode(u),u=void 0,l&&q.trigger(j?\"ajaxSuccess\":\"ajaxError\",[y,o,j?m:n]),t.fireWith(p,[y,x]),l&&(q.trigger(\"ajaxComplete\",[y,o]),--r.active||r.event.trigger(\"ajaxStop\")))}return y},getJSON:function(a,b,c){return r.get(a,b,c,\"json\")},getScript:function(a,b){return r.get(a,void 0,b,\"script\")}}),r.each([\"get\",\"post\"],function(a,b){r[b]=function(a,c,d,e){return r.isFunction(c)&&(e=e||d,d=c,c=void 0),r.ajax(r.extend({url:a,type:b,dataType:e,data:c,success:d},r.isPlainObject(a)&&a))}}),r._evalUrl=function(a){return r.ajax({url:a,type:\"GET\",dataType:\"script\",cache:!0,async:!1,global:!1,\"throws\":!0})},r.fn.extend({wrapAll:function(a){var b;return this[0]&&(r.isFunction(a)&&(a=a.call(this[0])),b=r(a,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstElementChild)a=a.firstElementChild;return a}).append(this)),this},wrapInner:function(a){return r.isFunction(a)?this.each(function(b){r(this).wrapInner(a.call(this,b))}):this.each(function(){var b=r(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=r.isFunction(a);return this.each(function(c){r(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(a){return this.parent(a).not(\"body\").each(function(){r(this).replaceWith(this.childNodes)}),this}}),r.expr.pseudos.hidden=function(a){return!r.expr.pseudos.visible(a)},r.expr.pseudos.visible=function(a){return!!(a.offsetWidth||a.offsetHeight||a.getClientRects().length)},r.ajaxSettings.xhr=function(){try{return new a.XMLHttpRequest}catch(b){}};var Rb={0:200,1223:204},Sb=r.ajaxSettings.xhr();o.cors=!!Sb&&\"withCredentials\"in Sb,o.ajax=Sb=!!Sb,r.ajaxTransport(function(b){var c,d;if(o.cors||Sb&&!b.crossDomain)return{send:function(e,f){var g,h=b.xhr();if(h.open(b.type,b.url,b.async,b.username,b.password),b.xhrFields)for(g in b.xhrFields)h[g]=b.xhrFields[g];b.mimeType&&h.overrideMimeType&&h.overrideMimeType(b.mimeType),b.crossDomain||e[\"X-Requested-With\"]||(e[\"X-Requested-With\"]=\"XMLHttpRequest\");for(g in e)h.setRequestHeader(g,e[g]);c=function(a){return function(){c&&(c=d=h.onload=h.onerror=h.onabort=h.onreadystatechange=null,\"abort\"===a?h.abort():\"error\"===a?\"number\"!=typeof h.status?f(0,\"error\"):f(h.status,h.statusText):f(Rb[h.status]||h.status,h.statusText,\"text\"!==(h.responseType||\"text\")||\"string\"!=typeof h.responseText?{binary:h.response}:{text:h.responseText},h.getAllResponseHeaders()))}},h.onload=c(),d=h.onerror=c(\"error\"),void 0!==h.onabort?h.onabort=d:h.onreadystatechange=function(){4===h.readyState&&a.setTimeout(function(){c&&d()})},c=c(\"abort\");try{h.send(b.hasContent&&b.data||null)}catch(i){if(c)throw i}},abort:function(){c&&c()}}}),r.ajaxPrefilter(function(a){a.crossDomain&&(a.contents.script=!1)}),r.ajaxSetup({accepts:{script:\"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript\"},contents:{script:/\\b(?:java|ecma)script\\b/},converters:{\"text script\":function(a){return r.globalEval(a),a}}}),r.ajaxPrefilter(\"script\",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type=\"GET\")}),r.ajaxTransport(\"script\",function(a){if(a.crossDomain){var b,c;return{send:function(e,f){b=r(\"<script>\").prop({charset:a.scriptCharset,src:a.url}).on(\"load error\",c=function(a){b.remove(),c=null,a&&f(\"error\"===a.type?404:200,a.type)}),d.head.appendChild(b[0])},abort:function(){c&&c()}}}});var Tb=[],Ub=/(=)\\?(?=&|$)|\\?\\?/;r.ajaxSetup({jsonp:\"callback\",jsonpCallback:function(){var a=Tb.pop()||r.expando+\"_\"+ub++;return this[a]=!0,a}}),r.ajaxPrefilter(\"json jsonp\",function(b,c,d){var e,f,g,h=b.jsonp!==!1&&(Ub.test(b.url)?\"url\":\"string\"==typeof b.data&&0===(b.contentType||\"\").indexOf(\"application/x-www-form-urlencoded\")&&Ub.test(b.data)&&\"data\");if(h||\"jsonp\"===b.dataTypes[0])return e=b.jsonpCallback=r.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,h?b[h]=b[h].replace(Ub,\"$1\"+e):b.jsonp!==!1&&(b.url+=(vb.test(b.url)?\"&\":\"?\")+b.jsonp+\"=\"+e),b.converters[\"script json\"]=function(){return g||r.error(e+\" was not called\"),g[0]},b.dataTypes[0]=\"json\",f=a[e],a[e]=function(){g=arguments},d.always(function(){void 0===f?r(a).removeProp(e):a[e]=f,b[e]&&(b.jsonpCallback=c.jsonpCallback,Tb.push(e)),g&&r.isFunction(f)&&f(g[0]),g=f=void 0}),\"script\"}),o.createHTMLDocument=function(){var a=d.implementation.createHTMLDocument(\"\").body;return a.innerHTML=\"<form></form><form></form>\",2===a.childNodes.length}(),r.parseHTML=function(a,b,c){if(\"string\"!=typeof a)return[];\"boolean\"==typeof b&&(c=b,b=!1);var e,f,g;return b||(o.createHTMLDocument?(b=d.implementation.createHTMLDocument(\"\"),e=b.createElement(\"base\"),e.href=d.location.href,b.head.appendChild(e)):b=d),f=C.exec(a),g=!c&&[],f?[b.createElement(f[1])]:(f=qa([a],b,g),g&&g.length&&r(g).remove(),r.merge([],f.childNodes))},r.fn.load=function(a,b,c){var d,e,f,g=this,h=a.indexOf(\" \");return h>-1&&(d=pb(a.slice(h)),a=a.slice(0,h)),r.isFunction(b)?(c=b,b=void 0):b&&\"object\"==typeof b&&(e=\"POST\"),g.length>0&&r.ajax({url:a,type:e||\"GET\",dataType:\"html\",data:b}).done(function(a){f=arguments,g.html(d?r(\"<div>\").append(r.parseHTML(a)).find(d):a)}).always(c&&function(a,b){g.each(function(){c.apply(this,f||[a.responseText,b,a])})}),this},r.each([\"ajaxStart\",\"ajaxStop\",\"ajaxComplete\",\"ajaxError\",\"ajaxSuccess\",\"ajaxSend\"],function(a,b){r.fn[b]=function(a){return this.on(b,a)}}),r.expr.pseudos.animated=function(a){return r.grep(r.timers,function(b){return a===b.elem}).length},r.offset={setOffset:function(a,b,c){var d,e,f,g,h,i,j,k=r.css(a,\"position\"),l=r(a),m={};\"static\"===k&&(a.style.position=\"relative\"),h=l.offset(),f=r.css(a,\"top\"),i=r.css(a,\"left\"),j=(\"absolute\"===k||\"fixed\"===k)&&(f+i).indexOf(\"auto\")>-1,j?(d=l.position(),g=d.top,e=d.left):(g=parseFloat(f)||0,e=parseFloat(i)||0),r.isFunction(b)&&(b=b.call(a,c,r.extend({},h))),null!=b.top&&(m.top=b.top-h.top+g),null!=b.left&&(m.left=b.left-h.left+e),\"using\"in b?b.using.call(a,m):l.css(m)}},r.fn.extend({offset:function(a){if(arguments.length)return void 0===a?this:this.each(function(b){r.offset.setOffset(this,a,b)});var b,c,d,e,f=this[0];if(f)return f.getClientRects().length?(d=f.getBoundingClientRect(),b=f.ownerDocument,c=b.documentElement,e=b.defaultView,{top:d.top+e.pageYOffset-c.clientTop,left:d.left+e.pageXOffset-c.clientLeft}):{top:0,left:0}},position:function(){if(this[0]){var a,b,c=this[0],d={top:0,left:0};return\"fixed\"===r.css(c,\"position\")?b=c.getBoundingClientRect():(a=this.offsetParent(),b=this.offset(),B(a[0],\"html\")||(d=a.offset()),d={top:d.top+r.css(a[0],\"borderTopWidth\",!0),left:d.left+r.css(a[0],\"borderLeftWidth\",!0)}),{top:b.top-d.top-r.css(c,\"marginTop\",!0),left:b.left-d.left-r.css(c,\"marginLeft\",!0)}}},offsetParent:function(){return this.map(function(){var a=this.offsetParent;while(a&&\"static\"===r.css(a,\"position\"))a=a.offsetParent;return a||ra})}}),r.each({scrollLeft:\"pageXOffset\",scrollTop:\"pageYOffset\"},function(a,b){var c=\"pageYOffset\"===b;r.fn[a]=function(d){return T(this,function(a,d,e){var f;return r.isWindow(a)?f=a:9===a.nodeType&&(f=a.defaultView),void 0===e?f?f[b]:a[d]:void(f?f.scrollTo(c?f.pageXOffset:e,c?e:f.pageYOffset):a[d]=e)},a,d,arguments.length)}}),r.each([\"top\",\"left\"],function(a,b){r.cssHooks[b]=Pa(o.pixelPosition,function(a,c){if(c)return c=Oa(a,b),Ma.test(c)?r(a).position()[b]+\"px\":c})}),r.each({Height:\"height\",Width:\"width\"},function(a,b){r.each({padding:\"inner\"+a,content:b,\"\":\"outer\"+a},function(c,d){r.fn[d]=function(e,f){var g=arguments.length&&(c||\"boolean\"!=typeof e),h=c||(e===!0||f===!0?\"margin\":\"border\");return T(this,function(b,c,e){var f;return r.isWindow(b)?0===d.indexOf(\"outer\")?b[\"inner\"+a]:b.document.documentElement[\"client\"+a]:9===b.nodeType?(f=b.documentElement,Math.max(b.body[\"scroll\"+a],f[\"scroll\"+a],b.body[\"offset\"+a],f[\"offset\"+a],f[\"client\"+a])):void 0===e?r.css(b,c,h):r.style(b,c,e,h)},b,g?e:void 0,g)}})}),r.fn.extend({bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return 1===arguments.length?this.off(a,\"**\"):this.off(b,a||\"**\",c)}}),r.holdReady=function(a){a?r.readyWait++:r.ready(!0)},r.isArray=Array.isArray,r.parseJSON=JSON.parse,r.nodeName=B,\"function\"==typeof define&&define.amd&&define(\"jquery\",[],function(){return r});var Vb=a.jQuery,Wb=a.$;return r.noConflict=function(b){return a.$===r&&(a.$=Wb),b&&a.jQuery===r&&(a.jQuery=Vb),r},b||(a.jQuery=a.$=r),r});\n"
  },
  {
    "path": "docs/_static/js/theme.js",
    "content": "/* sphinx_rtd_theme version 0.4.3 | MIT license */\n/* Built 20190212 16:02 */\nrequire=function r(s,a,l){function c(e,n){if(!a[e]){if(!s[e]){var i=\"function\"==typeof require&&require;if(!n&&i)return i(e,!0);if(u)return u(e,!0);var t=new Error(\"Cannot find module '\"+e+\"'\");throw t.code=\"MODULE_NOT_FOUND\",t}var o=a[e]={exports:{}};s[e][0].call(o.exports,function(n){return c(s[e][1][n]||n)},o,o.exports,r,s,a,l)}return a[e].exports}for(var u=\"function\"==typeof require&&require,n=0;n<l.length;n++)c(l[n]);return c}({\"sphinx-rtd-theme\":[function(n,e,i){var jQuery=\"undefined\"!=typeof window?window.jQuery:n(\"jquery\");e.exports.ThemeNav={navBar:null,win:null,winScroll:!1,winResize:!1,linkScroll:!1,winPosition:0,winHeight:null,docHeight:null,isRunning:!1,enable:function(e){var i=this;void 0===e&&(e=!0),i.isRunning||(i.isRunning=!0,jQuery(function(n){i.init(n),i.reset(),i.win.on(\"hashchange\",i.reset),e&&i.win.on(\"scroll\",function(){i.linkScroll||i.winScroll||(i.winScroll=!0,requestAnimationFrame(function(){i.onScroll()}))}),i.win.on(\"resize\",function(){i.winResize||(i.winResize=!0,requestAnimationFrame(function(){i.onResize()}))}),i.onResize()}))},enableSticky:function(){this.enable(!0)},init:function(i){i(document);var t=this;this.navBar=i(\"div.wy-side-scroll:first\"),this.win=i(window),i(document).on(\"click\",\"[data-toggle='wy-nav-top']\",function(){i(\"[data-toggle='wy-nav-shift']\").toggleClass(\"shift\"),i(\"[data-toggle='rst-versions']\").toggleClass(\"shift\")}).on(\"click\",\".wy-menu-vertical .current ul li a\",function(){var n=i(this);i(\"[data-toggle='wy-nav-shift']\").removeClass(\"shift\"),i(\"[data-toggle='rst-versions']\").toggleClass(\"shift\"),t.toggleCurrent(n),t.hashChange()}).on(\"click\",\"[data-toggle='rst-current-version']\",function(){i(\"[data-toggle='rst-versions']\").toggleClass(\"shift-up\")}),i(\"table.docutils:not(.field-list,.footnote,.citation)\").wrap(\"<div class='wy-table-responsive'></div>\"),i(\"table.docutils.footnote\").wrap(\"<div class='wy-table-responsive footnote'></div>\"),i(\"table.docutils.citation\").wrap(\"<div class='wy-table-responsive citation'></div>\"),i(\".wy-menu-vertical ul\").not(\".simple\").siblings(\"a\").each(function(){var e=i(this);expand=i('<span class=\"toctree-expand\"></span>'),expand.on(\"click\",function(n){return t.toggleCurrent(e),n.stopPropagation(),!1}),e.prepend(expand)})},reset:function(){var n=encodeURI(window.location.hash)||\"#\";try{var e=$(\".wy-menu-vertical\"),i=e.find('[href=\"'+n+'\"]');if(0===i.length){var t=$('.document [id=\"'+n.substring(1)+'\"]').closest(\"div.section\");0===(i=e.find('[href=\"#'+t.attr(\"id\")+'\"]')).length&&(i=e.find('[href=\"#\"]'))}0<i.length&&($(\".wy-menu-vertical .current\").removeClass(\"current\"),i.addClass(\"current\"),i.closest(\"li.toctree-l1\").addClass(\"current\"),i.closest(\"li.toctree-l1\").parent().addClass(\"current\"),i.closest(\"li.toctree-l1\").addClass(\"current\"),i.closest(\"li.toctree-l2\").addClass(\"current\"),i.closest(\"li.toctree-l3\").addClass(\"current\"),i.closest(\"li.toctree-l4\").addClass(\"current\"),i[0].scrollIntoView())}catch(o){console.log(\"Error expanding nav for anchor\",o)}},onScroll:function(){this.winScroll=!1;var n=this.win.scrollTop(),e=n+this.winHeight,i=this.navBar.scrollTop()+(n-this.winPosition);n<0||e>this.docHeight||(this.navBar.scrollTop(i),this.winPosition=n)},onResize:function(){this.winResize=!1,this.winHeight=this.win.height(),this.docHeight=$(document).height()},hashChange:function(){this.linkScroll=!0,this.win.one(\"hashchange\",function(){this.linkScroll=!1})},toggleCurrent:function(n){var e=n.closest(\"li\");e.siblings(\"li.current\").removeClass(\"current\"),e.siblings().find(\"li.current\").removeClass(\"current\"),e.find(\"> ul li.current\").removeClass(\"current\"),e.toggleClass(\"current\")}},\"undefined\"!=typeof window&&(window.SphinxRtdTheme={Navigation:e.exports.ThemeNav,StickyNav:e.exports.ThemeNav}),function(){for(var r=0,n=[\"ms\",\"moz\",\"webkit\",\"o\"],e=0;e<n.length&&!window.requestAnimationFrame;++e)window.requestAnimationFrame=window[n[e]+\"RequestAnimationFrame\"],window.cancelAnimationFrame=window[n[e]+\"CancelAnimationFrame\"]||window[n[e]+\"CancelRequestAnimationFrame\"];window.requestAnimationFrame||(window.requestAnimationFrame=function(n,e){var i=(new Date).getTime(),t=Math.max(0,16-(i-r)),o=window.setTimeout(function(){n(i+t)},t);return r=i+t,o}),window.cancelAnimationFrame||(window.cancelAnimationFrame=function(n){clearTimeout(n)})}()},{jquery:\"jquery\"}]},{},[\"sphinx-rtd-theme\"]);"
  },
  {
    "path": "docs/_static/language_data.js",
    "content": "/*\n * language_data.js\n * ~~~~~~~~~~~~~~~~\n *\n * This script contains the language-specific data used by searchtools.js,\n * namely the list of stopwords, stemmer, scorer and splitter.\n *\n * :copyright: Copyright 2007-2019 by the Sphinx team, see AUTHORS.\n * :license: BSD, see LICENSE for details.\n *\n */\n\nvar stopwords = [\"a\",\"and\",\"are\",\"as\",\"at\",\"be\",\"but\",\"by\",\"for\",\"if\",\"in\",\"into\",\"is\",\"it\",\"near\",\"no\",\"not\",\"of\",\"on\",\"or\",\"such\",\"that\",\"the\",\"their\",\"then\",\"there\",\"these\",\"they\",\"this\",\"to\",\"was\",\"will\",\"with\"];\n\n\n/* Non-minified version JS is _stemmer.js if file is provided */ \n/**\n * Porter Stemmer\n */\nvar Stemmer = function() {\n\n  var step2list = {\n    ational: 'ate',\n    tional: 'tion',\n    enci: 'ence',\n    anci: 'ance',\n    izer: 'ize',\n    bli: 'ble',\n    alli: 'al',\n    entli: 'ent',\n    eli: 'e',\n    ousli: 'ous',\n    ization: 'ize',\n    ation: 'ate',\n    ator: 'ate',\n    alism: 'al',\n    iveness: 'ive',\n    fulness: 'ful',\n    ousness: 'ous',\n    aliti: 'al',\n    iviti: 'ive',\n    biliti: 'ble',\n    logi: 'log'\n  };\n\n  var step3list = {\n    icate: 'ic',\n    ative: '',\n    alize: 'al',\n    iciti: 'ic',\n    ical: 'ic',\n    ful: '',\n    ness: ''\n  };\n\n  var c = \"[^aeiou]\";          // consonant\n  var v = \"[aeiouy]\";          // vowel\n  var C = c + \"[^aeiouy]*\";    // consonant sequence\n  var V = v + \"[aeiou]*\";      // vowel sequence\n\n  var mgr0 = \"^(\" + C + \")?\" + V + C;                      // [C]VC... is m>0\n  var meq1 = \"^(\" + C + \")?\" + V + C + \"(\" + V + \")?$\";    // [C]VC[V] is m=1\n  var mgr1 = \"^(\" + C + \")?\" + V + C + V + C;              // [C]VCVC... is m>1\n  var s_v   = \"^(\" + C + \")?\" + v;                         // vowel in stem\n\n  this.stemWord = function (w) {\n    var stem;\n    var suffix;\n    var firstch;\n    var origword = w;\n\n    if (w.length < 3)\n      return w;\n\n    var re;\n    var re2;\n    var re3;\n    var re4;\n\n    firstch = w.substr(0,1);\n    if (firstch == \"y\")\n      w = firstch.toUpperCase() + w.substr(1);\n\n    // Step 1a\n    re = /^(.+?)(ss|i)es$/;\n    re2 = /^(.+?)([^s])s$/;\n\n    if (re.test(w))\n      w = w.replace(re,\"$1$2\");\n    else if (re2.test(w))\n      w = w.replace(re2,\"$1$2\");\n\n    // Step 1b\n    re = /^(.+?)eed$/;\n    re2 = /^(.+?)(ed|ing)$/;\n    if (re.test(w)) {\n      var fp = re.exec(w);\n      re = new RegExp(mgr0);\n      if (re.test(fp[1])) {\n        re = /.$/;\n        w = w.replace(re,\"\");\n      }\n    }\n    else if (re2.test(w)) {\n      var fp = re2.exec(w);\n      stem = fp[1];\n      re2 = new RegExp(s_v);\n      if (re2.test(stem)) {\n        w = stem;\n        re2 = /(at|bl|iz)$/;\n        re3 = new RegExp(\"([^aeiouylsz])\\\\1$\");\n        re4 = new RegExp(\"^\" + C + v + \"[^aeiouwxy]$\");\n        if (re2.test(w))\n          w = w + \"e\";\n        else if (re3.test(w)) {\n          re = /.$/;\n          w = w.replace(re,\"\");\n        }\n        else if (re4.test(w))\n          w = w + \"e\";\n      }\n    }\n\n    // Step 1c\n    re = /^(.+?)y$/;\n    if (re.test(w)) {\n      var fp = re.exec(w);\n      stem = fp[1];\n      re = new RegExp(s_v);\n      if (re.test(stem))\n        w = stem + \"i\";\n    }\n\n    // Step 2\n    re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/;\n    if (re.test(w)) {\n      var fp = re.exec(w);\n      stem = fp[1];\n      suffix = fp[2];\n      re = new RegExp(mgr0);\n      if (re.test(stem))\n        w = stem + step2list[suffix];\n    }\n\n    // Step 3\n    re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/;\n    if (re.test(w)) {\n      var fp = re.exec(w);\n      stem = fp[1];\n      suffix = fp[2];\n      re = new RegExp(mgr0);\n      if (re.test(stem))\n        w = stem + step3list[suffix];\n    }\n\n    // Step 4\n    re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/;\n    re2 = /^(.+?)(s|t)(ion)$/;\n    if (re.test(w)) {\n      var fp = re.exec(w);\n      stem = fp[1];\n      re = new RegExp(mgr1);\n      if (re.test(stem))\n        w = stem;\n    }\n    else if (re2.test(w)) {\n      var fp = re2.exec(w);\n      stem = fp[1] + fp[2];\n      re2 = new RegExp(mgr1);\n      if (re2.test(stem))\n        w = stem;\n    }\n\n    // Step 5\n    re = /^(.+?)e$/;\n    if (re.test(w)) {\n      var fp = re.exec(w);\n      stem = fp[1];\n      re = new RegExp(mgr1);\n      re2 = new RegExp(meq1);\n      re3 = new RegExp(\"^\" + C + v + \"[^aeiouwxy]$\");\n      if (re.test(stem) || (re2.test(stem) && !(re3.test(stem))))\n        w = stem;\n    }\n    re = /ll$/;\n    re2 = new RegExp(mgr1);\n    if (re.test(w) && re2.test(w)) {\n      re = /.$/;\n      w = w.replace(re,\"\");\n    }\n\n    // and turn initial Y back to y\n    if (firstch == \"y\")\n      w = firstch.toLowerCase() + w.substr(1);\n    return w;\n  }\n}\n\n\n\n\n\nvar splitChars = (function() {\n    var result = {};\n    var singles = [96, 180, 187, 191, 215, 247, 749, 885, 903, 907, 909, 930, 1014, 1648,\n         1748, 1809, 2416, 2473, 2481, 2526, 2601, 2609, 2612, 2615, 2653, 2702,\n         2706, 2729, 2737, 2740, 2857, 2865, 2868, 2910, 2928, 2948, 2961, 2971,\n         2973, 3085, 3089, 3113, 3124, 3213, 3217, 3241, 3252, 3295, 3341, 3345,\n         3369, 3506, 3516, 3633, 3715, 3721, 3736, 3744, 3748, 3750, 3756, 3761,\n         3781, 3912, 4239, 4347, 4681, 4695, 4697, 4745, 4785, 4799, 4801, 4823,\n         4881, 5760, 5901, 5997, 6313, 7405, 8024, 8026, 8028, 8030, 8117, 8125,\n         8133, 8181, 8468, 8485, 8487, 8489, 8494, 8527, 11311, 11359, 11687, 11695,\n         11703, 11711, 11719, 11727, 11735, 12448, 12539, 43010, 43014, 43019, 43587,\n         43696, 43713, 64286, 64297, 64311, 64317, 64319, 64322, 64325, 65141];\n    var i, j, start, end;\n    for (i = 0; i < singles.length; i++) {\n        result[singles[i]] = true;\n    }\n    var ranges = [[0, 47], [58, 64], [91, 94], [123, 169], [171, 177], [182, 184], [706, 709],\n         [722, 735], [741, 747], [751, 879], [888, 889], [894, 901], [1154, 1161],\n         [1318, 1328], [1367, 1368], [1370, 1376], [1416, 1487], [1515, 1519], [1523, 1568],\n         [1611, 1631], [1642, 1645], [1750, 1764], [1767, 1773], [1789, 1790], [1792, 1807],\n         [1840, 1868], [1958, 1968], [1970, 1983], [2027, 2035], [2038, 2041], [2043, 2047],\n         [2070, 2073], [2075, 2083], [2085, 2087], [2089, 2307], [2362, 2364], [2366, 2383],\n         [2385, 2391], [2402, 2405], [2419, 2424], [2432, 2436], [2445, 2446], [2449, 2450],\n         [2483, 2485], [2490, 2492], [2494, 2509], [2511, 2523], [2530, 2533], [2546, 2547],\n         [2554, 2564], [2571, 2574], [2577, 2578], [2618, 2648], [2655, 2661], [2672, 2673],\n         [2677, 2692], [2746, 2748], [2750, 2767], [2769, 2783], [2786, 2789], [2800, 2820],\n         [2829, 2830], [2833, 2834], [2874, 2876], [2878, 2907], [2914, 2917], [2930, 2946],\n         [2955, 2957], [2966, 2968], [2976, 2978], [2981, 2983], [2987, 2989], [3002, 3023],\n         [3025, 3045], [3059, 3076], [3130, 3132], [3134, 3159], [3162, 3167], [3170, 3173],\n         [3184, 3191], [3199, 3204], [3258, 3260], [3262, 3293], [3298, 3301], [3312, 3332],\n         [3386, 3388], [3390, 3423], [3426, 3429], [3446, 3449], [3456, 3460], [3479, 3481],\n         [3518, 3519], [3527, 3584], [3636, 3647], [3655, 3663], [3674, 3712], [3717, 3718],\n         [3723, 3724], [3726, 3731], [3752, 3753], [3764, 3772], [3774, 3775], [3783, 3791],\n         [3802, 3803], [3806, 3839], [3841, 3871], [3892, 3903], [3949, 3975], [3980, 4095],\n         [4139, 4158], [4170, 4175], [4182, 4185], [4190, 4192], [4194, 4196], [4199, 4205],\n         [4209, 4212], [4226, 4237], [4250, 4255], [4294, 4303], [4349, 4351], [4686, 4687],\n         [4702, 4703], [4750, 4751], [4790, 4791], [4806, 4807], [4886, 4887], [4955, 4968],\n         [4989, 4991], [5008, 5023], [5109, 5120], [5741, 5742], [5787, 5791], [5867, 5869],\n         [5873, 5887], [5906, 5919], [5938, 5951], [5970, 5983], [6001, 6015], [6068, 6102],\n         [6104, 6107], [6109, 6111], [6122, 6127], [6138, 6159], [6170, 6175], [6264, 6271],\n         [6315, 6319], [6390, 6399], [6429, 6469], [6510, 6511], [6517, 6527], [6572, 6592],\n         [6600, 6607], [6619, 6655], [6679, 6687], [6741, 6783], [6794, 6799], [6810, 6822],\n         [6824, 6916], [6964, 6980], [6988, 6991], [7002, 7042], [7073, 7085], [7098, 7167],\n         [7204, 7231], [7242, 7244], [7294, 7400], [7410, 7423], [7616, 7679], [7958, 7959],\n         [7966, 7967], [8006, 8007], [8014, 8015], [8062, 8063], [8127, 8129], [8141, 8143],\n         [8148, 8149], [8156, 8159], [8173, 8177], [8189, 8303], [8306, 8307], [8314, 8318],\n         [8330, 8335], [8341, 8449], [8451, 8454], [8456, 8457], [8470, 8472], [8478, 8483],\n         [8506, 8507], [8512, 8516], [8522, 8525], [8586, 9311], [9372, 9449], [9472, 10101],\n         [10132, 11263], [11493, 11498], [11503, 11516], [11518, 11519], [11558, 11567],\n         [11622, 11630], [11632, 11647], [11671, 11679], [11743, 11822], [11824, 12292],\n         [12296, 12320], [12330, 12336], [12342, 12343], [12349, 12352], [12439, 12444],\n         [12544, 12548], [12590, 12592], [12687, 12689], [12694, 12703], [12728, 12783],\n         [12800, 12831], [12842, 12880], [12896, 12927], [12938, 12976], [12992, 13311],\n         [19894, 19967], [40908, 40959], [42125, 42191], [42238, 42239], [42509, 42511],\n         [42540, 42559], [42592, 42593], [42607, 42622], [42648, 42655], [42736, 42774],\n         [42784, 42785], [42889, 42890], [42893, 43002], [43043, 43055], [43062, 43071],\n         [43124, 43137], [43188, 43215], [43226, 43249], [43256, 43258], [43260, 43263],\n         [43302, 43311], [43335, 43359], [43389, 43395], [43443, 43470], [43482, 43519],\n         [43561, 43583], [43596, 43599], [43610, 43615], [43639, 43641], [43643, 43647],\n         [43698, 43700], [43703, 43704], [43710, 43711], [43715, 43738], [43742, 43967],\n         [44003, 44015], [44026, 44031], [55204, 55215], [55239, 55242], [55292, 55295],\n         [57344, 63743], [64046, 64047], [64110, 64111], [64218, 64255], [64263, 64274],\n         [64280, 64284], [64434, 64466], [64830, 64847], [64912, 64913], [64968, 65007],\n         [65020, 65135], [65277, 65295], [65306, 65312], [65339, 65344], [65371, 65381],\n         [65471, 65473], [65480, 65481], [65488, 65489], [65496, 65497]];\n    for (i = 0; i < ranges.length; i++) {\n        start = ranges[i][0];\n        end = ranges[i][1];\n        for (j = start; j <= end; j++) {\n            result[j] = true;\n        }\n    }\n    return result;\n})();\n\nfunction splitQuery(query) {\n    var result = [];\n    var start = -1;\n    for (var i = 0; i < query.length; i++) {\n        if (splitChars[query.charCodeAt(i)]) {\n            if (start !== -1) {\n                result.push(query.slice(start, i));\n                start = -1;\n            }\n        } else if (start === -1) {\n            start = i;\n        }\n    }\n    if (start !== -1) {\n        result.push(query.slice(start));\n    }\n    return result;\n}\n\n\n"
  },
  {
    "path": "docs/_static/pygments.css",
    "content": ".highlight .hll { background-color: #ffffcc }\n.highlight  { background: #f8f8f8; }\n.highlight .c { color: #408080; font-style: italic } /* Comment */\n.highlight .err { border: 1px solid #FF0000 } /* Error */\n.highlight .k { color: #008000; font-weight: bold } /* Keyword */\n.highlight .o { color: #666666 } /* Operator */\n.highlight .ch { color: #408080; font-style: italic } /* Comment.Hashbang */\n.highlight .cm { color: #408080; font-style: italic } /* Comment.Multiline */\n.highlight .cp { color: #BC7A00 } /* Comment.Preproc */\n.highlight .cpf { color: #408080; font-style: italic } /* Comment.PreprocFile */\n.highlight .c1 { color: #408080; font-style: italic } /* Comment.Single */\n.highlight .cs { color: #408080; font-style: italic } /* Comment.Special */\n.highlight .gd { color: #A00000 } /* Generic.Deleted */\n.highlight .ge { font-style: italic } /* Generic.Emph */\n.highlight .gr { color: #FF0000 } /* Generic.Error */\n.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */\n.highlight .gi { color: #00A000 } /* Generic.Inserted */\n.highlight .go { color: #888888 } /* Generic.Output */\n.highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */\n.highlight .gs { font-weight: bold } /* Generic.Strong */\n.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */\n.highlight .gt { color: #0044DD } /* Generic.Traceback */\n.highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */\n.highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */\n.highlight .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */\n.highlight .kp { color: #008000 } /* Keyword.Pseudo */\n.highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */\n.highlight .kt { color: #B00040 } /* Keyword.Type */\n.highlight .m { color: #666666 } /* Literal.Number */\n.highlight .s { color: #BA2121 } /* Literal.String */\n.highlight .na { color: #7D9029 } /* Name.Attribute */\n.highlight .nb { color: #008000 } /* Name.Builtin */\n.highlight .nc { color: #0000FF; font-weight: bold } /* Name.Class */\n.highlight .no { color: #880000 } /* Name.Constant */\n.highlight .nd { color: #AA22FF } /* Name.Decorator */\n.highlight .ni { color: #999999; font-weight: bold } /* Name.Entity */\n.highlight .ne { color: #D2413A; font-weight: bold } /* Name.Exception */\n.highlight .nf { color: #0000FF } /* Name.Function */\n.highlight .nl { color: #A0A000 } /* Name.Label */\n.highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */\n.highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */\n.highlight .nv { color: #19177C } /* Name.Variable */\n.highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */\n.highlight .w { color: #bbbbbb } /* Text.Whitespace */\n.highlight .mb { color: #666666 } /* Literal.Number.Bin */\n.highlight .mf { color: #666666 } /* Literal.Number.Float */\n.highlight .mh { color: #666666 } /* Literal.Number.Hex */\n.highlight .mi { color: #666666 } /* Literal.Number.Integer */\n.highlight .mo { color: #666666 } /* Literal.Number.Oct */\n.highlight .sa { color: #BA2121 } /* Literal.String.Affix */\n.highlight .sb { color: #BA2121 } /* Literal.String.Backtick */\n.highlight .sc { color: #BA2121 } /* Literal.String.Char */\n.highlight .dl { color: #BA2121 } /* Literal.String.Delimiter */\n.highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */\n.highlight .s2 { color: #BA2121 } /* Literal.String.Double */\n.highlight .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */\n.highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */\n.highlight .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */\n.highlight .sx { color: #008000 } /* Literal.String.Other */\n.highlight .sr { color: #BB6688 } /* Literal.String.Regex */\n.highlight .s1 { color: #BA2121 } /* Literal.String.Single */\n.highlight .ss { color: #19177C } /* Literal.String.Symbol */\n.highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */\n.highlight .fm { color: #0000FF } /* Name.Function.Magic */\n.highlight .vc { color: #19177C } /* Name.Variable.Class */\n.highlight .vg { color: #19177C } /* Name.Variable.Global */\n.highlight .vi { color: #19177C } /* Name.Variable.Instance */\n.highlight .vm { color: #19177C } /* Name.Variable.Magic */\n.highlight .il { color: #666666 } /* Literal.Number.Integer.Long */"
  },
  {
    "path": "docs/_static/searchtools.js",
    "content": "/*\n * searchtools.js\n * ~~~~~~~~~~~~~~~~\n *\n * Sphinx JavaScript utilities for the full-text search.\n *\n * :copyright: Copyright 2007-2019 by the Sphinx team, see AUTHORS.\n * :license: BSD, see LICENSE for details.\n *\n */\n\nif (!Scorer) {\n  /**\n   * Simple result scoring code.\n   */\n  var Scorer = {\n    // Implement the following function to further tweak the score for each result\n    // The function takes a result array [filename, title, anchor, descr, score]\n    // and returns the new score.\n    /*\n    score: function(result) {\n      return result[4];\n    },\n    */\n\n    // query matches the full name of an object\n    objNameMatch: 11,\n    // or matches in the last dotted part of the object name\n    objPartialMatch: 6,\n    // Additive scores depending on the priority of the object\n    objPrio: {0:  15,   // used to be importantResults\n              1:  5,   // used to be objectResults\n              2: -5},  // used to be unimportantResults\n    //  Used when the priority is not in the mapping.\n    objPrioDefault: 0,\n\n    // query found in title\n    title: 15,\n    // query found in terms\n    term: 5\n  };\n}\n\nif (!splitQuery) {\n  function splitQuery(query) {\n    return query.split(/\\s+/);\n  }\n}\n\n/**\n * Search Module\n */\nvar Search = {\n\n  _index : null,\n  _queued_query : null,\n  _pulse_status : -1,\n\n  init : function() {\n      var params = $.getQueryParameters();\n      if (params.q) {\n          var query = params.q[0];\n          $('input[name=\"q\"]')[0].value = query;\n          this.performSearch(query);\n      }\n  },\n\n  loadIndex : function(url) {\n    $.ajax({type: \"GET\", url: url, data: null,\n            dataType: \"script\", cache: true,\n            complete: function(jqxhr, textstatus) {\n              if (textstatus != \"success\") {\n                document.getElementById(\"searchindexloader\").src = url;\n              }\n            }});\n  },\n\n  setIndex : function(index) {\n    var q;\n    this._index = index;\n    if ((q = this._queued_query) !== null) {\n      this._queued_query = null;\n      Search.query(q);\n    }\n  },\n\n  hasIndex : function() {\n      return this._index !== null;\n  },\n\n  deferQuery : function(query) {\n      this._queued_query = query;\n  },\n\n  stopPulse : function() {\n      this._pulse_status = 0;\n  },\n\n  startPulse : function() {\n    if (this._pulse_status >= 0)\n        return;\n    function pulse() {\n      var i;\n      Search._pulse_status = (Search._pulse_status + 1) % 4;\n      var dotString = '';\n      for (i = 0; i < Search._pulse_status; i++)\n        dotString += '.';\n      Search.dots.text(dotString);\n      if (Search._pulse_status > -1)\n        window.setTimeout(pulse, 500);\n    }\n    pulse();\n  },\n\n  /**\n   * perform a search for something (or wait until index is loaded)\n   */\n  performSearch : function(query) {\n    // create the required interface elements\n    this.out = $('#search-results');\n    this.title = $('<h2>' + _('Searching') + '</h2>').appendTo(this.out);\n    this.dots = $('<span></span>').appendTo(this.title);\n    this.status = $('<p style=\"display: none\"></p>').appendTo(this.out);\n    this.output = $('<ul class=\"search\"/>').appendTo(this.out);\n\n    $('#search-progress').text(_('Preparing search...'));\n    this.startPulse();\n\n    // index already loaded, the browser was quick!\n    if (this.hasIndex())\n      this.query(query);\n    else\n      this.deferQuery(query);\n  },\n\n  /**\n   * execute search (requires search index to be loaded)\n   */\n  query : function(query) {\n    var i;\n\n    // stem the searchterms and add them to the correct list\n    var stemmer = new Stemmer();\n    var searchterms = [];\n    var excluded = [];\n    var hlterms = [];\n    var tmp = splitQuery(query);\n    var objectterms = [];\n    for (i = 0; i < tmp.length; i++) {\n      if (tmp[i] !== \"\") {\n          objectterms.push(tmp[i].toLowerCase());\n      }\n\n      if ($u.indexOf(stopwords, tmp[i].toLowerCase()) != -1 || tmp[i].match(/^\\d+$/) ||\n          tmp[i] === \"\") {\n        // skip this \"word\"\n        continue;\n      }\n      // stem the word\n      var word = stemmer.stemWord(tmp[i].toLowerCase());\n      // prevent stemmer from cutting word smaller than two chars\n      if(word.length < 3 && tmp[i].length >= 3) {\n        word = tmp[i];\n      }\n      var toAppend;\n      // select the correct list\n      if (word[0] == '-') {\n        toAppend = excluded;\n        word = word.substr(1);\n      }\n      else {\n        toAppend = searchterms;\n        hlterms.push(tmp[i].toLowerCase());\n      }\n      // only add if not already in the list\n      if (!$u.contains(toAppend, word))\n        toAppend.push(word);\n    }\n    var highlightstring = '?highlight=' + $.urlencode(hlterms.join(\" \"));\n\n    // console.debug('SEARCH: searching for:');\n    // console.info('required: ', searchterms);\n    // console.info('excluded: ', excluded);\n\n    // prepare search\n    var terms = this._index.terms;\n    var titleterms = this._index.titleterms;\n\n    // array of [filename, title, anchor, descr, score]\n    var results = [];\n    $('#search-progress').empty();\n\n    // lookup as object\n    for (i = 0; i < objectterms.length; i++) {\n      var others = [].concat(objectterms.slice(0, i),\n                             objectterms.slice(i+1, objectterms.length));\n      results = results.concat(this.performObjectSearch(objectterms[i], others));\n    }\n\n    // lookup as search terms in fulltext\n    results = results.concat(this.performTermsSearch(searchterms, excluded, terms, titleterms));\n\n    // let the scorer override scores with a custom scoring function\n    if (Scorer.score) {\n      for (i = 0; i < results.length; i++)\n        results[i][4] = Scorer.score(results[i]);\n    }\n\n    // now sort the results by score (in opposite order of appearance, since the\n    // display function below uses pop() to retrieve items) and then\n    // alphabetically\n    results.sort(function(a, b) {\n      var left = a[4];\n      var right = b[4];\n      if (left > right) {\n        return 1;\n      } else if (left < right) {\n        return -1;\n      } else {\n        // same score: sort alphabetically\n        left = a[1].toLowerCase();\n        right = b[1].toLowerCase();\n        return (left > right) ? -1 : ((left < right) ? 1 : 0);\n      }\n    });\n\n    // for debugging\n    //Search.lastresults = results.slice();  // a copy\n    //console.info('search results:', Search.lastresults);\n\n    // print the results\n    var resultCount = results.length;\n    function displayNextItem() {\n      // results left, load the summary and display it\n      if (results.length) {\n        var item = results.pop();\n        var listItem = $('<li style=\"display:none\"></li>');\n        if (DOCUMENTATION_OPTIONS.FILE_SUFFIX === '') {\n          // dirhtml builder\n          var dirname = item[0] + '/';\n          if (dirname.match(/\\/index\\/$/)) {\n            dirname = dirname.substring(0, dirname.length-6);\n          } else if (dirname == 'index/') {\n            dirname = '';\n          }\n          listItem.append($('<a/>').attr('href',\n            DOCUMENTATION_OPTIONS.URL_ROOT + dirname +\n            highlightstring + item[2]).html(item[1]));\n        } else {\n          // normal html builders\n          listItem.append($('<a/>').attr('href',\n            item[0] + DOCUMENTATION_OPTIONS.FILE_SUFFIX +\n            highlightstring + item[2]).html(item[1]));\n        }\n        if (item[3]) {\n          listItem.append($('<span> (' + item[3] + ')</span>'));\n          Search.output.append(listItem);\n          listItem.slideDown(5, function() {\n            displayNextItem();\n          });\n        } else if (DOCUMENTATION_OPTIONS.HAS_SOURCE) {\n          var suffix = DOCUMENTATION_OPTIONS.SOURCELINK_SUFFIX;\n          if (suffix === undefined) {\n            suffix = '.txt';\n          }\n          $.ajax({url: DOCUMENTATION_OPTIONS.URL_ROOT + '_sources/' + item[5] + (item[5].slice(-suffix.length) === suffix ? '' : suffix),\n                  dataType: \"text\",\n                  complete: function(jqxhr, textstatus) {\n                    var data = jqxhr.responseText;\n                    if (data !== '' && data !== undefined) {\n                      listItem.append(Search.makeSearchSummary(data, searchterms, hlterms));\n                    }\n                    Search.output.append(listItem);\n                    listItem.slideDown(5, function() {\n                      displayNextItem();\n                    });\n                  }});\n        } else {\n          // no source available, just display title\n          Search.output.append(listItem);\n          listItem.slideDown(5, function() {\n            displayNextItem();\n          });\n        }\n      }\n      // search finished, update title and status message\n      else {\n        Search.stopPulse();\n        Search.title.text(_('Search Results'));\n        if (!resultCount)\n          Search.status.text(_('Your search did not match any documents. Please make sure that all words are spelled correctly and that you\\'ve selected enough categories.'));\n        else\n            Search.status.text(_('Search finished, found %s page(s) matching the search query.').replace('%s', resultCount));\n        Search.status.fadeIn(500);\n      }\n    }\n    displayNextItem();\n  },\n\n  /**\n   * search for object names\n   */\n  performObjectSearch : function(object, otherterms) {\n    var filenames = this._index.filenames;\n    var docnames = this._index.docnames;\n    var objects = this._index.objects;\n    var objnames = this._index.objnames;\n    var titles = this._index.titles;\n\n    var i;\n    var results = [];\n\n    for (var prefix in objects) {\n      for (var name in objects[prefix]) {\n        var fullname = (prefix ? prefix + '.' : '') + name;\n        if (fullname.toLowerCase().indexOf(object) > -1) {\n          var score = 0;\n          var parts = fullname.split('.');\n          // check for different match types: exact matches of full name or\n          // \"last name\" (i.e. last dotted part)\n          if (fullname == object || parts[parts.length - 1] == object) {\n            score += Scorer.objNameMatch;\n          // matches in last name\n          } else if (parts[parts.length - 1].indexOf(object) > -1) {\n            score += Scorer.objPartialMatch;\n          }\n          var match = objects[prefix][name];\n          var objname = objnames[match[1]][2];\n          var title = titles[match[0]];\n          // If more than one term searched for, we require other words to be\n          // found in the name/title/description\n          if (otherterms.length > 0) {\n            var haystack = (prefix + ' ' + name + ' ' +\n                            objname + ' ' + title).toLowerCase();\n            var allfound = true;\n            for (i = 0; i < otherterms.length; i++) {\n              if (haystack.indexOf(otherterms[i]) == -1) {\n                allfound = false;\n                break;\n              }\n            }\n            if (!allfound) {\n              continue;\n            }\n          }\n          var descr = objname + _(', in ') + title;\n\n          var anchor = match[3];\n          if (anchor === '')\n            anchor = fullname;\n          else if (anchor == '-')\n            anchor = objnames[match[1]][1] + '-' + fullname;\n          // add custom score for some objects according to scorer\n          if (Scorer.objPrio.hasOwnProperty(match[2])) {\n            score += Scorer.objPrio[match[2]];\n          } else {\n            score += Scorer.objPrioDefault;\n          }\n          results.push([docnames[match[0]], fullname, '#'+anchor, descr, score, filenames[match[0]]]);\n        }\n      }\n    }\n\n    return results;\n  },\n\n  /**\n   * search for full-text terms in the index\n   */\n  performTermsSearch : function(searchterms, excluded, terms, titleterms) {\n    var docnames = this._index.docnames;\n    var filenames = this._index.filenames;\n    var titles = this._index.titles;\n\n    var i, j, file;\n    var fileMap = {};\n    var scoreMap = {};\n    var results = [];\n\n    // perform the search on the required terms\n    for (i = 0; i < searchterms.length; i++) {\n      var word = searchterms[i];\n      var files = [];\n      var _o = [\n        {files: terms[word], score: Scorer.term},\n        {files: titleterms[word], score: Scorer.title}\n      ];\n\n      // no match but word was a required one\n      if ($u.every(_o, function(o){return o.files === undefined;})) {\n        break;\n      }\n      // found search word in contents\n      $u.each(_o, function(o) {\n        var _files = o.files;\n        if (_files === undefined)\n          return\n\n        if (_files.length === undefined)\n          _files = [_files];\n        files = files.concat(_files);\n\n        // set score for the word in each file to Scorer.term\n        for (j = 0; j < _files.length; j++) {\n          file = _files[j];\n          if (!(file in scoreMap))\n            scoreMap[file] = {}\n          scoreMap[file][word] = o.score;\n        }\n      });\n\n      // create the mapping\n      for (j = 0; j < files.length; j++) {\n        file = files[j];\n        if (file in fileMap)\n          fileMap[file].push(word);\n        else\n          fileMap[file] = [word];\n      }\n    }\n\n    // now check if the files don't contain excluded terms\n    for (file in fileMap) {\n      var valid = true;\n\n      // check if all requirements are matched\n      if (fileMap[file].length != searchterms.length)\n          continue;\n\n      // ensure that none of the excluded terms is in the search result\n      for (i = 0; i < excluded.length; i++) {\n        if (terms[excluded[i]] == file ||\n            titleterms[excluded[i]] == file ||\n            $u.contains(terms[excluded[i]] || [], file) ||\n            $u.contains(titleterms[excluded[i]] || [], file)) {\n          valid = false;\n          break;\n        }\n      }\n\n      // if we have still a valid result we can add it to the result list\n      if (valid) {\n        // select one (max) score for the file.\n        // for better ranking, we should calculate ranking by using words statistics like basic tf-idf...\n        var score = $u.max($u.map(fileMap[file], function(w){return scoreMap[file][w]}));\n        results.push([docnames[file], titles[file], '', null, score, filenames[file]]);\n      }\n    }\n    return results;\n  },\n\n  /**\n   * helper function to return a node containing the\n   * search summary for a given text. keywords is a list\n   * of stemmed words, hlwords is the list of normal, unstemmed\n   * words. the first one is used to find the occurrence, the\n   * latter for highlighting it.\n   */\n  makeSearchSummary : function(text, keywords, hlwords) {\n    var textLower = text.toLowerCase();\n    var start = 0;\n    $.each(keywords, function() {\n      var i = textLower.indexOf(this.toLowerCase());\n      if (i > -1)\n        start = i;\n    });\n    start = Math.max(start - 120, 0);\n    var excerpt = ((start > 0) ? '...' : '') +\n      $.trim(text.substr(start, 240)) +\n      ((start + 240 - text.length) ? '...' : '');\n    var rv = $('<div class=\"context\"></div>').text(excerpt);\n    $.each(hlwords, function() {\n      rv = rv.highlightText(this, 'highlighted');\n    });\n    return rv;\n  }\n};\n\n$(document).ready(function() {\n  Search.init();\n});\n"
  },
  {
    "path": "docs/_static/translations.js",
    "content": "Documentation.addTranslations({\"locale\": \"zh_Hans_CN\", \"messages\": {\"%(filename)s &#8212; %(docstitle)s\": \"%(filename)s &#8212; %(docstitle)s\", \"&#169; <a href=\\\"%(path)s\\\">Copyright</a> %(copyright)s.\": \"&#169; <a href=\\\"%(path)s\\\"> \\u7248\\u6743\\u6240\\u6709</a> %(copyright)s.\", \"&#169; Copyright %(copyright)s.\": \"&#169; \\u7248\\u6743\\u6240\\u6709 %(copyright)s.\", \", in \": \"\\uff0c\\u5728\", \"About these documents\": \"\\u5173\\u4e8e\\u8fd9\\u4e9b\\u6587\\u6863\", \"Automatically generated list of changes in version %(version)s\": \"\\u81ea\\u52a8\\u751f\\u6210\\u7684 %(version)s \\u7248\\u672c\\u4e2d\\u7684\\u66f4\\u6539\\u5217\\u8868\", \"C API changes\": \"C API \\u66f4\\u6539\", \"Changes in Version %(version)s &#8212; %(docstitle)s\": \"\\u66f4\\u6539\\u53d1\\u751f\\u5728\\u7248\\u672c %(version)s&#8212; %(docstitle)s\", \"Collapse sidebar\": \"\\u6298\\u53e0\\u8fb9\\u680f\", \"Complete Table of Contents\": \"\\u5b8c\\u6574\\u7684\\u5185\\u5bb9\\u8868\", \"Contents\": \"\\u76ee\\u5f55\", \"Copyright\": \"\\u7248\\u6743\\u6240\\u6709\", \"Created using <a href=\\\"http://sphinx-doc.org/\\\">Sphinx</a> %(sphinx_version)s.\": \"\\u7531 <a href=\\\"http://sphinx-doc.org/\\\">Sphinx</a> %(sphinx_version)s \\u521b\\u5efa\\u3002\", \"Expand sidebar\": \"\\u5c55\\u5f00\\u8fb9\\u680f\", \"From here you can search these documents. Enter your search\\n    words into the box below and click \\\"search\\\". Note that the search\\n    function will automatically search for all of the words. Pages\\n    containing fewer words won't appear in the result list.\": \"\\u5728\\u8fd9\\u513f\\uff0c\\u4f60\\u53ef\\u4ee5\\u5bf9\\u8fd9\\u4e9b\\u6587\\u6863\\u8fdb\\u884c\\u641c\\u7d22\\u3002\\u5411\\u641c\\u7d22\\u6846\\u4e2d\\u8f93\\u5165\\u4f60\\u6240\\u8981\\u641c\\u7d22\\u7684\\u5173\\u952e\\u5b57\\u5e76\\u70b9\\u51fb\\u201c\\u641c\\u7d22\\u201d\\u3002\\u6ce8\\u610f\\uff1a\\u641c\\u7d22\\u5f15\\u64ce\\u4f1a\\u81ea\\u52a8\\u641c\\u7d22\\u6240\\u6709\\u7684\\u5173\\u952e\\u5b57\\u3002\\u5c06\\u4e0d\\u4f1a\\u641c\\u7d22\\u5230\\u90e8\\u5206\\u5173\\u952e\\u5b57\\u7684\\u9875\\u9762.\", \"Full index on one page\": \"\\u4e00\\u9875\\u7684\\u5168\\u90e8\\u7d22\\u5f15\", \"General Index\": \"\\u603b\\u76ee\\u5f55\", \"Global Module Index\": \"\\u5168\\u5c40\\u6a21\\u5757\\u7d22\\u5f15\", \"Go\": \"\\u8f6c\\u5411\", \"Hide Search Matches\": \"\\u9690\\u85cf\\u641c\\u7d22\\u7ed3\\u679c\", \"Index\": \"\\u7d22\\u5f15\", \"Index &ndash; %(key)s\": \"\\u7d22\\u5f15 &ndash; %(key)s\", \"Index pages by letter\": \"\\u6309\\u7167\\u5b57\\u6bcd\\u7684\\u7d22\\u5f15\\u9875\", \"Indices and tables:\": \"\\u7d22\\u5f15\\u548c\\u8868\\u683c\\uff1a\", \"Last updated on %(last_updated)s.\": \"\\u6700\\u540e\\u66f4\\u65b0\\u4e8e %(last_updated)s.\", \"Library changes\": \"\\u5e93\\u66f4\\u6539\", \"Navigation\": \"\\u5bfc\\u822a\", \"Next topic\": \"\\u4e0b\\u4e00\\u4e2a\\u4e3b\\u9898\", \"Other changes\": \"\\u5176\\u4ed6\\u66f4\\u6539\", \"Overview\": \"\\u6982\\u8ff0\", \"Permalink to this definition\": \"\\u6c38\\u4e45\\u94fe\\u63a5\\u81f3\\u76ee\\u6807\", \"Permalink to this headline\": \"\\u6c38\\u4e45\\u94fe\\u63a5\\u81f3\\u6807\\u9898\", \"Please activate JavaScript to enable the search\\n    functionality.\": \"\\u8bf7\\u6fc0\\u6d3b JavaScript \\u4ee5\\u5f00\\u542f\\u641c\\u7d22\\u529f\\u80fd\", \"Preparing search...\": \"\\u51c6\\u5907\\u641c\\u7d22\\u2026\\u2026\", \"Previous topic\": \"\\u4e0a\\u4e00\\u4e2a\\u4e3b\\u9898\", \"Quick search\": \"\\u5feb\\u901f\\u641c\\u7d22\", \"Search\": \"\\u641c\\u7d22\", \"Search Page\": \"\\u641c\\u7d22\\u9875\\u9762\", \"Search Results\": \"\\u641c\\u7d22\\u7ed3\\u679c\", \"Search finished, found %s page(s) matching the search query.\": \"\\u641c\\u7d22\\u5b8c\\u6210\\uff0c\\u6709 %s \\u4e2a\\u9875\\u9762\\u5339\\u914d\\u3002\", \"Search within %(docstitle)s\": \"\\u5728 %(docstitle)s \\u4e2d\\u641c\\u7d22\", \"Searching\": \"\\u641c\\u7d22\\u4e2d\", \"Show Source\": \"\\u663e\\u793a\\u6e90\\u4ee3\\u7801\", \"Table of Contents\": \"\", \"This Page\": \"\\u672c\\u9875\", \"Welcome! This is\": \"\\u6b22\\u8fce\\uff01\\u8fd9\\u662f\", \"Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.\": \"\\u6ca1\\u6709\\u4efb\\u4f55\\u6587\\u6863\\u5339\\u914d\\u60a8\\u7684\\u641c\\u7d22\\u3002\\u8bf7\\u786e\\u4fdd\\u4f60\\u8f93\\u5165\\u7684\\u8bcd\\u62fc\\u5199\\u6b63\\u786e\\u5e76\\u9009\\u62e9\\u4e86\\u5408\\u9002\\u7684\\u5206\\u7c7b\\u3002\", \"all functions, classes, terms\": \"\\u6240\\u7684\\u51fd\\u6570\\uff0c\\u7c7b\\uff0c\\u672f\\u8bed\", \"can be huge\": \"\\u53ef\\u80fd\\u4f1a\\u5f88\\u591a\", \"last updated\": \"\\u6700\\u540e\\u66f4\\u65b0\\u4e8e\", \"lists all sections and subsections\": \"\\u5217\\u51fa\\u6240\\u6709\\u7684\\u7ae0\\u8282\\u548c\\u90e8\\u5206\", \"next chapter\": \"\\u4e0b\\u4e00\\u7ae0\", \"previous chapter\": \"\\u4e0a\\u4e00\\u7ae0\", \"quick access to all modules\": \"\\u5feb\\u901f\\u67e5\\u770b\\u6240\\u6709\\u7684\\u6a21\\u5757\", \"search\": \"\\u641c\\u7d22\", \"search this documentation\": \"\\u641c\\u7d22\\u6587\\u6863\", \"the documentation for\": \"\\u8fd9\\u4efd\\u6587\\u6863\\u662f\"}, \"plural_expr\": \"0\"});\n"
  },
  {
    "path": "docs/_static/underscore-1.3.1.js",
    "content": "//     Underscore.js 1.3.1\n//     (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc.\n//     Underscore is freely distributable under the MIT license.\n//     Portions of Underscore are inspired or borrowed from Prototype,\n//     Oliver Steele's Functional, and John Resig's Micro-Templating.\n//     For all details and documentation:\n//     http://documentcloud.github.com/underscore\n\n(function() {\n\n  // Baseline setup\n  // --------------\n\n  // Establish the root object, `window` in the browser, or `global` on the server.\n  var root = this;\n\n  // Save the previous value of the `_` variable.\n  var previousUnderscore = root._;\n\n  // Establish the object that gets returned to break out of a loop iteration.\n  var breaker = {};\n\n  // Save bytes in the minified (but not gzipped) version:\n  var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype;\n\n  // Create quick reference variables for speed access to core prototypes.\n  var slice            = ArrayProto.slice,\n      unshift          = ArrayProto.unshift,\n      toString         = ObjProto.toString,\n      hasOwnProperty   = ObjProto.hasOwnProperty;\n\n  // All **ECMAScript 5** native function implementations that we hope to use\n  // are declared here.\n  var\n    nativeForEach      = ArrayProto.forEach,\n    nativeMap          = ArrayProto.map,\n    nativeReduce       = ArrayProto.reduce,\n    nativeReduceRight  = ArrayProto.reduceRight,\n    nativeFilter       = ArrayProto.filter,\n    nativeEvery        = ArrayProto.every,\n    nativeSome         = ArrayProto.some,\n    nativeIndexOf      = ArrayProto.indexOf,\n    nativeLastIndexOf  = ArrayProto.lastIndexOf,\n    nativeIsArray      = Array.isArray,\n    nativeKeys         = Object.keys,\n    nativeBind         = FuncProto.bind;\n\n  // Create a safe reference to the Underscore object for use below.\n  var _ = function(obj) { return new wrapper(obj); };\n\n  // Export the Underscore object for **Node.js**, with\n  // backwards-compatibility for the old `require()` API. If we're in\n  // the browser, add `_` as a global object via a string identifier,\n  // for Closure Compiler \"advanced\" mode.\n  if (typeof exports !== 'undefined') {\n    if (typeof module !== 'undefined' && module.exports) {\n      exports = module.exports = _;\n    }\n    exports._ = _;\n  } else {\n    root['_'] = _;\n  }\n\n  // Current version.\n  _.VERSION = '1.3.1';\n\n  // Collection Functions\n  // --------------------\n\n  // The cornerstone, an `each` implementation, aka `forEach`.\n  // Handles objects with the built-in `forEach`, arrays, and raw objects.\n  // Delegates to **ECMAScript 5**'s native `forEach` if available.\n  var each = _.each = _.forEach = function(obj, iterator, context) {\n    if (obj == null) return;\n    if (nativeForEach && obj.forEach === nativeForEach) {\n      obj.forEach(iterator, context);\n    } else if (obj.length === +obj.length) {\n      for (var i = 0, l = obj.length; i < l; i++) {\n        if (i in obj && iterator.call(context, obj[i], i, obj) === breaker) return;\n      }\n    } else {\n      for (var key in obj) {\n        if (_.has(obj, key)) {\n          if (iterator.call(context, obj[key], key, obj) === breaker) return;\n        }\n      }\n    }\n  };\n\n  // Return the results of applying the iterator to each element.\n  // Delegates to **ECMAScript 5**'s native `map` if available.\n  _.map = _.collect = function(obj, iterator, context) {\n    var results = [];\n    if (obj == null) return results;\n    if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);\n    each(obj, function(value, index, list) {\n      results[results.length] = iterator.call(context, value, index, list);\n    });\n    if (obj.length === +obj.length) results.length = obj.length;\n    return results;\n  };\n\n  // **Reduce** builds up a single result from a list of values, aka `inject`,\n  // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available.\n  _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) {\n    var initial = arguments.length > 2;\n    if (obj == null) obj = [];\n    if (nativeReduce && obj.reduce === nativeReduce) {\n      if (context) iterator = _.bind(iterator, context);\n      return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator);\n    }\n    each(obj, function(value, index, list) {\n      if (!initial) {\n        memo = value;\n        initial = true;\n      } else {\n        memo = iterator.call(context, memo, value, index, list);\n      }\n    });\n    if (!initial) throw new TypeError('Reduce of empty array with no initial value');\n    return memo;\n  };\n\n  // The right-associative version of reduce, also known as `foldr`.\n  // Delegates to **ECMAScript 5**'s native `reduceRight` if available.\n  _.reduceRight = _.foldr = function(obj, iterator, memo, context) {\n    var initial = arguments.length > 2;\n    if (obj == null) obj = [];\n    if (nativeReduceRight && obj.reduceRight === nativeReduceRight) {\n      if (context) iterator = _.bind(iterator, context);\n      return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);\n    }\n    var reversed = _.toArray(obj).reverse();\n    if (context && !initial) iterator = _.bind(iterator, context);\n    return initial ? _.reduce(reversed, iterator, memo, context) : _.reduce(reversed, iterator);\n  };\n\n  // Return the first value which passes a truth test. Aliased as `detect`.\n  _.find = _.detect = function(obj, iterator, context) {\n    var result;\n    any(obj, function(value, index, list) {\n      if (iterator.call(context, value, index, list)) {\n        result = value;\n        return true;\n      }\n    });\n    return result;\n  };\n\n  // Return all the elements that pass a truth test.\n  // Delegates to **ECMAScript 5**'s native `filter` if available.\n  // Aliased as `select`.\n  _.filter = _.select = function(obj, iterator, context) {\n    var results = [];\n    if (obj == null) return results;\n    if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context);\n    each(obj, function(value, index, list) {\n      if (iterator.call(context, value, index, list)) results[results.length] = value;\n    });\n    return results;\n  };\n\n  // Return all the elements for which a truth test fails.\n  _.reject = function(obj, iterator, context) {\n    var results = [];\n    if (obj == null) return results;\n    each(obj, function(value, index, list) {\n      if (!iterator.call(context, value, index, list)) results[results.length] = value;\n    });\n    return results;\n  };\n\n  // Determine whether all of the elements match a truth test.\n  // Delegates to **ECMAScript 5**'s native `every` if available.\n  // Aliased as `all`.\n  _.every = _.all = function(obj, iterator, context) {\n    var result = true;\n    if (obj == null) return result;\n    if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context);\n    each(obj, function(value, index, list) {\n      if (!(result = result && iterator.call(context, value, index, list))) return breaker;\n    });\n    return result;\n  };\n\n  // Determine if at least one element in the object matches a truth test.\n  // Delegates to **ECMAScript 5**'s native `some` if available.\n  // Aliased as `any`.\n  var any = _.some = _.any = function(obj, iterator, context) {\n    iterator || (iterator = _.identity);\n    var result = false;\n    if (obj == null) return result;\n    if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context);\n    each(obj, function(value, index, list) {\n      if (result || (result = iterator.call(context, value, index, list))) return breaker;\n    });\n    return !!result;\n  };\n\n  // Determine if a given value is included in the array or object using `===`.\n  // Aliased as `contains`.\n  _.include = _.contains = function(obj, target) {\n    var found = false;\n    if (obj == null) return found;\n    if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;\n    found = any(obj, function(value) {\n      return value === target;\n    });\n    return found;\n  };\n\n  // Invoke a method (with arguments) on every item in a collection.\n  _.invoke = function(obj, method) {\n    var args = slice.call(arguments, 2);\n    return _.map(obj, function(value) {\n      return (_.isFunction(method) ? method || value : value[method]).apply(value, args);\n    });\n  };\n\n  // Convenience version of a common use case of `map`: fetching a property.\n  _.pluck = function(obj, key) {\n    return _.map(obj, function(value){ return value[key]; });\n  };\n\n  // Return the maximum element or (element-based computation).\n  _.max = function(obj, iterator, context) {\n    if (!iterator && _.isArray(obj)) return Math.max.apply(Math, obj);\n    if (!iterator && _.isEmpty(obj)) return -Infinity;\n    var result = {computed : -Infinity};\n    each(obj, function(value, index, list) {\n      var computed = iterator ? iterator.call(context, value, index, list) : value;\n      computed >= result.computed && (result = {value : value, computed : computed});\n    });\n    return result.value;\n  };\n\n  // Return the minimum element (or element-based computation).\n  _.min = function(obj, iterator, context) {\n    if (!iterator && _.isArray(obj)) return Math.min.apply(Math, obj);\n    if (!iterator && _.isEmpty(obj)) return Infinity;\n    var result = {computed : Infinity};\n    each(obj, function(value, index, list) {\n      var computed = iterator ? iterator.call(context, value, index, list) : value;\n      computed < result.computed && (result = {value : value, computed : computed});\n    });\n    return result.value;\n  };\n\n  // Shuffle an array.\n  _.shuffle = function(obj) {\n    var shuffled = [], rand;\n    each(obj, function(value, index, list) {\n      if (index == 0) {\n        shuffled[0] = value;\n      } else {\n        rand = Math.floor(Math.random() * (index + 1));\n        shuffled[index] = shuffled[rand];\n        shuffled[rand] = value;\n      }\n    });\n    return shuffled;\n  };\n\n  // Sort the object's values by a criterion produced by an iterator.\n  _.sortBy = function(obj, iterator, context) {\n    return _.pluck(_.map(obj, function(value, index, list) {\n      return {\n        value : value,\n        criteria : iterator.call(context, value, index, list)\n      };\n    }).sort(function(left, right) {\n      var a = left.criteria, b = right.criteria;\n      return a < b ? -1 : a > b ? 1 : 0;\n    }), 'value');\n  };\n\n  // Groups the object's values by a criterion. Pass either a string attribute\n  // to group by, or a function that returns the criterion.\n  _.groupBy = function(obj, val) {\n    var result = {};\n    var iterator = _.isFunction(val) ? val : function(obj) { return obj[val]; };\n    each(obj, function(value, index) {\n      var key = iterator(value, index);\n      (result[key] || (result[key] = [])).push(value);\n    });\n    return result;\n  };\n\n  // Use a comparator function to figure out at what index an object should\n  // be inserted so as to maintain order. Uses binary search.\n  _.sortedIndex = function(array, obj, iterator) {\n    iterator || (iterator = _.identity);\n    var low = 0, high = array.length;\n    while (low < high) {\n      var mid = (low + high) >> 1;\n      iterator(array[mid]) < iterator(obj) ? low = mid + 1 : high = mid;\n    }\n    return low;\n  };\n\n  // Safely convert anything iterable into a real, live array.\n  _.toArray = function(iterable) {\n    if (!iterable)                return [];\n    if (iterable.toArray)         return iterable.toArray();\n    if (_.isArray(iterable))      return slice.call(iterable);\n    if (_.isArguments(iterable))  return slice.call(iterable);\n    return _.values(iterable);\n  };\n\n  // Return the number of elements in an object.\n  _.size = function(obj) {\n    return _.toArray(obj).length;\n  };\n\n  // Array Functions\n  // ---------------\n\n  // Get the first element of an array. Passing **n** will return the first N\n  // values in the array. Aliased as `head`. The **guard** check allows it to work\n  // with `_.map`.\n  _.first = _.head = function(array, n, guard) {\n    return (n != null) && !guard ? slice.call(array, 0, n) : array[0];\n  };\n\n  // Returns everything but the last entry of the array. Especcialy useful on\n  // the arguments object. Passing **n** will return all the values in\n  // the array, excluding the last N. The **guard** check allows it to work with\n  // `_.map`.\n  _.initial = function(array, n, guard) {\n    return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n));\n  };\n\n  // Get the last element of an array. Passing **n** will return the last N\n  // values in the array. The **guard** check allows it to work with `_.map`.\n  _.last = function(array, n, guard) {\n    if ((n != null) && !guard) {\n      return slice.call(array, Math.max(array.length - n, 0));\n    } else {\n      return array[array.length - 1];\n    }\n  };\n\n  // Returns everything but the first entry of the array. Aliased as `tail`.\n  // Especially useful on the arguments object. Passing an **index** will return\n  // the rest of the values in the array from that index onward. The **guard**\n  // check allows it to work with `_.map`.\n  _.rest = _.tail = function(array, index, guard) {\n    return slice.call(array, (index == null) || guard ? 1 : index);\n  };\n\n  // Trim out all falsy values from an array.\n  _.compact = function(array) {\n    return _.filter(array, function(value){ return !!value; });\n  };\n\n  // Return a completely flattened version of an array.\n  _.flatten = function(array, shallow) {\n    return _.reduce(array, function(memo, value) {\n      if (_.isArray(value)) return memo.concat(shallow ? value : _.flatten(value));\n      memo[memo.length] = value;\n      return memo;\n    }, []);\n  };\n\n  // Return a version of the array that does not contain the specified value(s).\n  _.without = function(array) {\n    return _.difference(array, slice.call(arguments, 1));\n  };\n\n  // Produce a duplicate-free version of the array. If the array has already\n  // been sorted, you have the option of using a faster algorithm.\n  // Aliased as `unique`.\n  _.uniq = _.unique = function(array, isSorted, iterator) {\n    var initial = iterator ? _.map(array, iterator) : array;\n    var result = [];\n    _.reduce(initial, function(memo, el, i) {\n      if (0 == i || (isSorted === true ? _.last(memo) != el : !_.include(memo, el))) {\n        memo[memo.length] = el;\n        result[result.length] = array[i];\n      }\n      return memo;\n    }, []);\n    return result;\n  };\n\n  // Produce an array that contains the union: each distinct element from all of\n  // the passed-in arrays.\n  _.union = function() {\n    return _.uniq(_.flatten(arguments, true));\n  };\n\n  // Produce an array that contains every item shared between all the\n  // passed-in arrays. (Aliased as \"intersect\" for back-compat.)\n  _.intersection = _.intersect = function(array) {\n    var rest = slice.call(arguments, 1);\n    return _.filter(_.uniq(array), function(item) {\n      return _.every(rest, function(other) {\n        return _.indexOf(other, item) >= 0;\n      });\n    });\n  };\n\n  // Take the difference between one array and a number of other arrays.\n  // Only the elements present in just the first array will remain.\n  _.difference = function(array) {\n    var rest = _.flatten(slice.call(arguments, 1));\n    return _.filter(array, function(value){ return !_.include(rest, value); });\n  };\n\n  // Zip together multiple lists into a single array -- elements that share\n  // an index go together.\n  _.zip = function() {\n    var args = slice.call(arguments);\n    var length = _.max(_.pluck(args, 'length'));\n    var results = new Array(length);\n    for (var i = 0; i < length; i++) results[i] = _.pluck(args, \"\" + i);\n    return results;\n  };\n\n  // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**),\n  // we need this function. Return the position of the first occurrence of an\n  // item in an array, or -1 if the item is not included in the array.\n  // Delegates to **ECMAScript 5**'s native `indexOf` if available.\n  // If the array is large and already in sort order, pass `true`\n  // for **isSorted** to use binary search.\n  _.indexOf = function(array, item, isSorted) {\n    if (array == null) return -1;\n    var i, l;\n    if (isSorted) {\n      i = _.sortedIndex(array, item);\n      return array[i] === item ? i : -1;\n    }\n    if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item);\n    for (i = 0, l = array.length; i < l; i++) if (i in array && array[i] === item) return i;\n    return -1;\n  };\n\n  // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available.\n  _.lastIndexOf = function(array, item) {\n    if (array == null) return -1;\n    if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) return array.lastIndexOf(item);\n    var i = array.length;\n    while (i--) if (i in array && array[i] === item) return i;\n    return -1;\n  };\n\n  // Generate an integer Array containing an arithmetic progression. A port of\n  // the native Python `range()` function. See\n  // [the Python documentation](http://docs.python.org/library/functions.html#range).\n  _.range = function(start, stop, step) {\n    if (arguments.length <= 1) {\n      stop = start || 0;\n      start = 0;\n    }\n    step = arguments[2] || 1;\n\n    var len = Math.max(Math.ceil((stop - start) / step), 0);\n    var idx = 0;\n    var range = new Array(len);\n\n    while(idx < len) {\n      range[idx++] = start;\n      start += step;\n    }\n\n    return range;\n  };\n\n  // Function (ahem) Functions\n  // ------------------\n\n  // Reusable constructor function for prototype setting.\n  var ctor = function(){};\n\n  // Create a function bound to a given object (assigning `this`, and arguments,\n  // optionally). Binding with arguments is also known as `curry`.\n  // Delegates to **ECMAScript 5**'s native `Function.bind` if available.\n  // We check for `func.bind` first, to fail fast when `func` is undefined.\n  _.bind = function bind(func, context) {\n    var bound, args;\n    if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));\n    if (!_.isFunction(func)) throw new TypeError;\n    args = slice.call(arguments, 2);\n    return bound = function() {\n      if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments)));\n      ctor.prototype = func.prototype;\n      var self = new ctor;\n      var result = func.apply(self, args.concat(slice.call(arguments)));\n      if (Object(result) === result) return result;\n      return self;\n    };\n  };\n\n  // Bind all of an object's methods to that object. Useful for ensuring that\n  // all callbacks defined on an object belong to it.\n  _.bindAll = function(obj) {\n    var funcs = slice.call(arguments, 1);\n    if (funcs.length == 0) funcs = _.functions(obj);\n    each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); });\n    return obj;\n  };\n\n  // Memoize an expensive function by storing its results.\n  _.memoize = function(func, hasher) {\n    var memo = {};\n    hasher || (hasher = _.identity);\n    return function() {\n      var key = hasher.apply(this, arguments);\n      return _.has(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments));\n    };\n  };\n\n  // Delays a function for the given number of milliseconds, and then calls\n  // it with the arguments supplied.\n  _.delay = function(func, wait) {\n    var args = slice.call(arguments, 2);\n    return setTimeout(function(){ return func.apply(func, args); }, wait);\n  };\n\n  // Defers a function, scheduling it to run after the current call stack has\n  // cleared.\n  _.defer = function(func) {\n    return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1)));\n  };\n\n  // Returns a function, that, when invoked, will only be triggered at most once\n  // during a given window of time.\n  _.throttle = function(func, wait) {\n    var context, args, timeout, throttling, more;\n    var whenDone = _.debounce(function(){ more = throttling = false; }, wait);\n    return function() {\n      context = this; args = arguments;\n      var later = function() {\n        timeout = null;\n        if (more) func.apply(context, args);\n        whenDone();\n      };\n      if (!timeout) timeout = setTimeout(later, wait);\n      if (throttling) {\n        more = true;\n      } else {\n        func.apply(context, args);\n      }\n      whenDone();\n      throttling = true;\n    };\n  };\n\n  // Returns a function, that, as long as it continues to be invoked, will not\n  // be triggered. The function will be called after it stops being called for\n  // N milliseconds.\n  _.debounce = function(func, wait) {\n    var timeout;\n    return function() {\n      var context = this, args = arguments;\n      var later = function() {\n        timeout = null;\n        func.apply(context, args);\n      };\n      clearTimeout(timeout);\n      timeout = setTimeout(later, wait);\n    };\n  };\n\n  // Returns a function that will be executed at most one time, no matter how\n  // often you call it. Useful for lazy initialization.\n  _.once = function(func) {\n    var ran = false, memo;\n    return function() {\n      if (ran) return memo;\n      ran = true;\n      return memo = func.apply(this, arguments);\n    };\n  };\n\n  // Returns the first function passed as an argument to the second,\n  // allowing you to adjust arguments, run code before and after, and\n  // conditionally execute the original function.\n  _.wrap = function(func, wrapper) {\n    return function() {\n      var args = [func].concat(slice.call(arguments, 0));\n      return wrapper.apply(this, args);\n    };\n  };\n\n  // Returns a function that is the composition of a list of functions, each\n  // consuming the return value of the function that follows.\n  _.compose = function() {\n    var funcs = arguments;\n    return function() {\n      var args = arguments;\n      for (var i = funcs.length - 1; i >= 0; i--) {\n        args = [funcs[i].apply(this, args)];\n      }\n      return args[0];\n    };\n  };\n\n  // Returns a function that will only be executed after being called N times.\n  _.after = function(times, func) {\n    if (times <= 0) return func();\n    return function() {\n      if (--times < 1) { return func.apply(this, arguments); }\n    };\n  };\n\n  // Object Functions\n  // ----------------\n\n  // Retrieve the names of an object's properties.\n  // Delegates to **ECMAScript 5**'s native `Object.keys`\n  _.keys = nativeKeys || function(obj) {\n    if (obj !== Object(obj)) throw new TypeError('Invalid object');\n    var keys = [];\n    for (var key in obj) if (_.has(obj, key)) keys[keys.length] = key;\n    return keys;\n  };\n\n  // Retrieve the values of an object's properties.\n  _.values = function(obj) {\n    return _.map(obj, _.identity);\n  };\n\n  // Return a sorted list of the function names available on the object.\n  // Aliased as `methods`\n  _.functions = _.methods = function(obj) {\n    var names = [];\n    for (var key in obj) {\n      if (_.isFunction(obj[key])) names.push(key);\n    }\n    return names.sort();\n  };\n\n  // Extend a given object with all the properties in passed-in object(s).\n  _.extend = function(obj) {\n    each(slice.call(arguments, 1), function(source) {\n      for (var prop in source) {\n        obj[prop] = source[prop];\n      }\n    });\n    return obj;\n  };\n\n  // Fill in a given object with default properties.\n  _.defaults = function(obj) {\n    each(slice.call(arguments, 1), function(source) {\n      for (var prop in source) {\n        if (obj[prop] == null) obj[prop] = source[prop];\n      }\n    });\n    return obj;\n  };\n\n  // Create a (shallow-cloned) duplicate of an object.\n  _.clone = function(obj) {\n    if (!_.isObject(obj)) return obj;\n    return _.isArray(obj) ? obj.slice() : _.extend({}, obj);\n  };\n\n  // Invokes interceptor with the obj, and then returns obj.\n  // The primary purpose of this method is to \"tap into\" a method chain, in\n  // order to perform operations on intermediate results within the chain.\n  _.tap = function(obj, interceptor) {\n    interceptor(obj);\n    return obj;\n  };\n\n  // Internal recursive comparison function.\n  function eq(a, b, stack) {\n    // Identical objects are equal. `0 === -0`, but they aren't identical.\n    // See the Harmony `egal` proposal: http://wiki.ecmascript.org/doku.php?id=harmony:egal.\n    if (a === b) return a !== 0 || 1 / a == 1 / b;\n    // A strict comparison is necessary because `null == undefined`.\n    if (a == null || b == null) return a === b;\n    // Unwrap any wrapped objects.\n    if (a._chain) a = a._wrapped;\n    if (b._chain) b = b._wrapped;\n    // Invoke a custom `isEqual` method if one is provided.\n    if (a.isEqual && _.isFunction(a.isEqual)) return a.isEqual(b);\n    if (b.isEqual && _.isFunction(b.isEqual)) return b.isEqual(a);\n    // Compare `[[Class]]` names.\n    var className = toString.call(a);\n    if (className != toString.call(b)) return false;\n    switch (className) {\n      // Strings, numbers, dates, and booleans are compared by value.\n      case '[object String]':\n        // Primitives and their corresponding object wrappers are equivalent; thus, `\"5\"` is\n        // equivalent to `new String(\"5\")`.\n        return a == String(b);\n      case '[object Number]':\n        // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for\n        // other numeric values.\n        return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b);\n      case '[object Date]':\n      case '[object Boolean]':\n        // Coerce dates and booleans to numeric primitive values. Dates are compared by their\n        // millisecond representations. Note that invalid dates with millisecond representations\n        // of `NaN` are not equivalent.\n        return +a == +b;\n      // RegExps are compared by their source patterns and flags.\n      case '[object RegExp]':\n        return a.source == b.source &&\n               a.global == b.global &&\n               a.multiline == b.multiline &&\n               a.ignoreCase == b.ignoreCase;\n    }\n    if (typeof a != 'object' || typeof b != 'object') return false;\n    // Assume equality for cyclic structures. The algorithm for detecting cyclic\n    // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.\n    var length = stack.length;\n    while (length--) {\n      // Linear search. Performance is inversely proportional to the number of\n      // unique nested structures.\n      if (stack[length] == a) return true;\n    }\n    // Add the first object to the stack of traversed objects.\n    stack.push(a);\n    var size = 0, result = true;\n    // Recursively compare objects and arrays.\n    if (className == '[object Array]') {\n      // Compare array lengths to determine if a deep comparison is necessary.\n      size = a.length;\n      result = size == b.length;\n      if (result) {\n        // Deep compare the contents, ignoring non-numeric properties.\n        while (size--) {\n          // Ensure commutative equality for sparse arrays.\n          if (!(result = size in a == size in b && eq(a[size], b[size], stack))) break;\n        }\n      }\n    } else {\n      // Objects with different constructors are not equivalent.\n      if ('constructor' in a != 'constructor' in b || a.constructor != b.constructor) return false;\n      // Deep compare objects.\n      for (var key in a) {\n        if (_.has(a, key)) {\n          // Count the expected number of properties.\n          size++;\n          // Deep compare each member.\n          if (!(result = _.has(b, key) && eq(a[key], b[key], stack))) break;\n        }\n      }\n      // Ensure that both objects contain the same number of properties.\n      if (result) {\n        for (key in b) {\n          if (_.has(b, key) && !(size--)) break;\n        }\n        result = !size;\n      }\n    }\n    // Remove the first object from the stack of traversed objects.\n    stack.pop();\n    return result;\n  }\n\n  // Perform a deep comparison to check if two objects are equal.\n  _.isEqual = function(a, b) {\n    return eq(a, b, []);\n  };\n\n  // Is a given array, string, or object empty?\n  // An \"empty\" object has no enumerable own-properties.\n  _.isEmpty = function(obj) {\n    if (_.isArray(obj) || _.isString(obj)) return obj.length === 0;\n    for (var key in obj) if (_.has(obj, key)) return false;\n    return true;\n  };\n\n  // Is a given value a DOM element?\n  _.isElement = function(obj) {\n    return !!(obj && obj.nodeType == 1);\n  };\n\n  // Is a given value an array?\n  // Delegates to ECMA5's native Array.isArray\n  _.isArray = nativeIsArray || function(obj) {\n    return toString.call(obj) == '[object Array]';\n  };\n\n  // Is a given variable an object?\n  _.isObject = function(obj) {\n    return obj === Object(obj);\n  };\n\n  // Is a given variable an arguments object?\n  _.isArguments = function(obj) {\n    return toString.call(obj) == '[object Arguments]';\n  };\n  if (!_.isArguments(arguments)) {\n    _.isArguments = function(obj) {\n      return !!(obj && _.has(obj, 'callee'));\n    };\n  }\n\n  // Is a given value a function?\n  _.isFunction = function(obj) {\n    return toString.call(obj) == '[object Function]';\n  };\n\n  // Is a given value a string?\n  _.isString = function(obj) {\n    return toString.call(obj) == '[object String]';\n  };\n\n  // Is a given value a number?\n  _.isNumber = function(obj) {\n    return toString.call(obj) == '[object Number]';\n  };\n\n  // Is the given value `NaN`?\n  _.isNaN = function(obj) {\n    // `NaN` is the only value for which `===` is not reflexive.\n    return obj !== obj;\n  };\n\n  // Is a given value a boolean?\n  _.isBoolean = function(obj) {\n    return obj === true || obj === false || toString.call(obj) == '[object Boolean]';\n  };\n\n  // Is a given value a date?\n  _.isDate = function(obj) {\n    return toString.call(obj) == '[object Date]';\n  };\n\n  // Is the given value a regular expression?\n  _.isRegExp = function(obj) {\n    return toString.call(obj) == '[object RegExp]';\n  };\n\n  // Is a given value equal to null?\n  _.isNull = function(obj) {\n    return obj === null;\n  };\n\n  // Is a given variable undefined?\n  _.isUndefined = function(obj) {\n    return obj === void 0;\n  };\n\n  // Has own property?\n  _.has = function(obj, key) {\n    return hasOwnProperty.call(obj, key);\n  };\n\n  // Utility Functions\n  // -----------------\n\n  // Run Underscore.js in *noConflict* mode, returning the `_` variable to its\n  // previous owner. Returns a reference to the Underscore object.\n  _.noConflict = function() {\n    root._ = previousUnderscore;\n    return this;\n  };\n\n  // Keep the identity function around for default iterators.\n  _.identity = function(value) {\n    return value;\n  };\n\n  // Run a function **n** times.\n  _.times = function (n, iterator, context) {\n    for (var i = 0; i < n; i++) iterator.call(context, i);\n  };\n\n  // Escape a string for HTML interpolation.\n  _.escape = function(string) {\n    return (''+string).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;').replace(/'/g, '&#x27;').replace(/\\//g,'&#x2F;');\n  };\n\n  // Add your own custom functions to the Underscore object, ensuring that\n  // they're correctly added to the OOP wrapper as well.\n  _.mixin = function(obj) {\n    each(_.functions(obj), function(name){\n      addToWrapper(name, _[name] = obj[name]);\n    });\n  };\n\n  // Generate a unique integer id (unique within the entire client session).\n  // Useful for temporary DOM ids.\n  var idCounter = 0;\n  _.uniqueId = function(prefix) {\n    var id = idCounter++;\n    return prefix ? prefix + id : id;\n  };\n\n  // By default, Underscore uses ERB-style template delimiters, change the\n  // following template settings to use alternative delimiters.\n  _.templateSettings = {\n    evaluate    : /<%([\\s\\S]+?)%>/g,\n    interpolate : /<%=([\\s\\S]+?)%>/g,\n    escape      : /<%-([\\s\\S]+?)%>/g\n  };\n\n  // When customizing `templateSettings`, if you don't want to define an\n  // interpolation, evaluation or escaping regex, we need one that is\n  // guaranteed not to match.\n  var noMatch = /.^/;\n\n  // Within an interpolation, evaluation, or escaping, remove HTML escaping\n  // that had been previously added.\n  var unescape = function(code) {\n    return code.replace(/\\\\\\\\/g, '\\\\').replace(/\\\\'/g, \"'\");\n  };\n\n  // JavaScript micro-templating, similar to John Resig's implementation.\n  // Underscore templating handles arbitrary delimiters, preserves whitespace,\n  // and correctly escapes quotes within interpolated code.\n  _.template = function(str, data) {\n    var c  = _.templateSettings;\n    var tmpl = 'var __p=[],print=function(){__p.push.apply(__p,arguments);};' +\n      'with(obj||{}){__p.push(\\'' +\n      str.replace(/\\\\/g, '\\\\\\\\')\n         .replace(/'/g, \"\\\\'\")\n         .replace(c.escape || noMatch, function(match, code) {\n           return \"',_.escape(\" + unescape(code) + \"),'\";\n         })\n         .replace(c.interpolate || noMatch, function(match, code) {\n           return \"',\" + unescape(code) + \",'\";\n         })\n         .replace(c.evaluate || noMatch, function(match, code) {\n           return \"');\" + unescape(code).replace(/[\\r\\n\\t]/g, ' ') + \";__p.push('\";\n         })\n         .replace(/\\r/g, '\\\\r')\n         .replace(/\\n/g, '\\\\n')\n         .replace(/\\t/g, '\\\\t')\n         + \"');}return __p.join('');\";\n    var func = new Function('obj', '_', tmpl);\n    if (data) return func(data, _);\n    return function(data) {\n      return func.call(this, data, _);\n    };\n  };\n\n  // Add a \"chain\" function, which will delegate to the wrapper.\n  _.chain = function(obj) {\n    return _(obj).chain();\n  };\n\n  // The OOP Wrapper\n  // ---------------\n\n  // If Underscore is called as a function, it returns a wrapped object that\n  // can be used OO-style. This wrapper holds altered versions of all the\n  // underscore functions. Wrapped objects may be chained.\n  var wrapper = function(obj) { this._wrapped = obj; };\n\n  // Expose `wrapper.prototype` as `_.prototype`\n  _.prototype = wrapper.prototype;\n\n  // Helper function to continue chaining intermediate results.\n  var result = function(obj, chain) {\n    return chain ? _(obj).chain() : obj;\n  };\n\n  // A method to easily add functions to the OOP wrapper.\n  var addToWrapper = function(name, func) {\n    wrapper.prototype[name] = function() {\n      var args = slice.call(arguments);\n      unshift.call(args, this._wrapped);\n      return result(func.apply(_, args), this._chain);\n    };\n  };\n\n  // Add all of the Underscore functions to the wrapper object.\n  _.mixin(_);\n\n  // Add all mutator Array functions to the wrapper.\n  each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {\n    var method = ArrayProto[name];\n    wrapper.prototype[name] = function() {\n      var wrapped = this._wrapped;\n      method.apply(wrapped, arguments);\n      var length = wrapped.length;\n      if ((name == 'shift' || name == 'splice') && length === 0) delete wrapped[0];\n      return result(wrapped, this._chain);\n    };\n  });\n\n  // Add all accessor Array functions to the wrapper.\n  each(['concat', 'join', 'slice'], function(name) {\n    var method = ArrayProto[name];\n    wrapper.prototype[name] = function() {\n      return result(method.apply(this._wrapped, arguments), this._chain);\n    };\n  });\n\n  // Start chaining a wrapped Underscore object.\n  wrapper.prototype.chain = function() {\n    this._chain = true;\n    return this;\n  };\n\n  // Extracts the result from a wrapped and chained object.\n  wrapper.prototype.value = function() {\n    return this._wrapped;\n  };\n\n}).call(this);\n"
  },
  {
    "path": "docs/_static/underscore.js",
    "content": "// Underscore.js 1.3.1\n// (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc.\n// Underscore is freely distributable under the MIT license.\n// Portions of Underscore are inspired or borrowed from Prototype,\n// Oliver Steele's Functional, and John Resig's Micro-Templating.\n// For all details and documentation:\n// http://documentcloud.github.com/underscore\n(function(){function q(a,c,d){if(a===c)return a!==0||1/a==1/c;if(a==null||c==null)return a===c;if(a._chain)a=a._wrapped;if(c._chain)c=c._wrapped;if(a.isEqual&&b.isFunction(a.isEqual))return a.isEqual(c);if(c.isEqual&&b.isFunction(c.isEqual))return c.isEqual(a);var e=l.call(a);if(e!=l.call(c))return false;switch(e){case \"[object String]\":return a==String(c);case \"[object Number]\":return a!=+a?c!=+c:a==0?1/a==1/c:a==+c;case \"[object Date]\":case \"[object Boolean]\":return+a==+c;case \"[object RegExp]\":return a.source==\nc.source&&a.global==c.global&&a.multiline==c.multiline&&a.ignoreCase==c.ignoreCase}if(typeof a!=\"object\"||typeof c!=\"object\")return false;for(var f=d.length;f--;)if(d[f]==a)return true;d.push(a);var f=0,g=true;if(e==\"[object Array]\"){if(f=a.length,g=f==c.length)for(;f--;)if(!(g=f in a==f in c&&q(a[f],c[f],d)))break}else{if(\"constructor\"in a!=\"constructor\"in c||a.constructor!=c.constructor)return false;for(var h in a)if(b.has(a,h)&&(f++,!(g=b.has(c,h)&&q(a[h],c[h],d))))break;if(g){for(h in c)if(b.has(c,\nh)&&!f--)break;g=!f}}d.pop();return g}var r=this,G=r._,n={},k=Array.prototype,o=Object.prototype,i=k.slice,H=k.unshift,l=o.toString,I=o.hasOwnProperty,w=k.forEach,x=k.map,y=k.reduce,z=k.reduceRight,A=k.filter,B=k.every,C=k.some,p=k.indexOf,D=k.lastIndexOf,o=Array.isArray,J=Object.keys,s=Function.prototype.bind,b=function(a){return new m(a)};if(typeof exports!==\"undefined\"){if(typeof module!==\"undefined\"&&module.exports)exports=module.exports=b;exports._=b}else r._=b;b.VERSION=\"1.3.1\";var j=b.each=\nb.forEach=function(a,c,d){if(a!=null)if(w&&a.forEach===w)a.forEach(c,d);else if(a.length===+a.length)for(var e=0,f=a.length;e<f;e++){if(e in a&&c.call(d,a[e],e,a)===n)break}else for(e in a)if(b.has(a,e)&&c.call(d,a[e],e,a)===n)break};b.map=b.collect=function(a,c,b){var e=[];if(a==null)return e;if(x&&a.map===x)return a.map(c,b);j(a,function(a,g,h){e[e.length]=c.call(b,a,g,h)});if(a.length===+a.length)e.length=a.length;return e};b.reduce=b.foldl=b.inject=function(a,c,d,e){var f=arguments.length>2;a==\nnull&&(a=[]);if(y&&a.reduce===y)return e&&(c=b.bind(c,e)),f?a.reduce(c,d):a.reduce(c);j(a,function(a,b,i){f?d=c.call(e,d,a,b,i):(d=a,f=true)});if(!f)throw new TypeError(\"Reduce of empty array with no initial value\");return d};b.reduceRight=b.foldr=function(a,c,d,e){var f=arguments.length>2;a==null&&(a=[]);if(z&&a.reduceRight===z)return e&&(c=b.bind(c,e)),f?a.reduceRight(c,d):a.reduceRight(c);var g=b.toArray(a).reverse();e&&!f&&(c=b.bind(c,e));return f?b.reduce(g,c,d,e):b.reduce(g,c)};b.find=b.detect=\nfunction(a,c,b){var e;E(a,function(a,g,h){if(c.call(b,a,g,h))return e=a,true});return e};b.filter=b.select=function(a,c,b){var e=[];if(a==null)return e;if(A&&a.filter===A)return a.filter(c,b);j(a,function(a,g,h){c.call(b,a,g,h)&&(e[e.length]=a)});return e};b.reject=function(a,c,b){var e=[];if(a==null)return e;j(a,function(a,g,h){c.call(b,a,g,h)||(e[e.length]=a)});return e};b.every=b.all=function(a,c,b){var e=true;if(a==null)return e;if(B&&a.every===B)return a.every(c,b);j(a,function(a,g,h){if(!(e=\ne&&c.call(b,a,g,h)))return n});return e};var E=b.some=b.any=function(a,c,d){c||(c=b.identity);var e=false;if(a==null)return e;if(C&&a.some===C)return a.some(c,d);j(a,function(a,b,h){if(e||(e=c.call(d,a,b,h)))return n});return!!e};b.include=b.contains=function(a,c){var b=false;if(a==null)return b;return p&&a.indexOf===p?a.indexOf(c)!=-1:b=E(a,function(a){return a===c})};b.invoke=function(a,c){var d=i.call(arguments,2);return b.map(a,function(a){return(b.isFunction(c)?c||a:a[c]).apply(a,d)})};b.pluck=\nfunction(a,c){return b.map(a,function(a){return a[c]})};b.max=function(a,c,d){if(!c&&b.isArray(a))return Math.max.apply(Math,a);if(!c&&b.isEmpty(a))return-Infinity;var e={computed:-Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;b>=e.computed&&(e={value:a,computed:b})});return e.value};b.min=function(a,c,d){if(!c&&b.isArray(a))return Math.min.apply(Math,a);if(!c&&b.isEmpty(a))return Infinity;var e={computed:Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;b<e.computed&&(e={value:a,computed:b})});\nreturn e.value};b.shuffle=function(a){var b=[],d;j(a,function(a,f){f==0?b[0]=a:(d=Math.floor(Math.random()*(f+1)),b[f]=b[d],b[d]=a)});return b};b.sortBy=function(a,c,d){return b.pluck(b.map(a,function(a,b,g){return{value:a,criteria:c.call(d,a,b,g)}}).sort(function(a,b){var c=a.criteria,d=b.criteria;return c<d?-1:c>d?1:0}),\"value\")};b.groupBy=function(a,c){var d={},e=b.isFunction(c)?c:function(a){return a[c]};j(a,function(a,b){var c=e(a,b);(d[c]||(d[c]=[])).push(a)});return d};b.sortedIndex=function(a,\nc,d){d||(d=b.identity);for(var e=0,f=a.length;e<f;){var g=e+f>>1;d(a[g])<d(c)?e=g+1:f=g}return e};b.toArray=function(a){return!a?[]:a.toArray?a.toArray():b.isArray(a)?i.call(a):b.isArguments(a)?i.call(a):b.values(a)};b.size=function(a){return b.toArray(a).length};b.first=b.head=function(a,b,d){return b!=null&&!d?i.call(a,0,b):a[0]};b.initial=function(a,b,d){return i.call(a,0,a.length-(b==null||d?1:b))};b.last=function(a,b,d){return b!=null&&!d?i.call(a,Math.max(a.length-b,0)):a[a.length-1]};b.rest=\nb.tail=function(a,b,d){return i.call(a,b==null||d?1:b)};b.compact=function(a){return b.filter(a,function(a){return!!a})};b.flatten=function(a,c){return b.reduce(a,function(a,e){if(b.isArray(e))return a.concat(c?e:b.flatten(e));a[a.length]=e;return a},[])};b.without=function(a){return b.difference(a,i.call(arguments,1))};b.uniq=b.unique=function(a,c,d){var d=d?b.map(a,d):a,e=[];b.reduce(d,function(d,g,h){if(0==h||(c===true?b.last(d)!=g:!b.include(d,g)))d[d.length]=g,e[e.length]=a[h];return d},[]);\nreturn e};b.union=function(){return b.uniq(b.flatten(arguments,true))};b.intersection=b.intersect=function(a){var c=i.call(arguments,1);return b.filter(b.uniq(a),function(a){return b.every(c,function(c){return b.indexOf(c,a)>=0})})};b.difference=function(a){var c=b.flatten(i.call(arguments,1));return b.filter(a,function(a){return!b.include(c,a)})};b.zip=function(){for(var a=i.call(arguments),c=b.max(b.pluck(a,\"length\")),d=Array(c),e=0;e<c;e++)d[e]=b.pluck(a,\"\"+e);return d};b.indexOf=function(a,c,\nd){if(a==null)return-1;var e;if(d)return d=b.sortedIndex(a,c),a[d]===c?d:-1;if(p&&a.indexOf===p)return a.indexOf(c);for(d=0,e=a.length;d<e;d++)if(d in a&&a[d]===c)return d;return-1};b.lastIndexOf=function(a,b){if(a==null)return-1;if(D&&a.lastIndexOf===D)return a.lastIndexOf(b);for(var d=a.length;d--;)if(d in a&&a[d]===b)return d;return-1};b.range=function(a,b,d){arguments.length<=1&&(b=a||0,a=0);for(var d=arguments[2]||1,e=Math.max(Math.ceil((b-a)/d),0),f=0,g=Array(e);f<e;)g[f++]=a,a+=d;return g};\nvar F=function(){};b.bind=function(a,c){var d,e;if(a.bind===s&&s)return s.apply(a,i.call(arguments,1));if(!b.isFunction(a))throw new TypeError;e=i.call(arguments,2);return d=function(){if(!(this instanceof d))return a.apply(c,e.concat(i.call(arguments)));F.prototype=a.prototype;var b=new F,g=a.apply(b,e.concat(i.call(arguments)));return Object(g)===g?g:b}};b.bindAll=function(a){var c=i.call(arguments,1);c.length==0&&(c=b.functions(a));j(c,function(c){a[c]=b.bind(a[c],a)});return a};b.memoize=function(a,\nc){var d={};c||(c=b.identity);return function(){var e=c.apply(this,arguments);return b.has(d,e)?d[e]:d[e]=a.apply(this,arguments)}};b.delay=function(a,b){var d=i.call(arguments,2);return setTimeout(function(){return a.apply(a,d)},b)};b.defer=function(a){return b.delay.apply(b,[a,1].concat(i.call(arguments,1)))};b.throttle=function(a,c){var d,e,f,g,h,i=b.debounce(function(){h=g=false},c);return function(){d=this;e=arguments;var b;f||(f=setTimeout(function(){f=null;h&&a.apply(d,e);i()},c));g?h=true:\na.apply(d,e);i();g=true}};b.debounce=function(a,b){var d;return function(){var e=this,f=arguments;clearTimeout(d);d=setTimeout(function(){d=null;a.apply(e,f)},b)}};b.once=function(a){var b=false,d;return function(){if(b)return d;b=true;return d=a.apply(this,arguments)}};b.wrap=function(a,b){return function(){var d=[a].concat(i.call(arguments,0));return b.apply(this,d)}};b.compose=function(){var a=arguments;return function(){for(var b=arguments,d=a.length-1;d>=0;d--)b=[a[d].apply(this,b)];return b[0]}};\nb.after=function(a,b){return a<=0?b():function(){if(--a<1)return b.apply(this,arguments)}};b.keys=J||function(a){if(a!==Object(a))throw new TypeError(\"Invalid object\");var c=[],d;for(d in a)b.has(a,d)&&(c[c.length]=d);return c};b.values=function(a){return b.map(a,b.identity)};b.functions=b.methods=function(a){var c=[],d;for(d in a)b.isFunction(a[d])&&c.push(d);return c.sort()};b.extend=function(a){j(i.call(arguments,1),function(b){for(var d in b)a[d]=b[d]});return a};b.defaults=function(a){j(i.call(arguments,\n1),function(b){for(var d in b)a[d]==null&&(a[d]=b[d])});return a};b.clone=function(a){return!b.isObject(a)?a:b.isArray(a)?a.slice():b.extend({},a)};b.tap=function(a,b){b(a);return a};b.isEqual=function(a,b){return q(a,b,[])};b.isEmpty=function(a){if(b.isArray(a)||b.isString(a))return a.length===0;for(var c in a)if(b.has(a,c))return false;return true};b.isElement=function(a){return!!(a&&a.nodeType==1)};b.isArray=o||function(a){return l.call(a)==\"[object Array]\"};b.isObject=function(a){return a===Object(a)};\nb.isArguments=function(a){return l.call(a)==\"[object Arguments]\"};if(!b.isArguments(arguments))b.isArguments=function(a){return!(!a||!b.has(a,\"callee\"))};b.isFunction=function(a){return l.call(a)==\"[object Function]\"};b.isString=function(a){return l.call(a)==\"[object String]\"};b.isNumber=function(a){return l.call(a)==\"[object Number]\"};b.isNaN=function(a){return a!==a};b.isBoolean=function(a){return a===true||a===false||l.call(a)==\"[object Boolean]\"};b.isDate=function(a){return l.call(a)==\"[object Date]\"};\nb.isRegExp=function(a){return l.call(a)==\"[object RegExp]\"};b.isNull=function(a){return a===null};b.isUndefined=function(a){return a===void 0};b.has=function(a,b){return I.call(a,b)};b.noConflict=function(){r._=G;return this};b.identity=function(a){return a};b.times=function(a,b,d){for(var e=0;e<a;e++)b.call(d,e)};b.escape=function(a){return(\"\"+a).replace(/&/g,\"&amp;\").replace(/</g,\"&lt;\").replace(/>/g,\"&gt;\").replace(/\"/g,\"&quot;\").replace(/'/g,\"&#x27;\").replace(/\\//g,\"&#x2F;\")};b.mixin=function(a){j(b.functions(a),\nfunction(c){K(c,b[c]=a[c])})};var L=0;b.uniqueId=function(a){var b=L++;return a?a+b:b};b.templateSettings={evaluate:/<%([\\s\\S]+?)%>/g,interpolate:/<%=([\\s\\S]+?)%>/g,escape:/<%-([\\s\\S]+?)%>/g};var t=/.^/,u=function(a){return a.replace(/\\\\\\\\/g,\"\\\\\").replace(/\\\\'/g,\"'\")};b.template=function(a,c){var d=b.templateSettings,d=\"var __p=[],print=function(){__p.push.apply(__p,arguments);};with(obj||{}){__p.push('\"+a.replace(/\\\\/g,\"\\\\\\\\\").replace(/'/g,\"\\\\'\").replace(d.escape||t,function(a,b){return\"',_.escape(\"+\nu(b)+\"),'\"}).replace(d.interpolate||t,function(a,b){return\"',\"+u(b)+\",'\"}).replace(d.evaluate||t,function(a,b){return\"');\"+u(b).replace(/[\\r\\n\\t]/g,\" \")+\";__p.push('\"}).replace(/\\r/g,\"\\\\r\").replace(/\\n/g,\"\\\\n\").replace(/\\t/g,\"\\\\t\")+\"');}return __p.join('');\",e=new Function(\"obj\",\"_\",d);return c?e(c,b):function(a){return e.call(this,a,b)}};b.chain=function(a){return b(a).chain()};var m=function(a){this._wrapped=a};b.prototype=m.prototype;var v=function(a,c){return c?b(a).chain():a},K=function(a,c){m.prototype[a]=\nfunction(){var a=i.call(arguments);H.call(a,this._wrapped);return v(c.apply(b,a),this._chain)}};b.mixin(b);j(\"pop,push,reverse,shift,sort,splice,unshift\".split(\",\"),function(a){var b=k[a];m.prototype[a]=function(){var d=this._wrapped;b.apply(d,arguments);var e=d.length;(a==\"shift\"||a==\"splice\")&&e===0&&delete d[0];return v(d,this._chain)}});j([\"concat\",\"join\",\"slice\"],function(a){var b=k[a];m.prototype[a]=function(){return v(b.apply(this._wrapped,arguments),this._chain)}});m.prototype.chain=function(){this._chain=\ntrue;return this};m.prototype.value=function(){return this._wrapped}}).call(this);\n"
  },
  {
    "path": "docs/_static/websupport.js",
    "content": "/*\n * websupport.js\n * ~~~~~~~~~~~~~\n *\n * sphinx.websupport utilities for all documentation.\n *\n * :copyright: Copyright 2007-2019 by the Sphinx team, see AUTHORS.\n * :license: BSD, see LICENSE for details.\n *\n */\n\n(function($) {\n  $.fn.autogrow = function() {\n    return this.each(function() {\n    var textarea = this;\n\n    $.fn.autogrow.resize(textarea);\n\n    $(textarea)\n      .focus(function() {\n        textarea.interval = setInterval(function() {\n          $.fn.autogrow.resize(textarea);\n        }, 500);\n      })\n      .blur(function() {\n        clearInterval(textarea.interval);\n      });\n    });\n  };\n\n  $.fn.autogrow.resize = function(textarea) {\n    var lineHeight = parseInt($(textarea).css('line-height'), 10);\n    var lines = textarea.value.split('\\n');\n    var columns = textarea.cols;\n    var lineCount = 0;\n    $.each(lines, function() {\n      lineCount += Math.ceil(this.length / columns) || 1;\n    });\n    var height = lineHeight * (lineCount + 1);\n    $(textarea).css('height', height);\n  };\n})(jQuery);\n\n(function($) {\n  var comp, by;\n\n  function init() {\n    initEvents();\n    initComparator();\n  }\n\n  function initEvents() {\n    $(document).on(\"click\", 'a.comment-close', function(event) {\n      event.preventDefault();\n      hide($(this).attr('id').substring(2));\n    });\n    $(document).on(\"click\", 'a.vote', function(event) {\n      event.preventDefault();\n      handleVote($(this));\n    });\n    $(document).on(\"click\", 'a.reply', function(event) {\n      event.preventDefault();\n      openReply($(this).attr('id').substring(2));\n    });\n    $(document).on(\"click\", 'a.close-reply', function(event) {\n      event.preventDefault();\n      closeReply($(this).attr('id').substring(2));\n    });\n    $(document).on(\"click\", 'a.sort-option', function(event) {\n      event.preventDefault();\n      handleReSort($(this));\n    });\n    $(document).on(\"click\", 'a.show-proposal', function(event) {\n      event.preventDefault();\n      showProposal($(this).attr('id').substring(2));\n    });\n    $(document).on(\"click\", 'a.hide-proposal', function(event) {\n      event.preventDefault();\n      hideProposal($(this).attr('id').substring(2));\n    });\n    $(document).on(\"click\", 'a.show-propose-change', function(event) {\n      event.preventDefault();\n      showProposeChange($(this).attr('id').substring(2));\n    });\n    $(document).on(\"click\", 'a.hide-propose-change', function(event) {\n      event.preventDefault();\n      hideProposeChange($(this).attr('id').substring(2));\n    });\n    $(document).on(\"click\", 'a.accept-comment', function(event) {\n      event.preventDefault();\n      acceptComment($(this).attr('id').substring(2));\n    });\n    $(document).on(\"click\", 'a.delete-comment', function(event) {\n      event.preventDefault();\n      deleteComment($(this).attr('id').substring(2));\n    });\n    $(document).on(\"click\", 'a.comment-markup', function(event) {\n      event.preventDefault();\n      toggleCommentMarkupBox($(this).attr('id').substring(2));\n    });\n  }\n\n  /**\n   * Set comp, which is a comparator function used for sorting and\n   * inserting comments into the list.\n   */\n  function setComparator() {\n    // If the first three letters are \"asc\", sort in ascending order\n    // and remove the prefix.\n    if (by.substring(0,3) == 'asc') {\n      var i = by.substring(3);\n      comp = function(a, b) { return a[i] - b[i]; };\n    } else {\n      // Otherwise sort in descending order.\n      comp = function(a, b) { return b[by] - a[by]; };\n    }\n\n    // Reset link styles and format the selected sort option.\n    $('a.sel').attr('href', '#').removeClass('sel');\n    $('a.by' + by).removeAttr('href').addClass('sel');\n  }\n\n  /**\n   * Create a comp function. If the user has preferences stored in\n   * the sortBy cookie, use those, otherwise use the default.\n   */\n  function initComparator() {\n    by = 'rating'; // Default to sort by rating.\n    // If the sortBy cookie is set, use that instead.\n    if (document.cookie.length > 0) {\n      var start = document.cookie.indexOf('sortBy=');\n      if (start != -1) {\n        start = start + 7;\n        var end = document.cookie.indexOf(\";\", start);\n        if (end == -1) {\n          end = document.cookie.length;\n          by = unescape(document.cookie.substring(start, end));\n        }\n      }\n    }\n    setComparator();\n  }\n\n  /**\n   * Show a comment div.\n   */\n  function show(id) {\n    $('#ao' + id).hide();\n    $('#ah' + id).show();\n    var context = $.extend({id: id}, opts);\n    var popup = $(renderTemplate(popupTemplate, context)).hide();\n    popup.find('textarea[name=\"proposal\"]').hide();\n    popup.find('a.by' + by).addClass('sel');\n    var form = popup.find('#cf' + id);\n    form.submit(function(event) {\n      event.preventDefault();\n      addComment(form);\n    });\n    $('#s' + id).after(popup);\n    popup.slideDown('fast', function() {\n      getComments(id);\n    });\n  }\n\n  /**\n   * Hide a comment div.\n   */\n  function hide(id) {\n    $('#ah' + id).hide();\n    $('#ao' + id).show();\n    var div = $('#sc' + id);\n    div.slideUp('fast', function() {\n      div.remove();\n    });\n  }\n\n  /**\n   * Perform an ajax request to get comments for a node\n   * and insert the comments into the comments tree.\n   */\n  function getComments(id) {\n    $.ajax({\n     type: 'GET',\n     url: opts.getCommentsURL,\n     data: {node: id},\n     success: function(data, textStatus, request) {\n       var ul = $('#cl' + id);\n       var speed = 100;\n       $('#cf' + id)\n         .find('textarea[name=\"proposal\"]')\n         .data('source', data.source);\n\n       if (data.comments.length === 0) {\n         ul.html('<li>No comments yet.</li>');\n         ul.data('empty', true);\n       } else {\n         // If there are comments, sort them and put them in the list.\n         var comments = sortComments(data.comments);\n         speed = data.comments.length * 100;\n         appendComments(comments, ul);\n         ul.data('empty', false);\n       }\n       $('#cn' + id).slideUp(speed + 200);\n       ul.slideDown(speed);\n     },\n     error: function(request, textStatus, error) {\n       showError('Oops, there was a problem retrieving the comments.');\n     },\n     dataType: 'json'\n    });\n  }\n\n  /**\n   * Add a comment via ajax and insert the comment into the comment tree.\n   */\n  function addComment(form) {\n    var node_id = form.find('input[name=\"node\"]').val();\n    var parent_id = form.find('input[name=\"parent\"]').val();\n    var text = form.find('textarea[name=\"comment\"]').val();\n    var proposal = form.find('textarea[name=\"proposal\"]').val();\n\n    if (text == '') {\n      showError('Please enter a comment.');\n      return;\n    }\n\n    // Disable the form that is being submitted.\n    form.find('textarea,input').attr('disabled', 'disabled');\n\n    // Send the comment to the server.\n    $.ajax({\n      type: \"POST\",\n      url: opts.addCommentURL,\n      dataType: 'json',\n      data: {\n        node: node_id,\n        parent: parent_id,\n        text: text,\n        proposal: proposal\n      },\n      success: function(data, textStatus, error) {\n        // Reset the form.\n        if (node_id) {\n          hideProposeChange(node_id);\n        }\n        form.find('textarea')\n          .val('')\n          .add(form.find('input'))\n          .removeAttr('disabled');\n\tvar ul = $('#cl' + (node_id || parent_id));\n        if (ul.data('empty')) {\n          $(ul).empty();\n          ul.data('empty', false);\n        }\n        insertComment(data.comment);\n        var ao = $('#ao' + node_id);\n        ao.find('img').attr({'src': opts.commentBrightImage});\n        if (node_id) {\n          // if this was a \"root\" comment, remove the commenting box\n          // (the user can get it back by reopening the comment popup)\n          $('#ca' + node_id).slideUp();\n        }\n      },\n      error: function(request, textStatus, error) {\n        form.find('textarea,input').removeAttr('disabled');\n        showError('Oops, there was a problem adding the comment.');\n      }\n    });\n  }\n\n  /**\n   * Recursively append comments to the main comment list and children\n   * lists, creating the comment tree.\n   */\n  function appendComments(comments, ul) {\n    $.each(comments, function() {\n      var div = createCommentDiv(this);\n      ul.append($(document.createElement('li')).html(div));\n      appendComments(this.children, div.find('ul.comment-children'));\n      // To avoid stagnating data, don't store the comments children in data.\n      this.children = null;\n      div.data('comment', this);\n    });\n  }\n\n  /**\n   * After adding a new comment, it must be inserted in the correct\n   * location in the comment tree.\n   */\n  function insertComment(comment) {\n    var div = createCommentDiv(comment);\n\n    // To avoid stagnating data, don't store the comments children in data.\n    comment.children = null;\n    div.data('comment', comment);\n\n    var ul = $('#cl' + (comment.node || comment.parent));\n    var siblings = getChildren(ul);\n\n    var li = $(document.createElement('li'));\n    li.hide();\n\n    // Determine where in the parents children list to insert this comment.\n    for(var i=0; i < siblings.length; i++) {\n      if (comp(comment, siblings[i]) <= 0) {\n        $('#cd' + siblings[i].id)\n          .parent()\n          .before(li.html(div));\n        li.slideDown('fast');\n        return;\n      }\n    }\n\n    // If we get here, this comment rates lower than all the others,\n    // or it is the only comment in the list.\n    ul.append(li.html(div));\n    li.slideDown('fast');\n  }\n\n  function acceptComment(id) {\n    $.ajax({\n      type: 'POST',\n      url: opts.acceptCommentURL,\n      data: {id: id},\n      success: function(data, textStatus, request) {\n        $('#cm' + id).fadeOut('fast');\n        $('#cd' + id).removeClass('moderate');\n      },\n      error: function(request, textStatus, error) {\n        showError('Oops, there was a problem accepting the comment.');\n      }\n    });\n  }\n\n  function deleteComment(id) {\n    $.ajax({\n      type: 'POST',\n      url: opts.deleteCommentURL,\n      data: {id: id},\n      success: function(data, textStatus, request) {\n        var div = $('#cd' + id);\n        if (data == 'delete') {\n          // Moderator mode: remove the comment and all children immediately\n          div.slideUp('fast', function() {\n            div.remove();\n          });\n          return;\n        }\n        // User mode: only mark the comment as deleted\n        div\n          .find('span.user-id:first')\n          .text('[deleted]').end()\n          .find('div.comment-text:first')\n          .text('[deleted]').end()\n          .find('#cm' + id + ', #dc' + id + ', #ac' + id + ', #rc' + id +\n                ', #sp' + id + ', #hp' + id + ', #cr' + id + ', #rl' + id)\n          .remove();\n        var comment = div.data('comment');\n        comment.username = '[deleted]';\n        comment.text = '[deleted]';\n        div.data('comment', comment);\n      },\n      error: function(request, textStatus, error) {\n        showError('Oops, there was a problem deleting the comment.');\n      }\n    });\n  }\n\n  function showProposal(id) {\n    $('#sp' + id).hide();\n    $('#hp' + id).show();\n    $('#pr' + id).slideDown('fast');\n  }\n\n  function hideProposal(id) {\n    $('#hp' + id).hide();\n    $('#sp' + id).show();\n    $('#pr' + id).slideUp('fast');\n  }\n\n  function showProposeChange(id) {\n    $('#pc' + id).hide();\n    $('#hc' + id).show();\n    var textarea = $('#pt' + id);\n    textarea.val(textarea.data('source'));\n    $.fn.autogrow.resize(textarea[0]);\n    textarea.slideDown('fast');\n  }\n\n  function hideProposeChange(id) {\n    $('#hc' + id).hide();\n    $('#pc' + id).show();\n    var textarea = $('#pt' + id);\n    textarea.val('').removeAttr('disabled');\n    textarea.slideUp('fast');\n  }\n\n  function toggleCommentMarkupBox(id) {\n    $('#mb' + id).toggle();\n  }\n\n  /** Handle when the user clicks on a sort by link. */\n  function handleReSort(link) {\n    var classes = link.attr('class').split(/\\s+/);\n    for (var i=0; i<classes.length; i++) {\n      if (classes[i] != 'sort-option') {\n\tby = classes[i].substring(2);\n      }\n    }\n    setComparator();\n    // Save/update the sortBy cookie.\n    var expiration = new Date();\n    expiration.setDate(expiration.getDate() + 365);\n    document.cookie= 'sortBy=' + escape(by) +\n                     ';expires=' + expiration.toUTCString();\n    $('ul.comment-ul').each(function(index, ul) {\n      var comments = getChildren($(ul), true);\n      comments = sortComments(comments);\n      appendComments(comments, $(ul).empty());\n    });\n  }\n\n  /**\n   * Function to process a vote when a user clicks an arrow.\n   */\n  function handleVote(link) {\n    if (!opts.voting) {\n      showError(\"You'll need to login to vote.\");\n      return;\n    }\n\n    var id = link.attr('id');\n    if (!id) {\n      // Didn't click on one of the voting arrows.\n      return;\n    }\n    // If it is an unvote, the new vote value is 0,\n    // Otherwise it's 1 for an upvote, or -1 for a downvote.\n    var value = 0;\n    if (id.charAt(1) != 'u') {\n      value = id.charAt(0) == 'u' ? 1 : -1;\n    }\n    // The data to be sent to the server.\n    var d = {\n      comment_id: id.substring(2),\n      value: value\n    };\n\n    // Swap the vote and unvote links.\n    link.hide();\n    $('#' + id.charAt(0) + (id.charAt(1) == 'u' ? 'v' : 'u') + d.comment_id)\n      .show();\n\n    // The div the comment is displayed in.\n    var div = $('div#cd' + d.comment_id);\n    var data = div.data('comment');\n\n    // If this is not an unvote, and the other vote arrow has\n    // already been pressed, unpress it.\n    if ((d.value !== 0) && (data.vote === d.value * -1)) {\n      $('#' + (d.value == 1 ? 'd' : 'u') + 'u' + d.comment_id).hide();\n      $('#' + (d.value == 1 ? 'd' : 'u') + 'v' + d.comment_id).show();\n    }\n\n    // Update the comments rating in the local data.\n    data.rating += (data.vote === 0) ? d.value : (d.value - data.vote);\n    data.vote = d.value;\n    div.data('comment', data);\n\n    // Change the rating text.\n    div.find('.rating:first')\n      .text(data.rating + ' point' + (data.rating == 1 ? '' : 's'));\n\n    // Send the vote information to the server.\n    $.ajax({\n      type: \"POST\",\n      url: opts.processVoteURL,\n      data: d,\n      error: function(request, textStatus, error) {\n        showError('Oops, there was a problem casting that vote.');\n      }\n    });\n  }\n\n  /**\n   * Open a reply form used to reply to an existing comment.\n   */\n  function openReply(id) {\n    // Swap out the reply link for the hide link\n    $('#rl' + id).hide();\n    $('#cr' + id).show();\n\n    // Add the reply li to the children ul.\n    var div = $(renderTemplate(replyTemplate, {id: id})).hide();\n    $('#cl' + id)\n      .prepend(div)\n      // Setup the submit handler for the reply form.\n      .find('#rf' + id)\n      .submit(function(event) {\n        event.preventDefault();\n        addComment($('#rf' + id));\n        closeReply(id);\n      })\n      .find('input[type=button]')\n      .click(function() {\n        closeReply(id);\n      });\n    div.slideDown('fast', function() {\n      $('#rf' + id).find('textarea').focus();\n    });\n  }\n\n  /**\n   * Close the reply form opened with openReply.\n   */\n  function closeReply(id) {\n    // Remove the reply div from the DOM.\n    $('#rd' + id).slideUp('fast', function() {\n      $(this).remove();\n    });\n\n    // Swap out the hide link for the reply link\n    $('#cr' + id).hide();\n    $('#rl' + id).show();\n  }\n\n  /**\n   * Recursively sort a tree of comments using the comp comparator.\n   */\n  function sortComments(comments) {\n    comments.sort(comp);\n    $.each(comments, function() {\n      this.children = sortComments(this.children);\n    });\n    return comments;\n  }\n\n  /**\n   * Get the children comments from a ul. If recursive is true,\n   * recursively include childrens' children.\n   */\n  function getChildren(ul, recursive) {\n    var children = [];\n    ul.children().children(\"[id^='cd']\")\n      .each(function() {\n        var comment = $(this).data('comment');\n        if (recursive)\n          comment.children = getChildren($(this).find('#cl' + comment.id), true);\n        children.push(comment);\n      });\n    return children;\n  }\n\n  /** Create a div to display a comment in. */\n  function createCommentDiv(comment) {\n    if (!comment.displayed && !opts.moderator) {\n      return $('<div class=\"moderate\">Thank you!  Your comment will show up '\n               + 'once it is has been approved by a moderator.</div>');\n    }\n    // Prettify the comment rating.\n    comment.pretty_rating = comment.rating + ' point' +\n      (comment.rating == 1 ? '' : 's');\n    // Make a class (for displaying not yet moderated comments differently)\n    comment.css_class = comment.displayed ? '' : ' moderate';\n    // Create a div for this comment.\n    var context = $.extend({}, opts, comment);\n    var div = $(renderTemplate(commentTemplate, context));\n\n    // If the user has voted on this comment, highlight the correct arrow.\n    if (comment.vote) {\n      var direction = (comment.vote == 1) ? 'u' : 'd';\n      div.find('#' + direction + 'v' + comment.id).hide();\n      div.find('#' + direction + 'u' + comment.id).show();\n    }\n\n    if (opts.moderator || comment.text != '[deleted]') {\n      div.find('a.reply').show();\n      if (comment.proposal_diff)\n        div.find('#sp' + comment.id).show();\n      if (opts.moderator && !comment.displayed)\n        div.find('#cm' + comment.id).show();\n      if (opts.moderator || (opts.username == comment.username))\n        div.find('#dc' + comment.id).show();\n    }\n    return div;\n  }\n\n  /**\n   * A simple template renderer. Placeholders such as <%id%> are replaced\n   * by context['id'] with items being escaped. Placeholders such as <#id#>\n   * are not escaped.\n   */\n  function renderTemplate(template, context) {\n    var esc = $(document.createElement('div'));\n\n    function handle(ph, escape) {\n      var cur = context;\n      $.each(ph.split('.'), function() {\n        cur = cur[this];\n      });\n      return escape ? esc.text(cur || \"\").html() : cur;\n    }\n\n    return template.replace(/<([%#])([\\w\\.]*)\\1>/g, function() {\n      return handle(arguments[2], arguments[1] == '%' ? true : false);\n    });\n  }\n\n  /** Flash an error message briefly. */\n  function showError(message) {\n    $(document.createElement('div')).attr({'class': 'popup-error'})\n      .append($(document.createElement('div'))\n               .attr({'class': 'error-message'}).text(message))\n      .appendTo('body')\n      .fadeIn(\"slow\")\n      .delay(2000)\n      .fadeOut(\"slow\");\n  }\n\n  /** Add a link the user uses to open the comments popup. */\n  $.fn.comment = function() {\n    return this.each(function() {\n      var id = $(this).attr('id').substring(1);\n      var count = COMMENT_METADATA[id];\n      var title = count + ' comment' + (count == 1 ? '' : 's');\n      var image = count > 0 ? opts.commentBrightImage : opts.commentImage;\n      var addcls = count == 0 ? ' nocomment' : '';\n      $(this)\n        .append(\n          $(document.createElement('a')).attr({\n            href: '#',\n            'class': 'sphinx-comment-open' + addcls,\n            id: 'ao' + id\n          })\n            .append($(document.createElement('img')).attr({\n              src: image,\n              alt: 'comment',\n              title: title\n            }))\n            .click(function(event) {\n              event.preventDefault();\n              show($(this).attr('id').substring(2));\n            })\n        )\n        .append(\n          $(document.createElement('a')).attr({\n            href: '#',\n            'class': 'sphinx-comment-close hidden',\n            id: 'ah' + id\n          })\n            .append($(document.createElement('img')).attr({\n              src: opts.closeCommentImage,\n              alt: 'close',\n              title: 'close'\n            }))\n            .click(function(event) {\n              event.preventDefault();\n              hide($(this).attr('id').substring(2));\n            })\n        );\n    });\n  };\n\n  var opts = {\n    processVoteURL: '/_process_vote',\n    addCommentURL: '/_add_comment',\n    getCommentsURL: '/_get_comments',\n    acceptCommentURL: '/_accept_comment',\n    deleteCommentURL: '/_delete_comment',\n    commentImage: '/static/_static/comment.png',\n    closeCommentImage: '/static/_static/comment-close.png',\n    loadingImage: '/static/_static/ajax-loader.gif',\n    commentBrightImage: '/static/_static/comment-bright.png',\n    upArrow: '/static/_static/up.png',\n    downArrow: '/static/_static/down.png',\n    upArrowPressed: '/static/_static/up-pressed.png',\n    downArrowPressed: '/static/_static/down-pressed.png',\n    voting: false,\n    moderator: false\n  };\n\n  if (typeof COMMENT_OPTIONS != \"undefined\") {\n    opts = jQuery.extend(opts, COMMENT_OPTIONS);\n  }\n\n  var popupTemplate = '\\\n    <div class=\"sphinx-comments\" id=\"sc<%id%>\">\\\n      <p class=\"sort-options\">\\\n        Sort by:\\\n        <a href=\"#\" class=\"sort-option byrating\">best rated</a>\\\n        <a href=\"#\" class=\"sort-option byascage\">newest</a>\\\n        <a href=\"#\" class=\"sort-option byage\">oldest</a>\\\n      </p>\\\n      <div class=\"comment-header\">Comments</div>\\\n      <div class=\"comment-loading\" id=\"cn<%id%>\">\\\n        loading comments... <img src=\"<%loadingImage%>\" alt=\"\" /></div>\\\n      <ul id=\"cl<%id%>\" class=\"comment-ul\"></ul>\\\n      <div id=\"ca<%id%>\">\\\n      <p class=\"add-a-comment\">Add a comment\\\n        (<a href=\"#\" class=\"comment-markup\" id=\"ab<%id%>\">markup</a>):</p>\\\n      <div class=\"comment-markup-box\" id=\"mb<%id%>\">\\\n        reStructured text markup: <i>*emph*</i>, <b>**strong**</b>, \\\n        <code>``code``</code>, \\\n        code blocks: <code>::</code> and an indented block after blank line</div>\\\n      <form method=\"post\" id=\"cf<%id%>\" class=\"comment-form\" action=\"\">\\\n        <textarea name=\"comment\" cols=\"80\"></textarea>\\\n        <p class=\"propose-button\">\\\n          <a href=\"#\" id=\"pc<%id%>\" class=\"show-propose-change\">\\\n            Propose a change &#9657;\\\n          </a>\\\n          <a href=\"#\" id=\"hc<%id%>\" class=\"hide-propose-change\">\\\n            Propose a change &#9663;\\\n          </a>\\\n        </p>\\\n        <textarea name=\"proposal\" id=\"pt<%id%>\" cols=\"80\"\\\n                  spellcheck=\"false\"></textarea>\\\n        <input type=\"submit\" value=\"Add comment\" />\\\n        <input type=\"hidden\" name=\"node\" value=\"<%id%>\" />\\\n        <input type=\"hidden\" name=\"parent\" value=\"\" />\\\n      </form>\\\n      </div>\\\n    </div>';\n\n  var commentTemplate = '\\\n    <div id=\"cd<%id%>\" class=\"sphinx-comment<%css_class%>\">\\\n      <div class=\"vote\">\\\n        <div class=\"arrow\">\\\n          <a href=\"#\" id=\"uv<%id%>\" class=\"vote\" title=\"vote up\">\\\n            <img src=\"<%upArrow%>\" />\\\n          </a>\\\n          <a href=\"#\" id=\"uu<%id%>\" class=\"un vote\" title=\"vote up\">\\\n            <img src=\"<%upArrowPressed%>\" />\\\n          </a>\\\n        </div>\\\n        <div class=\"arrow\">\\\n          <a href=\"#\" id=\"dv<%id%>\" class=\"vote\" title=\"vote down\">\\\n            <img src=\"<%downArrow%>\" id=\"da<%id%>\" />\\\n          </a>\\\n          <a href=\"#\" id=\"du<%id%>\" class=\"un vote\" title=\"vote down\">\\\n            <img src=\"<%downArrowPressed%>\" />\\\n          </a>\\\n        </div>\\\n      </div>\\\n      <div class=\"comment-content\">\\\n        <p class=\"tagline comment\">\\\n          <span class=\"user-id\"><%username%></span>\\\n          <span class=\"rating\"><%pretty_rating%></span>\\\n          <span class=\"delta\"><%time.delta%></span>\\\n        </p>\\\n        <div class=\"comment-text comment\"><#text#></div>\\\n        <p class=\"comment-opts comment\">\\\n          <a href=\"#\" class=\"reply hidden\" id=\"rl<%id%>\">reply &#9657;</a>\\\n          <a href=\"#\" class=\"close-reply\" id=\"cr<%id%>\">reply &#9663;</a>\\\n          <a href=\"#\" id=\"sp<%id%>\" class=\"show-proposal\">proposal &#9657;</a>\\\n          <a href=\"#\" id=\"hp<%id%>\" class=\"hide-proposal\">proposal &#9663;</a>\\\n          <a href=\"#\" id=\"dc<%id%>\" class=\"delete-comment hidden\">delete</a>\\\n          <span id=\"cm<%id%>\" class=\"moderation hidden\">\\\n            <a href=\"#\" id=\"ac<%id%>\" class=\"accept-comment\">accept</a>\\\n          </span>\\\n        </p>\\\n        <pre class=\"proposal\" id=\"pr<%id%>\">\\\n<#proposal_diff#>\\\n        </pre>\\\n          <ul class=\"comment-children\" id=\"cl<%id%>\"></ul>\\\n        </div>\\\n        <div class=\"clearleft\"></div>\\\n      </div>\\\n    </div>';\n\n  var replyTemplate = '\\\n    <li>\\\n      <div class=\"reply-div\" id=\"rd<%id%>\">\\\n        <form id=\"rf<%id%>\">\\\n          <textarea name=\"comment\" cols=\"80\"></textarea>\\\n          <input type=\"submit\" value=\"Add reply\" />\\\n          <input type=\"button\" value=\"Cancel\" />\\\n          <input type=\"hidden\" name=\"parent\" value=\"<%id%>\" />\\\n          <input type=\"hidden\" name=\"node\" value=\"\" />\\\n        </form>\\\n      </div>\\\n    </li>';\n\n  $(document).ready(function() {\n    init();\n  });\n})(jQuery);\n\n$(document).ready(function() {\n  // add comment anchors for all paragraphs that are commentable\n  $('.sphinx-has-comment').comment();\n\n  // highlight search words in search results\n  $(\"div.context\").each(function() {\n    var params = $.getQueryParameters();\n    var terms = (params.q) ? params.q[0].split(/\\s+/) : [];\n    var result = $(this);\n    $.each(terms, function() {\n      result.highlightText(this.toLowerCase(), 'highlighted');\n    });\n  });\n\n  // directly open comment window if requested\n  var anchor = document.location.hash;\n  if (anchor.substring(0, 9) == '#comment-') {\n    $('#ao' + anchor.substring(9)).click();\n    document.location.hash = '#s' + anchor.substring(9);\n  }\n});\n"
  },
  {
    "path": "docs/config.html",
    "content": "\n\n<!DOCTYPE html>\n<!--[if IE 8]><html class=\"no-js lt-ie9\" lang=\"zh-CN\" > <![endif]-->\n<!--[if gt IE 8]><!--> <html class=\"no-js\" lang=\"zh-CN\" > <!--<![endif]-->\n<head>\n  <meta charset=\"utf-8\">\n  \n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  \n  <title>config module &mdash; wukong-robot 1.2.0 文档</title>\n  \n\n  \n  \n  \n  \n\n  \n  <script type=\"text/javascript\" src=\"_static/js/modernizr.min.js\"></script>\n  \n    \n      <script type=\"text/javascript\" id=\"documentation_options\" data-url_root=\"./\" src=\"_static/documentation_options.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/jquery.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/underscore.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/doctools.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/language_data.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/translations.js\"></script>\n    \n    <script type=\"text/javascript\" src=\"_static/js/theme.js\"></script>\n\n    \n\n  \n  <link rel=\"stylesheet\" href=\"_static/css/theme.css\" type=\"text/css\" />\n  <link rel=\"stylesheet\" href=\"_static/pygments.css\" type=\"text/css\" />\n    <link rel=\"index\" title=\"索引\" href=\"genindex.html\" />\n    <link rel=\"search\" title=\"搜索\" href=\"search.html\" /> \n</head>\n\n<body class=\"wy-body-for-nav\">\n\n   \n  <div class=\"wy-grid-for-nav\">\n    \n    <nav data-toggle=\"wy-nav-shift\" class=\"wy-nav-side\">\n      <div class=\"wy-side-scroll\">\n        <div class=\"wy-side-nav-search\" >\n          \n\n          \n            <a href=\"index.html\" class=\"icon icon-home\"> wukong-robot\n          \n\n          \n          </a>\n\n          \n            \n            \n          \n\n          \n<div role=\"search\">\n  <form id=\"rtd-search-form\" class=\"wy-form\" action=\"search.html\" method=\"get\">\n    <input type=\"text\" name=\"q\" placeholder=\"Search docs\" />\n    <input type=\"hidden\" name=\"check_keywords\" value=\"yes\" />\n    <input type=\"hidden\" name=\"area\" value=\"default\" />\n  </form>\n</div>\n\n          \n        </div>\n\n        <div class=\"wy-menu wy-menu-vertical\" data-spy=\"affix\" role=\"navigation\" aria-label=\"main navigation\">\n          \n            \n            \n              \n            \n            \n              <!-- Local TOC -->\n              <div class=\"local-toc\"><ul>\n<li><a class=\"reference internal\" href=\"#\">config module</a></li>\n</ul>\n</div>\n            \n          \n        </div>\n      </div>\n    </nav>\n\n    <section data-toggle=\"wy-nav-shift\" class=\"wy-nav-content-wrap\">\n\n      \n      <nav class=\"wy-nav-top\" aria-label=\"top navigation\">\n        \n          <i data-toggle=\"wy-nav-top\" class=\"fa fa-bars\"></i>\n          <a href=\"index.html\">wukong-robot</a>\n        \n      </nav>\n\n\n      <div class=\"wy-nav-content\">\n        \n        <div class=\"rst-content\">\n        \n          \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<div role=\"navigation\" aria-label=\"breadcrumbs navigation\">\n\n  <ul class=\"wy-breadcrumbs\">\n    \n      <li><a href=\"index.html\">Docs</a> &raquo;</li>\n        \n      <li>config module</li>\n    \n    \n      <li class=\"wy-breadcrumbs-aside\">\n        \n            \n            <a href=\"_sources/config.rst.txt\" rel=\"nofollow\"> View page source</a>\n          \n        \n      </li>\n    \n  </ul>\n\n  \n  <hr/>\n</div>\n          <div role=\"main\" class=\"document\" itemscope=\"itemscope\" itemtype=\"http://schema.org/Article\">\n           <div itemprop=\"articleBody\">\n            \n  <div class=\"section\" id=\"config-module\">\n<h1>config module<a class=\"headerlink\" href=\"#config-module\" title=\"永久链接至标题\">¶</a></h1>\n</div>\n\n\n           </div>\n           \n          </div>\n          <footer>\n  \n\n  <hr/>\n\n  <div role=\"contentinfo\">\n    <p>\n        &copy; Copyright 2019, wzpan\n\n    </p>\n  </div>\n  Built with <a href=\"http://sphinx-doc.org/\">Sphinx</a> using a <a href=\"https://github.com/rtfd/sphinx_rtd_theme\">theme</a> provided by <a href=\"https://readthedocs.org\">Read the Docs</a>. \n\n</footer>\n\n        </div>\n      </div>\n\n    </section>\n\n  </div>\n  \n\n\n  <script type=\"text/javascript\">\n      jQuery(function () {\n          SphinxRtdTheme.Navigation.enable(true);\n      });\n  </script>\n\n  \n  \n    \n   \n\n</body>\n</html>"
  },
  {
    "path": "docs/constants.html",
    "content": "\n\n<!DOCTYPE html>\n<!--[if IE 8]><html class=\"no-js lt-ie9\" lang=\"zh-CN\" > <![endif]-->\n<!--[if gt IE 8]><!--> <html class=\"no-js\" lang=\"zh-CN\" > <!--<![endif]-->\n<head>\n  <meta charset=\"utf-8\">\n  \n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  \n  <title>constants module &mdash; wukong-robot 1.2.0 文档</title>\n  \n\n  \n  \n  \n  \n\n  \n  <script type=\"text/javascript\" src=\"_static/js/modernizr.min.js\"></script>\n  \n    \n      <script type=\"text/javascript\" id=\"documentation_options\" data-url_root=\"./\" src=\"_static/documentation_options.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/jquery.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/underscore.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/doctools.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/language_data.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/translations.js\"></script>\n    \n    <script type=\"text/javascript\" src=\"_static/js/theme.js\"></script>\n\n    \n\n  \n  <link rel=\"stylesheet\" href=\"_static/css/theme.css\" type=\"text/css\" />\n  <link rel=\"stylesheet\" href=\"_static/pygments.css\" type=\"text/css\" />\n    <link rel=\"index\" title=\"索引\" href=\"genindex.html\" />\n    <link rel=\"search\" title=\"搜索\" href=\"search.html\" /> \n</head>\n\n<body class=\"wy-body-for-nav\">\n\n   \n  <div class=\"wy-grid-for-nav\">\n    \n    <nav data-toggle=\"wy-nav-shift\" class=\"wy-nav-side\">\n      <div class=\"wy-side-scroll\">\n        <div class=\"wy-side-nav-search\" >\n          \n\n          \n            <a href=\"index.html\" class=\"icon icon-home\"> wukong-robot\n          \n\n          \n          </a>\n\n          \n            \n            \n          \n\n          \n<div role=\"search\">\n  <form id=\"rtd-search-form\" class=\"wy-form\" action=\"search.html\" method=\"get\">\n    <input type=\"text\" name=\"q\" placeholder=\"Search docs\" />\n    <input type=\"hidden\" name=\"check_keywords\" value=\"yes\" />\n    <input type=\"hidden\" name=\"area\" value=\"default\" />\n  </form>\n</div>\n\n          \n        </div>\n\n        <div class=\"wy-menu wy-menu-vertical\" data-spy=\"affix\" role=\"navigation\" aria-label=\"main navigation\">\n          \n            \n            \n              \n            \n            \n              <!-- Local TOC -->\n              <div class=\"local-toc\"><ul>\n<li><a class=\"reference internal\" href=\"#\">constants module</a></li>\n</ul>\n</div>\n            \n          \n        </div>\n      </div>\n    </nav>\n\n    <section data-toggle=\"wy-nav-shift\" class=\"wy-nav-content-wrap\">\n\n      \n      <nav class=\"wy-nav-top\" aria-label=\"top navigation\">\n        \n          <i data-toggle=\"wy-nav-top\" class=\"fa fa-bars\"></i>\n          <a href=\"index.html\">wukong-robot</a>\n        \n      </nav>\n\n\n      <div class=\"wy-nav-content\">\n        \n        <div class=\"rst-content\">\n        \n          \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<div role=\"navigation\" aria-label=\"breadcrumbs navigation\">\n\n  <ul class=\"wy-breadcrumbs\">\n    \n      <li><a href=\"index.html\">Docs</a> &raquo;</li>\n        \n      <li>constants module</li>\n    \n    \n      <li class=\"wy-breadcrumbs-aside\">\n        \n            \n            <a href=\"_sources/constants.rst.txt\" rel=\"nofollow\"> View page source</a>\n          \n        \n      </li>\n    \n  </ul>\n\n  \n  <hr/>\n</div>\n          <div role=\"main\" class=\"document\" itemscope=\"itemscope\" itemtype=\"http://schema.org/Article\">\n           <div itemprop=\"articleBody\">\n            \n  <div class=\"section\" id=\"constants-module\">\n<h1>constants module<a class=\"headerlink\" href=\"#constants-module\" title=\"永久链接至标题\">¶</a></h1>\n</div>\n\n\n           </div>\n           \n          </div>\n          <footer>\n  \n\n  <hr/>\n\n  <div role=\"contentinfo\">\n    <p>\n        &copy; Copyright 2019, wzpan\n\n    </p>\n  </div>\n  Built with <a href=\"http://sphinx-doc.org/\">Sphinx</a> using a <a href=\"https://github.com/rtfd/sphinx_rtd_theme\">theme</a> provided by <a href=\"https://readthedocs.org\">Read the Docs</a>. \n\n</footer>\n\n        </div>\n      </div>\n\n    </section>\n\n  </div>\n  \n\n\n  <script type=\"text/javascript\">\n      jQuery(function () {\n          SphinxRtdTheme.Navigation.enable(true);\n      });\n  </script>\n\n  \n  \n    \n   \n\n</body>\n</html>"
  },
  {
    "path": "docs/drivers.html",
    "content": "\n\n<!DOCTYPE html>\n<!--[if IE 8]><html class=\"no-js lt-ie9\" lang=\"zh-CN\" > <![endif]-->\n<!--[if gt IE 8]><!--> <html class=\"no-js\" lang=\"zh-CN\" > <!--<![endif]-->\n<head>\n  <meta charset=\"utf-8\">\n  \n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  \n  <title>drivers package &mdash; wukong-robot 1.2.0 文档</title>\n  \n\n  \n  \n  \n  \n\n  \n  <script type=\"text/javascript\" src=\"_static/js/modernizr.min.js\"></script>\n  \n    \n      <script type=\"text/javascript\" id=\"documentation_options\" data-url_root=\"./\" src=\"_static/documentation_options.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/jquery.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/underscore.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/doctools.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/language_data.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/translations.js\"></script>\n    \n    <script type=\"text/javascript\" src=\"_static/js/theme.js\"></script>\n\n    \n\n  \n  <link rel=\"stylesheet\" href=\"_static/css/theme.css\" type=\"text/css\" />\n  <link rel=\"stylesheet\" href=\"_static/pygments.css\" type=\"text/css\" />\n    <link rel=\"index\" title=\"索引\" href=\"genindex.html\" />\n    <link rel=\"search\" title=\"搜索\" href=\"search.html\" /> \n</head>\n\n<body class=\"wy-body-for-nav\">\n\n   \n  <div class=\"wy-grid-for-nav\">\n    \n    <nav data-toggle=\"wy-nav-shift\" class=\"wy-nav-side\">\n      <div class=\"wy-side-scroll\">\n        <div class=\"wy-side-nav-search\" >\n          \n\n          \n            <a href=\"index.html\" class=\"icon icon-home\"> wukong-robot\n          \n\n          \n          </a>\n\n          \n            \n            \n          \n\n          \n<div role=\"search\">\n  <form id=\"rtd-search-form\" class=\"wy-form\" action=\"search.html\" method=\"get\">\n    <input type=\"text\" name=\"q\" placeholder=\"Search docs\" />\n    <input type=\"hidden\" name=\"check_keywords\" value=\"yes\" />\n    <input type=\"hidden\" name=\"area\" value=\"default\" />\n  </form>\n</div>\n\n          \n        </div>\n\n        <div class=\"wy-menu wy-menu-vertical\" data-spy=\"affix\" role=\"navigation\" aria-label=\"main navigation\">\n          \n            \n            \n              \n            \n            \n              <!-- Local TOC -->\n              <div class=\"local-toc\"><ul>\n<li><a class=\"reference internal\" href=\"#\">drivers package</a><ul>\n<li><a class=\"reference internal\" href=\"#submodules\">Submodules</a></li>\n<li><a class=\"reference internal\" href=\"#drivers-apa102-module\">drivers.apa102 module</a></li>\n<li><a class=\"reference internal\" href=\"#drivers-pixels-module\">drivers.pixels module</a></li>\n<li><a class=\"reference internal\" href=\"#module-contents\">Module contents</a></li>\n</ul>\n</li>\n</ul>\n</div>\n            \n          \n        </div>\n      </div>\n    </nav>\n\n    <section data-toggle=\"wy-nav-shift\" class=\"wy-nav-content-wrap\">\n\n      \n      <nav class=\"wy-nav-top\" aria-label=\"top navigation\">\n        \n          <i data-toggle=\"wy-nav-top\" class=\"fa fa-bars\"></i>\n          <a href=\"index.html\">wukong-robot</a>\n        \n      </nav>\n\n\n      <div class=\"wy-nav-content\">\n        \n        <div class=\"rst-content\">\n        \n          \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<div role=\"navigation\" aria-label=\"breadcrumbs navigation\">\n\n  <ul class=\"wy-breadcrumbs\">\n    \n      <li><a href=\"index.html\">Docs</a> &raquo;</li>\n        \n      <li>drivers package</li>\n    \n    \n      <li class=\"wy-breadcrumbs-aside\">\n        \n            \n            <a href=\"_sources/drivers.rst.txt\" rel=\"nofollow\"> View page source</a>\n          \n        \n      </li>\n    \n  </ul>\n\n  \n  <hr/>\n</div>\n          <div role=\"main\" class=\"document\" itemscope=\"itemscope\" itemtype=\"http://schema.org/Article\">\n           <div itemprop=\"articleBody\">\n            \n  <div class=\"section\" id=\"drivers-package\">\n<h1>drivers package<a class=\"headerlink\" href=\"#drivers-package\" title=\"永久链接至标题\">¶</a></h1>\n<div class=\"section\" id=\"submodules\">\n<h2>Submodules<a class=\"headerlink\" href=\"#submodules\" title=\"永久链接至标题\">¶</a></h2>\n</div>\n<div class=\"section\" id=\"drivers-apa102-module\">\n<h2>drivers.apa102 module<a class=\"headerlink\" href=\"#drivers-apa102-module\" title=\"永久链接至标题\">¶</a></h2>\n</div>\n<div class=\"section\" id=\"drivers-pixels-module\">\n<h2>drivers.pixels module<a class=\"headerlink\" href=\"#drivers-pixels-module\" title=\"永久链接至标题\">¶</a></h2>\n</div>\n<div class=\"section\" id=\"module-contents\">\n<h2>Module contents<a class=\"headerlink\" href=\"#module-contents\" title=\"永久链接至标题\">¶</a></h2>\n</div>\n</div>\n\n\n           </div>\n           \n          </div>\n          <footer>\n  \n\n  <hr/>\n\n  <div role=\"contentinfo\">\n    <p>\n        &copy; Copyright 2019, wzpan\n\n    </p>\n  </div>\n  Built with <a href=\"http://sphinx-doc.org/\">Sphinx</a> using a <a href=\"https://github.com/rtfd/sphinx_rtd_theme\">theme</a> provided by <a href=\"https://readthedocs.org\">Read the Docs</a>. \n\n</footer>\n\n        </div>\n      </div>\n\n    </section>\n\n  </div>\n  \n\n\n  <script type=\"text/javascript\">\n      jQuery(function () {\n          SphinxRtdTheme.Navigation.enable(true);\n      });\n  </script>\n\n  \n  \n    \n   \n\n</body>\n</html>"
  },
  {
    "path": "docs/genindex.html",
    "content": "\n\n\n<!DOCTYPE html>\n<!--[if IE 8]><html class=\"no-js lt-ie9\" lang=\"zh-CN\" > <![endif]-->\n<!--[if gt IE 8]><!--> <html class=\"no-js\" lang=\"zh-CN\" > <!--<![endif]-->\n<head>\n  <meta charset=\"utf-8\">\n  \n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  \n  <title>索引 &mdash; wukong-robot 1.2.0 文档</title>\n  \n\n  \n  \n  \n  \n\n  \n  <script type=\"text/javascript\" src=\"_static/js/modernizr.min.js\"></script>\n  \n    \n      <script type=\"text/javascript\" id=\"documentation_options\" data-url_root=\"./\" src=\"_static/documentation_options.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/jquery.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/underscore.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/doctools.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/language_data.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/translations.js\"></script>\n    \n    <script type=\"text/javascript\" src=\"_static/js/theme.js\"></script>\n\n    \n\n  \n  <link rel=\"stylesheet\" href=\"_static/css/theme.css\" type=\"text/css\" />\n  <link rel=\"stylesheet\" href=\"_static/pygments.css\" type=\"text/css\" />\n    <link rel=\"index\" title=\"索引\" href=\"#\" />\n    <link rel=\"search\" title=\"搜索\" href=\"search.html\" /> \n</head>\n\n<body class=\"wy-body-for-nav\">\n\n   \n  <div class=\"wy-grid-for-nav\">\n    \n    <nav data-toggle=\"wy-nav-shift\" class=\"wy-nav-side\">\n      <div class=\"wy-side-scroll\">\n        <div class=\"wy-side-nav-search\" >\n          \n\n          \n            <a href=\"index.html\" class=\"icon icon-home\"> wukong-robot\n          \n\n          \n          </a>\n\n          \n            \n            \n          \n\n          \n<div role=\"search\">\n  <form id=\"rtd-search-form\" class=\"wy-form\" action=\"search.html\" method=\"get\">\n    <input type=\"text\" name=\"q\" placeholder=\"Search docs\" />\n    <input type=\"hidden\" name=\"check_keywords\" value=\"yes\" />\n    <input type=\"hidden\" name=\"area\" value=\"default\" />\n  </form>\n</div>\n\n          \n        </div>\n\n        <div class=\"wy-menu wy-menu-vertical\" data-spy=\"affix\" role=\"navigation\" aria-label=\"main navigation\">\n          \n            \n            \n              \n            \n            \n              <!-- Local TOC -->\n              <div class=\"local-toc\"></div>\n            \n          \n        </div>\n      </div>\n    </nav>\n\n    <section data-toggle=\"wy-nav-shift\" class=\"wy-nav-content-wrap\">\n\n      \n      <nav class=\"wy-nav-top\" aria-label=\"top navigation\">\n        \n          <i data-toggle=\"wy-nav-top\" class=\"fa fa-bars\"></i>\n          <a href=\"index.html\">wukong-robot</a>\n        \n      </nav>\n\n\n      <div class=\"wy-nav-content\">\n        \n        <div class=\"rst-content\">\n        \n          \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<div role=\"navigation\" aria-label=\"breadcrumbs navigation\">\n\n  <ul class=\"wy-breadcrumbs\">\n    \n      <li><a href=\"index.html\">Docs</a> &raquo;</li>\n        \n      <li>索引</li>\n    \n    \n      <li class=\"wy-breadcrumbs-aside\">\n        \n            \n        \n      </li>\n    \n  </ul>\n\n  \n  <hr/>\n</div>\n          <div role=\"main\" class=\"document\" itemscope=\"itemscope\" itemtype=\"http://schema.org/Article\">\n           <div itemprop=\"articleBody\">\n            \n\n<h1 id=\"index\">索引</h1>\n\n<div class=\"genindex-jumpbox\">\n <a href=\"#A\"><strong>A</strong></a>\n | <a href=\"#B\"><strong>B</strong></a>\n | <a href=\"#C\"><strong>C</strong></a>\n | <a href=\"#D\"><strong>D</strong></a>\n | <a href=\"#E\"><strong>E</strong></a>\n | <a href=\"#F\"><strong>F</strong></a>\n | <a href=\"#G\"><strong>G</strong></a>\n | <a href=\"#H\"><strong>H</strong></a>\n | <a href=\"#I\"><strong>I</strong></a>\n | <a href=\"#L\"><strong>L</strong></a>\n | <a href=\"#M\"><strong>M</strong></a>\n | <a href=\"#N\"><strong>N</strong></a>\n | <a href=\"#O\"><strong>O</strong></a>\n | <a href=\"#P\"><strong>P</strong></a>\n | <a href=\"#Q\"><strong>Q</strong></a>\n | <a href=\"#R\"><strong>R</strong></a>\n | <a href=\"#S\"><strong>S</strong></a>\n | <a href=\"#T\"><strong>T</strong></a>\n | <a href=\"#U\"><strong>U</strong></a>\n | <a href=\"#V\"><strong>V</strong></a>\n | <a href=\"#W\"><strong>W</strong></a>\n | <a href=\"#X\"><strong>X</strong></a>\n \n</div>\n<h2 id=\"A\">A</h2>\n<table style=\"width: 100%\" class=\"indextable genindextable\"><tr>\n  <td style=\"width: 33%; vertical-align: top;\"><ul>\n      <li><a href=\"robot.html#robot.ASR.AbstractASR\">AbstractASR (robot.ASR 中的类)</a>\n</li>\n      <li><a href=\"robot.html#robot.NLU.AbstractNLU\">AbstractNLU (robot.NLU 中的类)</a>\n</li>\n      <li><a href=\"robot.html#robot.Player.AbstractPlayer\">AbstractPlayer (robot.Player 中的类)</a>\n</li>\n      <li><a href=\"robot.sdk.html#robot.sdk.AbstractPlugin.AbstractPlugin\">AbstractPlugin (robot.sdk.AbstractPlugin 中的类)</a>\n</li>\n      <li><a href=\"robot.html#robot.AI.AbstractRobot\">AbstractRobot (robot.AI 中的类)</a>\n</li>\n      <li><a href=\"robot.html#robot.TTS.AbstractTTS\">AbstractTTS (robot.TTS 中的类)</a>\n</li>\n      <li><a href=\"robot.html#robot.Conversation.Conversation.activeListen\">activeListen() (robot.Conversation.Conversation 方法)</a>\n\n      <ul>\n        <li><a href=\"robot.sdk.html#robot.sdk.AbstractPlugin.AbstractPlugin.activeListen\">(robot.sdk.AbstractPlugin.AbstractPlugin 方法)</a>\n</li>\n      </ul></li>\n  </ul></td>\n  <td style=\"width: 33%; vertical-align: top;\"><ul>\n      <li><a href=\"snowboy.html#snowboy.snowboydecoder.ActiveListener\">ActiveListener (snowboy.snowboydecoder 中的类)</a>\n</li>\n      <li><a href=\"robot.html#robot.ASR.AliASR\">AliASR (robot.ASR 中的类)</a>\n</li>\n      <li><a href=\"robot.html#robot.TTS.AliTTS\">AliTTS (robot.TTS 中的类)</a>\n</li>\n      <li><a href=\"robot.html#robot.Conversation.Conversation.appendHistory\">appendHistory() (robot.Conversation.Conversation 方法)</a>\n</li>\n      <li><a href=\"robot.html#robot.Player.SoxPlayer.appendOnCompleted\">appendOnCompleted() (robot.Player.SoxPlayer 方法)</a>\n</li>\n      <li><a href=\"snowboy.html#snowboy.snowboydetect.SnowboyDetect.ApplyFrontend\">ApplyFrontend() (snowboy.snowboydetect.SnowboyDetect 方法)</a>\n\n      <ul>\n        <li><a href=\"snowboy.html#snowboy.snowboydetect.SnowboyVad.ApplyFrontend\">(snowboy.snowboydetect.SnowboyVad 方法)</a>\n</li>\n      </ul></li>\n      <li><a href=\"robot.sdk.html#robot.sdk.TencentSpeech.tencentSpeech.ASR\">ASR() (robot.sdk.TencentSpeech.tencentSpeech 方法)</a>\n</li>\n      <li><a href=\"robot.sdk.html#robot.sdk.AliSpeech.asr\">asr() (在 robot.sdk.AliSpeech 模块中)</a>\n</li>\n  </ul></td>\n</tr></table>\n\n<h2 id=\"B\">B</h2>\n<table style=\"width: 100%\" class=\"indextable genindextable\"><tr>\n  <td style=\"width: 33%; vertical-align: top;\"><ul>\n      <li><a href=\"robot.html#robot.ASR.BaiduASR\">BaiduASR (robot.ASR 中的类)</a>\n</li>\n      <li><a href=\"robot.html#robot.TTS.BaiduTTS\">BaiduTTS (robot.TTS 中的类)</a>\n</li>\n  </ul></td>\n  <td style=\"width: 33%; vertical-align: top;\"><ul>\n      <li><a href=\"snowboy.html#snowboy.snowboydetect.SnowboyDetect.BitsPerSample\">BitsPerSample() (snowboy.snowboydetect.SnowboyDetect 方法)</a>\n\n      <ul>\n        <li><a href=\"snowboy.html#snowboy.snowboydetect.SnowboyVad.BitsPerSample\">(snowboy.snowboydetect.SnowboyVad 方法)</a>\n</li>\n      </ul></li>\n      <li><a href=\"robot.html#robot.Brain.Brain\">Brain (robot.Brain 中的类)</a>\n</li>\n  </ul></td>\n</tr></table>\n\n<h2 id=\"C\">C</h2>\n<table style=\"width: 100%\" class=\"indextable genindextable\"><tr>\n  <td style=\"width: 33%; vertical-align: top;\"><ul>\n      <li><a href=\"robot.html#robot.AI.AbstractRobot.chat\">chat() (robot.AI.AbstractRobot 方法)</a>\n\n      <ul>\n        <li><a href=\"robot.html#robot.AI.Emotibot.chat\">(robot.AI.Emotibot 方法)</a>\n</li>\n        <li><a href=\"robot.html#robot.AI.TulingRobot.chat\">(robot.AI.TulingRobot 方法)</a>\n</li>\n      </ul></li>\n      <li><a href=\"robot.html#robot.utils.check_and_delete\">check_and_delete() (在 robot.utils 模块中)</a>\n</li>\n      <li><a href=\"robot.html#robot.Conversation.Conversation.checkRestore\">checkRestore() (robot.Conversation.Conversation 方法)</a>\n</li>\n      <li><a href=\"robot.html#robot.utils.clean\">clean() (在 robot.utils 模块中)</a>\n</li>\n  </ul></td>\n  <td style=\"width: 33%; vertical-align: top;\"><ul>\n      <li><a href=\"robot.sdk.html#robot.sdk.AbstractPlugin.AbstractPlugin.clearImmersive\">clearImmersive() (robot.sdk.AbstractPlugin.AbstractPlugin 方法)</a>\n</li>\n      <li><a href=\"robot.html#robot.ConfigMonitor.ConfigMonitor\">ConfigMonitor (robot.ConfigMonitor 中的类)</a>\n</li>\n      <li><a href=\"robot.html#robot.Conversation.Conversation\">Conversation (robot.Conversation 中的类)</a>\n</li>\n      <li><a href=\"robot.html#robot.Conversation.Conversation.converse\">converse() (robot.Conversation.Conversation 方法)</a>\n</li>\n      <li><a href=\"robot.html#robot.utils.convert_mp3_to_wav\">convert_mp3_to_wav() (在 robot.utils 模块中)</a>\n</li>\n      <li><a href=\"robot.html#robot.utils.convert_wav_to_mp3\">convert_wav_to_mp3() (在 robot.utils 模块中)</a>\n</li>\n      <li><a href=\"robot.sdk.html#robot.sdk.XunfeiSpeech.Ws_Param.create_url\">create_url() (robot.sdk.XunfeiSpeech.Ws_Param 方法)</a>\n</li>\n  </ul></td>\n</tr></table>\n\n<h2 id=\"D\">D</h2>\n<table style=\"width: 100%\" class=\"indextable genindextable\"><tr>\n  <td style=\"width: 33%; vertical-align: top;\"><ul>\n      <li><a href=\"wukong.html#wukong.Wukong.dev\">dev() (wukong.Wukong 方法)</a>\n</li>\n      <li><a href=\"robot.html#robot.Conversation.Conversation.doConverse\">doConverse() (robot.Conversation.Conversation 方法)</a>\n</li>\n      <li><a href=\"robot.html#robot.config.doInit\">doInit() (在 robot.config 模块中)</a>\n</li>\n  </ul></td>\n  <td style=\"width: 33%; vertical-align: top;\"><ul>\n      <li><a href=\"robot.html#robot.Conversation.Conversation.doParse\">doParse() (robot.Conversation.Conversation 方法)</a>\n</li>\n      <li><a href=\"robot.html#robot.Player.SoxPlayer.doPlay\">doPlay() (robot.Player.SoxPlayer 方法)</a>\n</li>\n      <li><a href=\"robot.html#robot.Conversation.Conversation.doResponse\">doResponse() (robot.Conversation.Conversation 方法)</a>\n</li>\n      <li><a href=\"robot.html#robot.config.dump\">dump() (在 robot.config 模块中)</a>\n</li>\n  </ul></td>\n</tr></table>\n\n<h2 id=\"E\">E</h2>\n<table style=\"width: 100%\" class=\"indextable genindextable\"><tr>\n  <td style=\"width: 33%; vertical-align: top;\"><ul>\n      <li><a href=\"robot.html#robot.utils.emailUser\">emailUser() (在 robot.utils 模块中)</a>\n</li>\n      <li><a href=\"robot.html#robot.AI.Emotibot\">Emotibot (robot.AI 中的类)</a>\n</li>\n  </ul></td>\n  <td style=\"width: 33%; vertical-align: top;\"><ul>\n      <li><a href=\"robot.sdk.html#robot.sdk.TencentSpeech.tencentSpeech.encode_sign\">encode_sign() (robot.sdk.TencentSpeech.tencentSpeech 方法)</a>\n</li>\n      <li><a href=\"snowboy.html#snowboy.snowboydecoder.RingBuffer.extend\">extend() (snowboy.snowboydecoder.RingBuffer 方法)</a>\n</li>\n  </ul></td>\n</tr></table>\n\n<h2 id=\"F\">F</h2>\n<table style=\"width: 100%\" class=\"indextable genindextable\"><tr>\n  <td style=\"width: 33%; vertical-align: top;\"><ul>\n      <li><a href=\"robot.html#robot.Updater.Updater.fetch\">fetch() (robot.Updater.Updater 方法)</a>\n\n      <ul>\n        <li><a href=\"wukong.html#wukong.Wukong.fetch\">(wukong.Wukong 方法)</a>\n</li>\n        <li><a href=\"robot.html#robot.Updater.fetch\">(在 robot.Updater 模块中)</a>\n</li>\n      </ul></li>\n  </ul></td>\n  <td style=\"width: 33%; vertical-align: top;\"><ul>\n      <li><a href=\"plugins.html#plugins.Email.Plugin.fetchUnreadEmails\">fetchUnreadEmails() (plugins.Email.Plugin 方法)</a>\n</li>\n      <li><a href=\"robot.sdk.html#robot.sdk.TencentSpeech.tencentSpeech.formatSignString\">formatSignString() (robot.sdk.TencentSpeech.tencentSpeech 方法)</a>\n\n      <ul>\n        <li><a href=\"robot.sdk.html#robot.sdk.RASRsdk.formatSignString\">(在 robot.sdk.RASRsdk 模块中)</a>\n</li>\n      </ul></li>\n  </ul></td>\n</tr></table>\n\n<h2 id=\"G\">G</h2>\n<table style=\"width: 100%\" class=\"indextable genindextable\"><tr>\n  <td style=\"width: 33%; vertical-align: top;\"><ul>\n      <li><a href=\"snowboy.html#snowboy.snowboydecoder.RingBuffer.get\">get() (snowboy.snowboydecoder.RingBuffer 方法)</a>\n\n      <ul>\n        <li><a href=\"robot.html#robot.config.get\">(在 robot.config 模块中)</a>\n</li>\n      </ul></li>\n      <li><a href=\"robot.html#robot.AI.Emotibot.get_config\">get_config() (robot.AI.Emotibot 类方法)</a>\n\n      <ul>\n        <li><a href=\"robot.html#robot.AI.TulingRobot.get_config\">(robot.AI.TulingRobot 类方法)</a>\n</li>\n        <li><a href=\"robot.html#robot.ASR.AbstractASR.get_config\">(robot.ASR.AbstractASR 类方法)</a>\n</li>\n        <li><a href=\"robot.html#robot.ASR.AliASR.get_config\">(robot.ASR.AliASR 类方法)</a>\n</li>\n        <li><a href=\"robot.html#robot.ASR.BaiduASR.get_config\">(robot.ASR.BaiduASR 类方法)</a>\n</li>\n        <li><a href=\"robot.html#robot.ASR.TencentASR.get_config\">(robot.ASR.TencentASR 类方法)</a>\n</li>\n        <li><a href=\"robot.html#robot.ASR.XunfeiASR.get_config\">(robot.ASR.XunfeiASR 类方法)</a>\n</li>\n        <li><a href=\"robot.html#robot.NLU.AbstractNLU.get_config\">(robot.NLU.AbstractNLU 类方法)</a>\n</li>\n        <li><a href=\"robot.html#robot.NLU.UnitNLU.get_config\">(robot.NLU.UnitNLU 类方法)</a>\n</li>\n        <li><a href=\"robot.html#robot.TTS.AbstractTTS.get_config\">(robot.TTS.AbstractTTS 类方法)</a>\n</li>\n        <li><a href=\"robot.html#robot.TTS.AliTTS.get_config\">(robot.TTS.AliTTS 类方法)</a>\n</li>\n        <li><a href=\"robot.html#robot.TTS.BaiduTTS.get_config\">(robot.TTS.BaiduTTS 类方法)</a>\n</li>\n        <li><a href=\"robot.html#robot.TTS.TencentTTS.get_config\">(robot.TTS.TencentTTS 类方法)</a>\n</li>\n        <li><a href=\"robot.html#robot.TTS.XunfeiTTS.get_config\">(robot.TTS.XunfeiTTS 类方法)</a>\n</li>\n      </ul></li>\n      <li><a href=\"robot.html#robot.utils.get_do_not_bother_off_hotword\">get_do_not_bother_off_hotword() (在 robot.utils 模块中)</a>\n</li>\n      <li><a href=\"robot.html#robot.utils.get_do_not_bother_on_hotword\">get_do_not_bother_on_hotword() (在 robot.utils 模块中)</a>\n</li>\n      <li><a href=\"robot.html#robot.ASR.get_engine_by_slug\">get_engine_by_slug() (在 robot.ASR 模块中)</a>\n\n      <ul>\n        <li><a href=\"robot.html#robot.NLU.get_engine_by_slug\">(在 robot.NLU 模块中)</a>\n</li>\n        <li><a href=\"robot.html#robot.TTS.get_engine_by_slug\">(在 robot.TTS 模块中)</a>\n</li>\n      </ul></li>\n      <li><a href=\"robot.html#robot.ASR.get_engines\">get_engines() (在 robot.ASR 模块中)</a>\n\n      <ul>\n        <li><a href=\"robot.html#robot.NLU.get_engines\">(在 robot.NLU 模块中)</a>\n</li>\n        <li><a href=\"robot.html#robot.TTS.get_engines\">(在 robot.TTS 模块中)</a>\n</li>\n      </ul></li>\n      <li><a href=\"robot.html#robot.utils.get_file_content\">get_file_content() (在 robot.utils 模块中)</a>\n</li>\n      <li><a href=\"robot.html#robot.AI.AbstractRobot.get_instance\">get_instance() (robot.AI.AbstractRobot 类方法)</a>\n\n      <ul>\n        <li><a href=\"robot.html#robot.ASR.AbstractASR.get_instance\">(robot.ASR.AbstractASR 类方法)</a>\n</li>\n        <li><a href=\"robot.html#robot.NLU.AbstractNLU.get_instance\">(robot.NLU.AbstractNLU 类方法)</a>\n</li>\n        <li><a href=\"robot.html#robot.TTS.AbstractTTS.get_instance\">(robot.TTS.AbstractTTS 类方法)</a>\n</li>\n      </ul></li>\n      <li><a href=\"robot.html#robot.config.get_path\">get_path() (在 robot.config 模块中)</a>\n</li>\n      <li><a href=\"robot.html#robot.utils.get_pcm_from_wav\">get_pcm_from_wav() (在 robot.utils 模块中)</a>\n</li>\n      <li><a href=\"robot.html#robot.plugin_loader.get_plugins\">get_plugins() (在 robot.plugin_loader 模块中)</a>\n</li>\n      <li><a href=\"robot.html#robot.AI.get_robot_by_slug\">get_robot_by_slug() (在 robot.AI 模块中)</a>\n</li>\n      <li><a href=\"robot.html#robot.AI.get_robots\">get_robots() (在 robot.AI 模块中)</a>\n</li>\n      <li><a href=\"plugins.html#plugins.LocalPlayer.Plugin.get_song_list\">get_song_list() (plugins.LocalPlayer.Plugin 方法)</a>\n</li>\n      <li><a href=\"robot.html#robot.TTS.AbstractTTS.get_speech\">get_speech() (robot.TTS.AbstractTTS 方法)</a>\n\n      <ul>\n        <li><a href=\"robot.html#robot.TTS.AliTTS.get_speech\">(robot.TTS.AliTTS 方法)</a>\n</li>\n        <li><a href=\"robot.html#robot.TTS.BaiduTTS.get_speech\">(robot.TTS.BaiduTTS 方法)</a>\n</li>\n        <li><a href=\"robot.html#robot.TTS.TencentTTS.get_speech\">(robot.TTS.TencentTTS 方法)</a>\n</li>\n        <li><a href=\"robot.html#robot.TTS.XunfeiTTS.get_speech\">(robot.TTS.XunfeiTTS 方法)</a>\n</li>\n      </ul></li>\n  </ul></td>\n  <td style=\"width: 33%; vertical-align: top;\"><ul>\n      <li><a href=\"robot.sdk.html#robot.sdk.unit.get_token\">get_token() (在 robot.sdk.unit 模块中)</a>\n</li>\n      <li><a href=\"robot.html#robot.TTS.XunfeiTTS.getBody\">getBody() (robot.TTS.XunfeiTTS 方法)</a>\n</li>\n      <li><a href=\"robot.html#robot.utils.getCache\">getCache() (在 robot.utils 模块中)</a>\n</li>\n      <li><a href=\"robot.html#robot.config.getConfig\">getConfig() (在 robot.config 模块中)</a>\n</li>\n      <li><a href=\"robot.html#robot.constants.getConfigData\">getConfigData() (在 robot.constants 模块中)</a>\n</li>\n      <li><a href=\"robot.html#robot.constants.getConfigPath\">getConfigPath() (在 robot.constants 模块中)</a>\n</li>\n      <li><a href=\"robot.html#robot.constants.getData\">getData() (在 robot.constants 模块中)</a>\n</li>\n      <li><a href=\"plugins.html#plugins.Email.Plugin.getDate\">getDate() (plugins.Email.Plugin 方法)</a>\n</li>\n      <li><a href=\"robot.html#robot.constants.getDefaultConfigPath\">getDefaultConfigPath() (在 robot.constants 模块中)</a>\n</li>\n      <li><a href=\"robot.html#robot.TTS.XunfeiTTS.getHeader\">getHeader() (robot.TTS.XunfeiTTS 方法)</a>\n</li>\n      <li><a href=\"robot.html#robot.Conversation.Conversation.getHistory\">getHistory() (robot.Conversation.Conversation 方法)</a>\n</li>\n      <li><a href=\"robot.html#robot.constants.getHotwordModel\">getHotwordModel() (在 robot.constants 模块中)</a>\n</li>\n      <li><a href=\"robot.html#robot.Conversation.Conversation.getImmersiveMode\">getImmersiveMode() (robot.Conversation.Conversation 方法)</a>\n</li>\n      <li><a href=\"robot.html#robot.NLU.AbstractNLU.getIntent\">getIntent() (robot.NLU.AbstractNLU 方法)</a>\n\n      <ul>\n        <li><a href=\"robot.html#robot.NLU.UnitNLU.getIntent\">(robot.NLU.UnitNLU 方法)</a>\n</li>\n        <li><a href=\"robot.sdk.html#robot.sdk.unit.getIntent\">(在 robot.sdk.unit 模块中)</a>\n</li>\n      </ul></li>\n      <li><a href=\"robot.html#robot.logging.getLogger\">getLogger() (在 robot.logging 模块中)</a>\n</li>\n      <li><a href=\"plugins.html#plugins.Email.Plugin.getMostRecentDate\">getMostRecentDate() (plugins.Email.Plugin 方法)</a>\n</li>\n      <li><a href=\"robot.html#robot.Player.getPlayerByFileName\">getPlayerByFileName() (在 robot.Player 模块中)</a>\n</li>\n      <li><a href=\"robot.html#robot.NLU.AbstractNLU.getSay\">getSay() (robot.NLU.AbstractNLU 方法)</a>\n\n      <ul>\n        <li><a href=\"robot.html#robot.NLU.UnitNLU.getSay\">(robot.NLU.UnitNLU 方法)</a>\n</li>\n        <li><a href=\"robot.sdk.html#robot.sdk.unit.getSay\">(在 robot.sdk.unit 模块中)</a>\n</li>\n      </ul></li>\n      <li><a href=\"plugins.html#plugins.Email.Plugin.getSender\">getSender() (plugins.Email.Plugin 方法)</a>\n</li>\n      <li><a href=\"snowboy.html#snowboy.snowboydetect.SnowboyDetect.GetSensitivity\">GetSensitivity() (snowboy.snowboydetect.SnowboyDetect 方法)</a>\n</li>\n      <li><a href=\"robot.html#robot.NLU.AbstractNLU.getSlots\">getSlots() (robot.NLU.AbstractNLU 方法)</a>\n\n      <ul>\n        <li><a href=\"robot.html#robot.NLU.UnitNLU.getSlots\">(robot.NLU.UnitNLU 方法)</a>\n</li>\n        <li><a href=\"robot.sdk.html#robot.sdk.unit.getSlots\">(在 robot.sdk.unit 模块中)</a>\n</li>\n      </ul></li>\n      <li><a href=\"robot.html#robot.NLU.AbstractNLU.getSlotWords\">getSlotWords() (robot.NLU.AbstractNLU 方法)</a>\n\n      <ul>\n        <li><a href=\"robot.html#robot.NLU.UnitNLU.getSlotWords\">(robot.NLU.UnitNLU 方法)</a>\n</li>\n        <li><a href=\"robot.sdk.html#robot.sdk.unit.getSlotWords\">(在 robot.sdk.unit 模块中)</a>\n</li>\n      </ul></li>\n      <li><a href=\"plugins.html#plugins.Email.Plugin.getSubject\">getSubject() (plugins.Email.Plugin 方法)</a>\n</li>\n      <li><a href=\"robot.html#robot.config.getText\">getText() (在 robot.config 模块中)</a>\n</li>\n      <li><a href=\"robot.html#robot.utils.getTimezone\">getTimezone() (在 robot.utils 模块中)</a>\n</li>\n      <li><a href=\"robot.sdk.html#robot.sdk.unit.getUnit\">getUnit() (在 robot.sdk.unit 模块中)</a>\n</li>\n      <li><a href=\"robot.html#robot.statistic.getUUID\">getUUID() (在 robot.statistic 模块中)</a>\n</li>\n  </ul></td>\n</tr></table>\n\n<h2 id=\"H\">H</h2>\n<table style=\"width: 100%\" class=\"indextable genindextable\"><tr>\n  <td style=\"width: 33%; vertical-align: top;\"><ul>\n      <li><a href=\"plugins.html#plugins.Camera.Plugin.handle\">handle() (plugins.Camera.Plugin 方法)</a>\n\n      <ul>\n        <li><a href=\"plugins.html#plugins.CleanCache.Plugin.handle\">(plugins.CleanCache.Plugin 方法)</a>\n</li>\n        <li><a href=\"plugins.html#plugins.Echo.Plugin.handle\">(plugins.Echo.Plugin 方法)</a>\n</li>\n        <li><a href=\"plugins.html#plugins.Email.Plugin.handle\">(plugins.Email.Plugin 方法)</a>\n</li>\n        <li><a href=\"plugins.html#plugins.Geek.Plugin.handle\">(plugins.Geek.Plugin 方法)</a>\n</li>\n        <li><a href=\"plugins.html#plugins.LocalPlayer.Plugin.handle\">(plugins.LocalPlayer.Plugin 方法)</a>\n</li>\n        <li><a href=\"plugins.html#plugins.Poem.Plugin.handle\">(plugins.Poem.Plugin 方法)</a>\n</li>\n        <li><a href=\"robot.sdk.html#robot.sdk.AbstractPlugin.AbstractPlugin.handle\">(robot.sdk.AbstractPlugin.AbstractPlugin 方法)</a>\n</li>\n      </ul></li>\n  </ul></td>\n  <td style=\"width: 33%; vertical-align: top;\"><ul>\n      <li><a href=\"robot.html#robot.config.has\">has() (在 robot.config 模块中)</a>\n</li>\n      <li><a href=\"robot.html#robot.config.has_path\">has_path() (在 robot.config 模块中)</a>\n</li>\n      <li><a href=\"robot.html#robot.NLU.AbstractNLU.hasIntent\">hasIntent() (robot.NLU.AbstractNLU 方法)</a>\n\n      <ul>\n        <li><a href=\"robot.html#robot.NLU.UnitNLU.hasIntent\">(robot.NLU.UnitNLU 方法)</a>\n</li>\n        <li><a href=\"robot.sdk.html#robot.sdk.unit.hasIntent\">(在 robot.sdk.unit 模块中)</a>\n</li>\n      </ul></li>\n      <li><a href=\"snowboy.html#snowboy.snowboydecoder.HotwordDetector\">HotwordDetector (snowboy.snowboydecoder 中的类)</a>\n</li>\n  </ul></td>\n</tr></table>\n\n<h2 id=\"I\">I</h2>\n<table style=\"width: 100%\" class=\"indextable genindextable\"><tr>\n  <td style=\"width: 33%; vertical-align: top;\"><ul>\n      <li><a href=\"wukong.html#wukong.Wukong.init\">init() (wukong.Wukong 方法)</a>\n\n      <ul>\n        <li><a href=\"robot.html#robot.config.init\">(在 robot.config 模块中)</a>\n</li>\n      </ul></li>\n      <li><a href=\"plugins.html#plugins.LocalPlayer.Plugin.init_music_player\">init_music_player() (plugins.LocalPlayer.Plugin 方法)</a>\n</li>\n      <li><a href=\"robot.html#robot.plugin_loader.init_plugins\">init_plugins() (在 robot.plugin_loader 模块中)</a>\n</li>\n      <li><a href=\"wukong.html#wukong.Wukong.initDetector\">initDetector() (wukong.Wukong 方法)</a>\n</li>\n      <li><a href=\"robot.html#robot.Conversation.Conversation.interrupt\">interrupt() (robot.Conversation.Conversation 方法)</a>\n</li>\n      <li><a href=\"plugins.html#plugins.Geek.Plugin.IS_IMMERSIVE\">IS_IMMERSIVE (plugins.Geek.Plugin 属性)</a>\n\n      <ul>\n        <li><a href=\"plugins.html#plugins.LocalPlayer.Plugin.IS_IMMERSIVE\">(plugins.LocalPlayer.Plugin 属性)</a>\n</li>\n        <li><a href=\"robot.sdk.html#robot.sdk.AbstractPlugin.AbstractPlugin.IS_IMMERSIVE\">(robot.sdk.AbstractPlugin.AbstractPlugin 属性)</a>\n</li>\n      </ul></li>\n      <li><a href=\"robot.html#robot.Player.MusicPlayer.is_pausing\">is_pausing() (robot.Player.MusicPlayer 方法)</a>\n</li>\n      <li><a href=\"robot.html#robot.Player.AbstractPlayer.is_playing\">is_playing() (robot.Player.AbstractPlayer 方法)</a>\n\n      <ul>\n        <li><a href=\"robot.html#robot.Player.MusicPlayer.is_playing\">(robot.Player.MusicPlayer 方法)</a>\n</li>\n        <li><a href=\"robot.html#robot.Player.SoxPlayer.is_playing\">(robot.Player.SoxPlayer 方法)</a>\n</li>\n      </ul></li>\n      <li><a href=\"robot.html#robot.utils.is_proper_time\">is_proper_time() (在 robot.utils 模块中)</a>\n</li>\n  </ul></td>\n  <td style=\"width: 33%; vertical-align: top;\"><ul>\n      <li><a href=\"robot.html#robot.Brain.Brain.isImmersive\">isImmersive() (robot.Brain.Brain 方法)</a>\n</li>\n      <li><a href=\"plugins.html#plugins.Email.Plugin.isNewEmail\">isNewEmail() (plugins.Email.Plugin 方法)</a>\n</li>\n      <li><a href=\"plugins.html#plugins.Email.Plugin.isSelfEmail\">isSelfEmail() (plugins.Email.Plugin 方法)</a>\n</li>\n      <li><a href=\"plugins.html#plugins.Camera.Plugin.isValid\">isValid() (plugins.Camera.Plugin 方法)</a>\n\n      <ul>\n        <li><a href=\"plugins.html#plugins.CleanCache.Plugin.isValid\">(plugins.CleanCache.Plugin 方法)</a>\n</li>\n        <li><a href=\"plugins.html#plugins.Echo.Plugin.isValid\">(plugins.Echo.Plugin 方法)</a>\n</li>\n        <li><a href=\"plugins.html#plugins.Email.Plugin.isValid\">(plugins.Email.Plugin 方法)</a>\n</li>\n        <li><a href=\"plugins.html#plugins.Geek.Plugin.isValid\">(plugins.Geek.Plugin 方法)</a>\n</li>\n        <li><a href=\"plugins.html#plugins.LocalPlayer.Plugin.isValid\">(plugins.LocalPlayer.Plugin 方法)</a>\n</li>\n        <li><a href=\"plugins.html#plugins.Poem.Plugin.isValid\">(plugins.Poem.Plugin 方法)</a>\n</li>\n        <li><a href=\"robot.sdk.html#robot.sdk.AbstractPlugin.AbstractPlugin.isValid\">(robot.sdk.AbstractPlugin.AbstractPlugin 方法)</a>\n</li>\n      </ul></li>\n      <li><a href=\"plugins.html#plugins.Geek.Plugin.isValidImmersive\">isValidImmersive() (plugins.Geek.Plugin 方法)</a>\n\n      <ul>\n        <li><a href=\"plugins.html#plugins.LocalPlayer.Plugin.isValidImmersive\">(plugins.LocalPlayer.Plugin 方法)</a>\n</li>\n        <li><a href=\"robot.sdk.html#robot.sdk.AbstractPlugin.AbstractPlugin.isValidImmersive\">(robot.sdk.AbstractPlugin.AbstractPlugin 方法)</a>\n</li>\n      </ul></li>\n  </ul></td>\n</tr></table>\n\n<h2 id=\"L\">L</h2>\n<table style=\"width: 100%\" class=\"indextable genindextable\"><tr>\n  <td style=\"width: 33%; vertical-align: top;\"><ul>\n      <li><a href=\"snowboy.html#snowboy.snowboydecoder.ActiveListener.listen\">listen() (snowboy.snowboydecoder.ActiveListener 方法)</a>\n</li>\n  </ul></td>\n  <td style=\"width: 33%; vertical-align: top;\"><ul>\n      <li><a href=\"robot.html#robot.utils.lruCache\">lruCache() (在 robot.utils 模块中)</a>\n</li>\n  </ul></td>\n</tr></table>\n\n<h2 id=\"M\">M</h2>\n<table style=\"width: 100%\" class=\"indextable genindextable\"><tr>\n  <td style=\"width: 33%; vertical-align: top;\"><ul>\n      <li><a href=\"wukong.html#wukong.Wukong.md5\">md5() (wukong.Wukong 方法)</a>\n</li>\n  </ul></td>\n  <td style=\"width: 33%; vertical-align: top;\"><ul>\n      <li><a href=\"robot.html#robot.Player.MusicPlayer\">MusicPlayer (robot.Player 中的类)</a>\n</li>\n  </ul></td>\n</tr></table>\n\n<h2 id=\"N\">N</h2>\n<table style=\"width: 100%\" class=\"indextable genindextable\"><tr>\n  <td style=\"width: 33%; vertical-align: top;\"><ul>\n      <li><a href=\"robot.html#robot.constants.newConfig\">newConfig() (在 robot.constants 模块中)</a>\n</li>\n      <li><a href=\"robot.html#robot.Player.MusicPlayer.next\">next() (robot.Player.MusicPlayer 方法)</a>\n</li>\n      <li><a href=\"robot.html#robot.Player.no_alsa_error\">no_alsa_error() (在 robot.Player 模块中)</a>\n\n      <ul>\n        <li><a href=\"snowboy.html#snowboy.snowboydecoder.no_alsa_error\">(在 snowboy.snowboydecoder 模块中)</a>\n</li>\n      </ul></li>\n  </ul></td>\n  <td style=\"width: 33%; vertical-align: top;\"><ul>\n      <li><a href=\"snowboy.html#snowboy.snowboydetect.SnowboyDetect.NumChannels\">NumChannels() (snowboy.snowboydetect.SnowboyDetect 方法)</a>\n\n      <ul>\n        <li><a href=\"snowboy.html#snowboy.snowboydetect.SnowboyVad.NumChannels\">(snowboy.snowboydetect.SnowboyVad 方法)</a>\n</li>\n      </ul></li>\n      <li><a href=\"snowboy.html#snowboy.snowboydetect.SnowboyDetect.NumHotwords\">NumHotwords() (snowboy.snowboydetect.SnowboyDetect 方法)</a>\n</li>\n  </ul></td>\n</tr></table>\n\n<h2 id=\"O\">O</h2>\n<table style=\"width: 100%\" class=\"indextable genindextable\"><tr>\n  <td style=\"width: 33%; vertical-align: top;\"><ul>\n      <li><a href=\"robot.sdk.html#robot.sdk.XunfeiSpeech.on_close\">on_close() (在 robot.sdk.XunfeiSpeech 模块中)</a>\n</li>\n      <li><a href=\"robot.sdk.html#robot.sdk.XunfeiSpeech.on_error\">on_error() (在 robot.sdk.XunfeiSpeech 模块中)</a>\n</li>\n      <li><a href=\"robot.sdk.html#robot.sdk.XunfeiSpeech.on_message\">on_message() (在 robot.sdk.XunfeiSpeech 模块中)</a>\n</li>\n  </ul></td>\n  <td style=\"width: 33%; vertical-align: top;\"><ul>\n      <li><a href=\"robot.html#robot.ConfigMonitor.ConfigMonitor.on_modified\">on_modified() (robot.ConfigMonitor.ConfigMonitor 方法)</a>\n</li>\n      <li><a href=\"robot.sdk.html#robot.sdk.XunfeiSpeech.on_open\">on_open() (在 robot.sdk.XunfeiSpeech 模块中)</a>\n</li>\n      <li><a href=\"plugins.html#plugins.Geek.Plugin.onAsk\">onAsk() (plugins.Geek.Plugin 方法)</a>\n</li>\n      <li><a href=\"robot.sdk.html#robot.sdk.TencentSpeech.tencentSpeech.oneSentenceRecognition\">oneSentenceRecognition() (robot.sdk.TencentSpeech.tencentSpeech 方法)</a>\n</li>\n  </ul></td>\n</tr></table>\n\n<h2 id=\"P\">P</h2>\n<table style=\"width: 100%\" class=\"indextable genindextable\"><tr>\n  <td style=\"width: 33%; vertical-align: top;\"><ul>\n      <li><a href=\"robot.html#robot.Conversation.Conversation.pardon\">pardon() (robot.Conversation.Conversation 方法)</a>\n</li>\n      <li><a href=\"robot.html#robot.NLU.AbstractNLU.parse\">parse() (robot.NLU.AbstractNLU 方法)</a>\n\n      <ul>\n        <li><a href=\"robot.html#robot.NLU.UnitNLU.parse\">(robot.NLU.UnitNLU 方法)</a>\n</li>\n      </ul></li>\n      <li><a href=\"plugins.html#plugins.LocalPlayer.Plugin.pause\">pause() (plugins.LocalPlayer.Plugin 方法)</a>\n\n      <ul>\n        <li><a href=\"robot.html#robot.Brain.Brain.pause\">(robot.Brain.Brain 方法)</a>\n</li>\n        <li><a href=\"robot.html#robot.Player.MusicPlayer.pause\">(robot.Player.MusicPlayer 方法)</a>\n</li>\n        <li><a href=\"robot.sdk.html#robot.sdk.AbstractPlugin.AbstractPlugin.pause\">(robot.sdk.AbstractPlugin.AbstractPlugin 方法)</a>\n</li>\n      </ul></li>\n      <li><a href=\"robot.html#robot.Conversation.Conversation.play\">play() (robot.Conversation.Conversation 方法)</a>\n\n      <ul>\n        <li><a href=\"robot.html#robot.Player.AbstractPlayer.play\">(robot.Player.AbstractPlayer 方法)</a>\n</li>\n        <li><a href=\"robot.html#robot.Player.MusicPlayer.play\">(robot.Player.MusicPlayer 方法)</a>\n</li>\n        <li><a href=\"robot.html#robot.Player.SoxPlayer.play\">(robot.Player.SoxPlayer 方法)</a>\n</li>\n        <li><a href=\"robot.sdk.html#robot.sdk.AbstractPlugin.AbstractPlugin.play\">(robot.sdk.AbstractPlugin.AbstractPlugin 方法)</a>\n</li>\n        <li><a href=\"robot.html#robot.Player.play\">(在 robot.Player 模块中)</a>\n</li>\n      </ul></li>\n      <li><a href=\"snowboy.html#snowboy.snowboydecoder.play_audio_file\">play_audio_file() (在 snowboy.snowboydecoder 模块中)</a>\n</li>\n      <li><a href=\"robot.html#robot.Player.AbstractPlayer.play_block\">play_block() (robot.Player.AbstractPlayer 方法)</a>\n\n      <ul>\n        <li><a href=\"robot.html#robot.Player.SoxPlayer.play_block\">(robot.Player.SoxPlayer 方法)</a>\n</li>\n      </ul></li>\n      <li><a href=\"plugins.html#plugins.Camera.Plugin\">Plugin (plugins.Camera 中的类)</a>\n\n      <ul>\n        <li><a href=\"plugins.html#plugins.CleanCache.Plugin\">(plugins.CleanCache 中的类)</a>\n</li>\n        <li><a href=\"plugins.html#plugins.Echo.Plugin\">(plugins.Echo 中的类)</a>\n</li>\n        <li><a href=\"plugins.html#plugins.Email.Plugin\">(plugins.Email 中的类)</a>\n</li>\n        <li><a href=\"plugins.html#plugins.Geek.Plugin\">(plugins.Geek 中的类)</a>\n</li>\n        <li><a href=\"plugins.html#plugins.LocalPlayer.Plugin\">(plugins.LocalPlayer 中的类)</a>\n</li>\n        <li><a href=\"plugins.html#plugins.Poem.Plugin\">(plugins.Poem 中的类)</a>\n</li>\n      </ul></li>\n  </ul></td>\n  <td style=\"width: 33%; vertical-align: top;\"><ul>\n      <li><a href=\"plugins.html#module-plugins\">plugins (模块)</a>\n</li>\n      <li><a href=\"plugins.html#module-plugins.Camera\">plugins.Camera (模块)</a>\n</li>\n      <li><a href=\"plugins.html#module-plugins.CleanCache\">plugins.CleanCache (模块)</a>\n</li>\n      <li><a href=\"plugins.html#module-plugins.Echo\">plugins.Echo (模块)</a>\n</li>\n      <li><a href=\"plugins.html#module-plugins.Email\">plugins.Email (模块)</a>\n</li>\n      <li><a href=\"plugins.html#module-plugins.Geek\">plugins.Geek (模块)</a>\n</li>\n      <li><a href=\"plugins.html#module-plugins.LocalPlayer\">plugins.LocalPlayer (模块)</a>\n</li>\n      <li><a href=\"plugins.html#module-plugins.Poem\">plugins.Poem (模块)</a>\n</li>\n      <li><a href=\"robot.html#robot.Player.MusicPlayer.prev\">prev() (robot.Player.MusicPlayer 方法)</a>\n</li>\n      <li><a href=\"robot.sdk.html#robot.sdk.TencentSpeech.tencentSpeech.PrimaryLanguage\">PrimaryLanguage (robot.sdk.TencentSpeech.tencentSpeech 属性)</a>\n</li>\n      <li><a href=\"robot.sdk.html#robot.sdk.TencentSpeech.tencentSpeech.primarylanguage\">primarylanguage (robot.sdk.TencentSpeech.tencentSpeech 属性)</a>\n</li>\n      <li><a href=\"robot.html#robot.Brain.Brain.printPlugins\">printPlugins() (robot.Brain.Brain 方法)</a>\n</li>\n      <li><a href=\"robot.sdk.html#robot.sdk.AliSpeech.process\">process() (在 robot.sdk.AliSpeech 模块中)</a>\n</li>\n      <li><a href=\"robot.sdk.html#robot.sdk.AliSpeech.processGETRequest\">processGETRequest() (在 robot.sdk.AliSpeech 模块中)</a>\n</li>\n      <li><a href=\"robot.sdk.html#robot.sdk.AliSpeech.processPOSTRequest\">processPOSTRequest() (在 robot.sdk.AliSpeech 模块中)</a>\n</li>\n      <li><a href=\"wukong.html#wukong.Wukong.profiling\">profiling() (wukong.Wukong 方法)</a>\n</li>\n      <li><a href=\"robot.html#robot.Player.py_error_handler\">py_error_handler() (在 robot.Player 模块中)</a>\n\n      <ul>\n        <li><a href=\"snowboy.html#snowboy.snowboydecoder.py_error_handler\">(在 snowboy.snowboydecoder 模块中)</a>\n</li>\n      </ul></li>\n  </ul></td>\n</tr></table>\n\n<h2 id=\"Q\">Q</h2>\n<table style=\"width: 100%\" class=\"indextable genindextable\"><tr>\n  <td style=\"width: 33%; vertical-align: top;\"><ul>\n      <li><a href=\"robot.html#robot.Brain.Brain.query\">query() (robot.Brain.Brain 方法)</a>\n</li>\n  </ul></td>\n</tr></table>\n\n<h2 id=\"R\">R</h2>\n<table style=\"width: 100%\" class=\"indextable genindextable\"><tr>\n  <td style=\"width: 33%; vertical-align: top;\"><ul>\n      <li><a href=\"robot.sdk.html#robot.sdk.RASRsdk.randstr\">randstr() (在 robot.sdk.RASRsdk 模块中)</a>\n</li>\n      <li><a href=\"robot.html#robot.logging.readLog\">readLog() (在 robot.logging 模块中)</a>\n</li>\n      <li><a href=\"robot.sdk.html#robot.sdk.TencentSpeech.tencentSpeech.Region\">Region (robot.sdk.TencentSpeech.tencentSpeech 属性)</a>\n</li>\n      <li><a href=\"robot.sdk.html#robot.sdk.TencentSpeech.tencentSpeech.region\">region (robot.sdk.TencentSpeech.tencentSpeech 属性)</a>\n</li>\n      <li><a href=\"robot.html#robot.Conversation.Conversation.reload\">reload() (robot.Conversation.Conversation 方法)</a>\n\n      <ul>\n        <li><a href=\"robot.html#robot.config.reload\">(在 robot.config 模块中)</a>\n</li>\n      </ul></li>\n      <li><a href=\"robot.html#robot.statistic.report\">report() (在 robot.statistic 模块中)</a>\n</li>\n      <li><a href=\"robot.html#robot.statistic.ReportThread\">ReportThread (robot.statistic 中的类)</a>\n</li>\n      <li><a href=\"snowboy.html#snowboy.snowboydetect.SnowboyDetect.Reset\">Reset() (snowboy.snowboydetect.SnowboyDetect 方法)</a>\n\n      <ul>\n        <li><a href=\"snowboy.html#snowboy.snowboydetect.SnowboyVad.Reset\">(snowboy.snowboydetect.SnowboyVad 方法)</a>\n</li>\n      </ul></li>\n      <li><a href=\"wukong.html#wukong.Wukong.restart\">restart() (wukong.Wukong 方法)</a>\n</li>\n      <li><a href=\"plugins.html#plugins.Geek.Plugin.restore\">restore() (plugins.Geek.Plugin 方法)</a>\n\n      <ul>\n        <li><a href=\"plugins.html#plugins.LocalPlayer.Plugin.restore\">(plugins.LocalPlayer.Plugin 方法)</a>\n</li>\n        <li><a href=\"robot.html#robot.Brain.Brain.restore\">(robot.Brain.Brain 方法)</a>\n</li>\n        <li><a href=\"robot.sdk.html#robot.sdk.AbstractPlugin.AbstractPlugin.restore\">(robot.sdk.AbstractPlugin.AbstractPlugin 方法)</a>\n</li>\n      </ul></li>\n      <li><a href=\"robot.html#robot.Player.MusicPlayer.resume\">resume() (robot.Player.MusicPlayer 方法)</a>\n</li>\n      <li><a href=\"snowboy.html#snowboy.snowboydecoder.RingBuffer\">RingBuffer (snowboy.snowboydecoder 中的类)</a>\n</li>\n      <li><a href=\"robot.html#module-robot\">robot (模块)</a>\n</li>\n      <li><a href=\"robot.html#module-robot.AI\">robot.AI (模块)</a>\n</li>\n      <li><a href=\"robot.html#module-robot.ASR\">robot.ASR (模块)</a>\n</li>\n      <li><a href=\"robot.html#module-robot.Brain\">robot.Brain (模块)</a>\n</li>\n      <li><a href=\"robot.html#module-robot.config\">robot.config (模块)</a>\n</li>\n  </ul></td>\n  <td style=\"width: 33%; vertical-align: top;\"><ul>\n      <li><a href=\"robot.html#module-robot.ConfigMonitor\">robot.ConfigMonitor (模块)</a>\n</li>\n      <li><a href=\"robot.html#module-robot.constants\">robot.constants (模块)</a>\n</li>\n      <li><a href=\"robot.html#module-robot.Conversation\">robot.Conversation (模块)</a>\n</li>\n      <li><a href=\"robot.drivers.html#module-robot.drivers\">robot.drivers (模块)</a>\n</li>\n      <li><a href=\"robot.html#module-robot.logging\">robot.logging (模块)</a>\n</li>\n      <li><a href=\"robot.html#module-robot.NLU\">robot.NLU (模块)</a>\n</li>\n      <li><a href=\"robot.html#module-robot.Player\">robot.Player (模块)</a>\n</li>\n      <li><a href=\"robot.html#module-robot.plugin_loader\">robot.plugin_loader (模块)</a>\n</li>\n      <li><a href=\"robot.sdk.html#module-robot.sdk\">robot.sdk (模块)</a>\n</li>\n      <li><a href=\"robot.sdk.html#module-robot.sdk.AbstractPlugin\">robot.sdk.AbstractPlugin (模块)</a>\n</li>\n      <li><a href=\"robot.sdk.html#module-robot.sdk.AliSpeech\">robot.sdk.AliSpeech (模块)</a>\n</li>\n      <li><a href=\"robot.sdk.html#module-robot.sdk.RASRsdk\">robot.sdk.RASRsdk (模块)</a>\n</li>\n      <li><a href=\"robot.sdk.html#module-robot.sdk.TencentSpeech\">robot.sdk.TencentSpeech (模块)</a>\n</li>\n      <li><a href=\"robot.sdk.html#module-robot.sdk.unit\">robot.sdk.unit (模块)</a>\n</li>\n      <li><a href=\"robot.sdk.html#module-robot.sdk.XunfeiSpeech\">robot.sdk.XunfeiSpeech (模块)</a>\n</li>\n      <li><a href=\"robot.html#module-robot.statistic\">robot.statistic (模块)</a>\n</li>\n      <li><a href=\"robot.html#module-robot.TTS\">robot.TTS (模块)</a>\n</li>\n      <li><a href=\"robot.html#module-robot.Updater\">robot.Updater (模块)</a>\n</li>\n      <li><a href=\"robot.html#module-robot.utils\">robot.utils (模块)</a>\n</li>\n      <li><a href=\"robot.html#robot.statistic.ReportThread.run\">run() (robot.statistic.ReportThread 方法)</a>\n\n      <ul>\n        <li><a href=\"wukong.html#wukong.Wukong.run\">(wukong.Wukong 方法)</a>\n</li>\n      </ul></li>\n      <li><a href=\"snowboy.html#snowboy.snowboydetect.SnowboyDetect.RunDetection\">RunDetection() (snowboy.snowboydetect.SnowboyDetect 方法)</a>\n</li>\n      <li><a href=\"snowboy.html#snowboy.snowboydetect.SnowboyVad.RunVad\">RunVad() (snowboy.snowboydetect.SnowboyVad 方法)</a>\n</li>\n  </ul></td>\n</tr></table>\n\n<h2 id=\"S\">S</h2>\n<table style=\"width: 100%\" class=\"indextable genindextable\"><tr>\n  <td style=\"width: 33%; vertical-align: top;\"><ul>\n      <li><a href=\"snowboy.html#snowboy.snowboydetect.SnowboyDetect.SampleRate\">SampleRate() (snowboy.snowboydetect.SnowboyDetect 方法)</a>\n\n      <ul>\n        <li><a href=\"snowboy.html#snowboy.snowboydetect.SnowboyVad.SampleRate\">(snowboy.snowboydetect.SnowboyVad 方法)</a>\n</li>\n      </ul></li>\n      <li><a href=\"robot.html#robot.utils.saveCache\">saveCache() (在 robot.utils 模块中)</a>\n</li>\n      <li><a href=\"snowboy.html#snowboy.snowboydecoder.ActiveListener.saveMessage\">saveMessage() (snowboy.snowboydecoder.ActiveListener 方法)</a>\n\n      <ul>\n        <li><a href=\"snowboy.html#snowboy.snowboydecoder.HotwordDetector.saveMessage\">(snowboy.snowboydecoder.HotwordDetector 方法)</a>\n</li>\n      </ul></li>\n      <li><a href=\"robot.html#robot.Brain.Brain.say\">say() (robot.Brain.Brain 方法)</a>\n\n      <ul>\n        <li><a href=\"robot.html#robot.Conversation.Conversation.say\">(robot.Conversation.Conversation 方法)</a>\n</li>\n        <li><a href=\"robot.sdk.html#robot.sdk.AbstractPlugin.AbstractPlugin.say\">(robot.sdk.AbstractPlugin.AbstractPlugin 方法)</a>\n</li>\n      </ul></li>\n      <li><a href=\"robot.sdk.html#robot.sdk.TencentSpeech.tencentSpeech.SECRET_ID\">SECRET_ID (robot.sdk.TencentSpeech.tencentSpeech 属性)</a>\n</li>\n      <li><a href=\"robot.sdk.html#robot.sdk.TencentSpeech.tencentSpeech.secret_id\">secret_id (robot.sdk.TencentSpeech.tencentSpeech 属性)</a>\n</li>\n      <li><a href=\"robot.sdk.html#robot.sdk.TencentSpeech.tencentSpeech.SECRET_KEY\">SECRET_KEY (robot.sdk.TencentSpeech.tencentSpeech 属性)</a>\n</li>\n      <li><a href=\"robot.sdk.html#robot.sdk.TencentSpeech.tencentSpeech.secret_key\">secret_key (robot.sdk.TencentSpeech.tencentSpeech 属性)</a>\n</li>\n      <li><a href=\"robot.html#robot.utils.sendEmail\">sendEmail() (在 robot.utils 模块中)</a>\n</li>\n      <li><a href=\"robot.sdk.html#robot.sdk.RASRsdk.sendVoice\">sendVoice() (在 robot.sdk.RASRsdk 模块中)</a>\n</li>\n      <li><a href=\"snowboy.html#snowboy.snowboydetect.SnowboyDetect.SetAudioGain\">SetAudioGain() (snowboy.snowboydetect.SnowboyDetect 方法)</a>\n\n      <ul>\n        <li><a href=\"snowboy.html#snowboy.snowboydetect.SnowboyVad.SetAudioGain\">(snowboy.snowboydetect.SnowboyVad 方法)</a>\n</li>\n      </ul></li>\n      <li><a href=\"snowboy.html#snowboy.snowboydetect.SnowboyDetect.SetHighSensitivity\">SetHighSensitivity() (snowboy.snowboydetect.SnowboyDetect 方法)</a>\n</li>\n      <li><a href=\"robot.html#robot.Conversation.Conversation.setImmersiveMode\">setImmersiveMode() (robot.Conversation.Conversation 方法)</a>\n</li>\n      <li><a href=\"snowboy.html#snowboy.snowboydetect.SnowboyDetect.SetSensitivity\">SetSensitivity() (snowboy.snowboydetect.SnowboyDetect 方法)</a>\n</li>\n      <li><a href=\"robot.sdk.html#robot.sdk.RASRsdk.sign\">sign() (在 robot.sdk.RASRsdk 模块中)</a>\n</li>\n      <li><a href=\"plugins.html#plugins.Camera.Plugin.SLUG\">SLUG (plugins.Camera.Plugin 属性)</a>\n\n      <ul>\n        <li><a href=\"plugins.html#plugins.CleanCache.Plugin.SLUG\">(plugins.CleanCache.Plugin 属性)</a>\n</li>\n        <li><a href=\"plugins.html#plugins.Email.Plugin.SLUG\">(plugins.Email.Plugin 属性)</a>\n</li>\n        <li><a href=\"plugins.html#plugins.Poem.Plugin.SLUG\">(plugins.Poem.Plugin 属性)</a>\n</li>\n        <li><a href=\"robot.html#robot.AI.Emotibot.SLUG\">(robot.AI.Emotibot 属性)</a>\n</li>\n        <li><a href=\"robot.html#robot.AI.TulingRobot.SLUG\">(robot.AI.TulingRobot 属性)</a>\n</li>\n        <li><a href=\"robot.html#robot.ASR.AliASR.SLUG\">(robot.ASR.AliASR 属性)</a>\n</li>\n        <li><a href=\"robot.html#robot.ASR.BaiduASR.SLUG\">(robot.ASR.BaiduASR 属性)</a>\n</li>\n        <li><a href=\"robot.html#robot.ASR.TencentASR.SLUG\">(robot.ASR.TencentASR 属性)</a>\n</li>\n        <li><a href=\"robot.html#robot.ASR.XunfeiASR.SLUG\">(robot.ASR.XunfeiASR 属性)</a>\n</li>\n        <li><a href=\"robot.html#robot.NLU.UnitNLU.SLUG\">(robot.NLU.UnitNLU 属性)</a>\n</li>\n        <li><a href=\"robot.html#robot.Player.MusicPlayer.SLUG\">(robot.Player.MusicPlayer 属性)</a>\n</li>\n        <li><a href=\"robot.html#robot.Player.SoxPlayer.SLUG\">(robot.Player.SoxPlayer 属性)</a>\n</li>\n        <li><a href=\"robot.html#robot.TTS.AliTTS.SLUG\">(robot.TTS.AliTTS 属性)</a>\n</li>\n        <li><a href=\"robot.html#robot.TTS.BaiduTTS.SLUG\">(robot.TTS.BaiduTTS 属性)</a>\n</li>\n        <li><a href=\"robot.html#robot.TTS.TencentTTS.SLUG\">(robot.TTS.TencentTTS 属性)</a>\n</li>\n        <li><a href=\"robot.html#robot.TTS.XunfeiTTS.SLUG\">(robot.TTS.XunfeiTTS 属性)</a>\n</li>\n        <li><a href=\"robot.sdk.html#robot.sdk.AbstractPlugin.AbstractPlugin.SLUG\">(robot.sdk.AbstractPlugin.AbstractPlugin 属性)</a>\n</li>\n      </ul></li>\n  </ul></td>\n  <td style=\"width: 33%; vertical-align: top;\"><ul>\n      <li><a href=\"snowboy.html#module-snowboy\">snowboy (模块)</a>\n</li>\n      <li><a href=\"snowboy.html#module-snowboy.snowboydecoder\">snowboy.snowboydecoder (模块)</a>\n</li>\n      <li><a href=\"snowboy.html#module-snowboy.snowboydetect\">snowboy.snowboydetect (模块)</a>\n</li>\n      <li><a href=\"snowboy.html#snowboy.snowboydetect.SnowboyDetect\">SnowboyDetect (snowboy.snowboydetect 中的类)</a>\n</li>\n      <li><a href=\"snowboy.html#snowboy.snowboydetect.SnowboyVad\">SnowboyVad (snowboy.snowboydetect 中的类)</a>\n</li>\n      <li><a href=\"robot.sdk.html#robot.sdk.TencentSpeech.tencentSpeech.source_type\">source_type (robot.sdk.TencentSpeech.tencentSpeech 属性)</a>\n</li>\n      <li><a href=\"robot.sdk.html#robot.sdk.TencentSpeech.tencentSpeech.SourceType\">SourceType (robot.sdk.TencentSpeech.tencentSpeech 属性)</a>\n</li>\n      <li><a href=\"robot.html#robot.Player.SoxPlayer\">SoxPlayer (robot.Player 中的类)</a>\n</li>\n      <li><a href=\"snowboy.html#snowboy.snowboydecoder.HotwordDetector.start\">start() (snowboy.snowboydecoder.HotwordDetector 方法)</a>\n</li>\n      <li><a href=\"robot.html#robot.Player.AbstractPlayer.stop\">stop() (robot.Player.AbstractPlayer 方法)</a>\n\n      <ul>\n        <li><a href=\"robot.html#robot.Player.MusicPlayer.stop\">(robot.Player.MusicPlayer 方法)</a>\n</li>\n        <li><a href=\"robot.html#robot.Player.SoxPlayer.stop\">(robot.Player.SoxPlayer 方法)</a>\n</li>\n      </ul></li>\n  </ul></td>\n</tr></table>\n\n<h2 id=\"T\">T</h2>\n<table style=\"width: 100%\" class=\"indextable genindextable\"><tr>\n  <td style=\"width: 33%; vertical-align: top;\"><ul>\n      <li><a href=\"robot.html#robot.logging.tail\">tail() (在 robot.logging 模块中)</a>\n</li>\n      <li><a href=\"robot.html#robot.ASR.TencentASR\">TencentASR (robot.ASR 中的类)</a>\n</li>\n      <li><a href=\"robot.sdk.html#robot.sdk.TencentSpeech.tencentSpeech\">tencentSpeech (robot.sdk.TencentSpeech 中的类)</a>\n</li>\n      <li><a href=\"robot.html#robot.TTS.TencentTTS\">TencentTTS (robot.TTS 中的类)</a>\n</li>\n      <li><a href=\"snowboy.html#snowboy.snowboydecoder.HotwordDetector.terminate\">terminate() (snowboy.snowboydecoder.HotwordDetector 方法)</a>\n</li>\n      <li><a href=\"robot.sdk.html#robot.sdk.TencentSpeech.tencentSpeech.Text\">Text (robot.sdk.TencentSpeech.tencentSpeech 属性)</a>\n</li>\n      <li><a href=\"robot.sdk.html#robot.sdk.TencentSpeech.tencentSpeech.text\">text (robot.sdk.TencentSpeech.tencentSpeech 属性)</a>\n</li>\n      <li><a href=\"robot.sdk.html#robot.sdk.TencentSpeech.tencentSpeech.textToSpeech\">textToSpeech() (robot.sdk.TencentSpeech.tencentSpeech 方法)</a>\n</li>\n      <li><a href=\"robot.html#robot.ASR.AbstractASR.transcribe\">transcribe() (robot.ASR.AbstractASR 方法)</a>\n\n      <ul>\n        <li><a href=\"robot.html#robot.ASR.AliASR.transcribe\">(robot.ASR.AliASR 方法)</a>\n</li>\n        <li><a href=\"robot.html#robot.ASR.BaiduASR.transcribe\">(robot.ASR.BaiduASR 方法)</a>\n</li>\n        <li><a href=\"robot.html#robot.ASR.TencentASR.transcribe\">(robot.ASR.TencentASR 方法)</a>\n</li>\n        <li><a href=\"robot.html#robot.ASR.XunfeiASR.transcribe\">(robot.ASR.XunfeiASR 方法)</a>\n</li>\n        <li><a href=\"robot.sdk.html#robot.sdk.XunfeiSpeech.transcribe\">(在 robot.sdk.XunfeiSpeech 模块中)</a>\n</li>\n      </ul></li>\n  </ul></td>\n  <td style=\"width: 33%; vertical-align: top;\"><ul>\n      <li><a href=\"robot.sdk.html#robot.sdk.TencentSpeech.tencentSpeech.TTS\">TTS() (robot.sdk.TencentSpeech.tencentSpeech 方法)</a>\n</li>\n      <li><a href=\"robot.sdk.html#robot.sdk.AliSpeech.tts\">tts() (在 robot.sdk.AliSpeech 模块中)</a>\n</li>\n      <li><a href=\"robot.html#robot.AI.TulingRobot\">TulingRobot (robot.AI 中的类)</a>\n</li>\n      <li><a href=\"robot.html#robot.Player.MusicPlayer.turnDown\">turnDown() (robot.Player.MusicPlayer 方法)</a>\n</li>\n      <li><a href=\"robot.html#robot.Player.MusicPlayer.turnUp\">turnUp() (robot.Player.MusicPlayer 方法)</a>\n</li>\n  </ul></td>\n</tr></table>\n\n<h2 id=\"U\">U</h2>\n<table style=\"width: 100%\" class=\"indextable genindextable\"><tr>\n  <td style=\"width: 33%; vertical-align: top;\"><ul>\n      <li><a href=\"robot.html#robot.Brain.Brain.understand\">understand() (robot.Brain.Brain 方法)</a>\n</li>\n      <li><a href=\"robot.html#robot.NLU.UnitNLU\">UnitNLU (robot.NLU 中的类)</a>\n</li>\n      <li><a href=\"robot.html#robot.Updater.Updater.update\">update() (robot.Updater.Updater 方法)</a>\n\n      <ul>\n        <li><a href=\"wukong.html#wukong.Wukong.update\">(wukong.Wukong 方法)</a>\n</li>\n      </ul></li>\n  </ul></td>\n  <td style=\"width: 33%; vertical-align: top;\"><ul>\n      <li><a href=\"robot.html#robot.Player.MusicPlayer.update_playlist\">update_playlist() (robot.Player.MusicPlayer 方法)</a>\n</li>\n      <li><a href=\"snowboy.html#snowboy.snowboydetect.SnowboyDetect.UpdateModel\">UpdateModel() (snowboy.snowboydetect.SnowboyDetect 方法)</a>\n</li>\n      <li><a href=\"robot.html#robot.Updater.Updater\">Updater (robot.Updater 中的类)</a>\n</li>\n      <li><a href=\"robot.sdk.html#robot.sdk.TencentSpeech.tencentSpeech.URL\">URL (robot.sdk.TencentSpeech.tencentSpeech 属性)</a>\n</li>\n      <li><a href=\"robot.sdk.html#robot.sdk.TencentSpeech.tencentSpeech.url\">url (robot.sdk.TencentSpeech.tencentSpeech 属性)</a>\n</li>\n  </ul></td>\n</tr></table>\n\n<h2 id=\"V\">V</h2>\n<table style=\"width: 100%\" class=\"indextable genindextable\"><tr>\n  <td style=\"width: 33%; vertical-align: top;\"><ul>\n      <li><a href=\"robot.sdk.html#robot.sdk.TencentSpeech.tencentSpeech.VoiceFormat\">VoiceFormat (robot.sdk.TencentSpeech.tencentSpeech 属性)</a>\n</li>\n      <li><a href=\"robot.sdk.html#robot.sdk.TencentSpeech.tencentSpeech.voiceformat\">voiceformat (robot.sdk.TencentSpeech.tencentSpeech 属性)</a>\n</li>\n  </ul></td>\n  <td style=\"width: 33%; vertical-align: top;\"><ul>\n      <li><a href=\"robot.sdk.html#robot.sdk.TencentSpeech.tencentSpeech.VoiceType\">VoiceType (robot.sdk.TencentSpeech.tencentSpeech 属性)</a>\n</li>\n      <li><a href=\"robot.sdk.html#robot.sdk.TencentSpeech.tencentSpeech.voicetype\">voicetype (robot.sdk.TencentSpeech.tencentSpeech 属性)</a>\n</li>\n  </ul></td>\n</tr></table>\n\n<h2 id=\"W\">W</h2>\n<table style=\"width: 100%\" class=\"indextable genindextable\"><tr>\n  <td style=\"width: 33%; vertical-align: top;\"><ul>\n      <li><a href=\"robot.html#robot.utils.write_temp_file\">write_temp_file() (在 robot.utils 模块中)</a>\n</li>\n      <li><a href=\"robot.sdk.html#robot.sdk.XunfeiSpeech.Ws_Param\">Ws_Param (robot.sdk.XunfeiSpeech 中的类)</a>\n</li>\n  </ul></td>\n  <td style=\"width: 33%; vertical-align: top;\"><ul>\n      <li><a href=\"wukong.html#wukong.Wukong\">Wukong (wukong 中的类)</a>\n</li>\n      <li><a href=\"index.html#module-wukong\">wukong (模块)</a>, <a href=\"wukong.html#module-wukong\">[1]</a>\n</li>\n  </ul></td>\n</tr></table>\n\n<h2 id=\"X\">X</h2>\n<table style=\"width: 100%\" class=\"indextable genindextable\"><tr>\n  <td style=\"width: 33%; vertical-align: top;\"><ul>\n      <li><a href=\"robot.html#robot.ASR.XunfeiASR\">XunfeiASR (robot.ASR 中的类)</a>\n</li>\n  </ul></td>\n  <td style=\"width: 33%; vertical-align: top;\"><ul>\n      <li><a href=\"robot.html#robot.TTS.XunfeiTTS\">XunfeiTTS (robot.TTS 中的类)</a>\n</li>\n  </ul></td>\n</tr></table>\n\n\n\n           </div>\n           \n          </div>\n          <footer>\n  \n\n  <hr/>\n\n  <div role=\"contentinfo\">\n    <p>\n        &copy; Copyright 2019, wzpan\n\n    </p>\n  </div>\n  Built with <a href=\"http://sphinx-doc.org/\">Sphinx</a> using a <a href=\"https://github.com/rtfd/sphinx_rtd_theme\">theme</a> provided by <a href=\"https://readthedocs.org\">Read the Docs</a>. \n\n</footer>\n\n        </div>\n      </div>\n\n    </section>\n\n  </div>\n  \n\n\n  <script type=\"text/javascript\">\n      jQuery(function () {\n          SphinxRtdTheme.Navigation.enable(true);\n      });\n  </script>\n\n  \n  \n    \n   \n\n</body>\n</html>"
  },
  {
    "path": "docs/index.html",
    "content": "\n\n<!DOCTYPE html>\n<!--[if IE 8]><html class=\"no-js lt-ie9\" lang=\"zh-CN\" > <![endif]-->\n<!--[if gt IE 8]><!--> <html class=\"no-js\" lang=\"zh-CN\" > <!--<![endif]-->\n<head>\n  <meta charset=\"utf-8\">\n  \n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  \n  <title>Welcome to wukong-robot’s documentation! &mdash; wukong-robot 1.2.0 文档</title>\n  \n\n  \n  \n  \n  \n\n  \n  <script type=\"text/javascript\" src=\"_static/js/modernizr.min.js\"></script>\n  \n    \n      <script type=\"text/javascript\" id=\"documentation_options\" data-url_root=\"./\" src=\"_static/documentation_options.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/jquery.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/underscore.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/doctools.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/language_data.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/translations.js\"></script>\n    \n    <script type=\"text/javascript\" src=\"_static/js/theme.js\"></script>\n\n    \n\n  \n  <link rel=\"stylesheet\" href=\"_static/css/theme.css\" type=\"text/css\" />\n  <link rel=\"stylesheet\" href=\"_static/pygments.css\" type=\"text/css\" />\n    <link rel=\"index\" title=\"索引\" href=\"genindex.html\" />\n    <link rel=\"search\" title=\"搜索\" href=\"search.html\" /> \n</head>\n\n<body class=\"wy-body-for-nav\">\n\n   \n  <div class=\"wy-grid-for-nav\">\n    \n    <nav data-toggle=\"wy-nav-shift\" class=\"wy-nav-side\">\n      <div class=\"wy-side-scroll\">\n        <div class=\"wy-side-nav-search\" >\n          \n\n          \n            <a href=\"#\" class=\"icon icon-home\"> wukong-robot\n          \n\n          \n          </a>\n\n          \n            \n            \n          \n\n          \n<div role=\"search\">\n  <form id=\"rtd-search-form\" class=\"wy-form\" action=\"search.html\" method=\"get\">\n    <input type=\"text\" name=\"q\" placeholder=\"Search docs\" />\n    <input type=\"hidden\" name=\"check_keywords\" value=\"yes\" />\n    <input type=\"hidden\" name=\"area\" value=\"default\" />\n  </form>\n</div>\n\n          \n        </div>\n\n        <div class=\"wy-menu wy-menu-vertical\" data-spy=\"affix\" role=\"navigation\" aria-label=\"main navigation\">\n          \n            \n            \n              \n            \n            \n              <!-- Local TOC -->\n              <div class=\"local-toc\"><ul>\n<li><a class=\"reference internal\" href=\"#\">Welcome to wukong-robot’s documentation!</a></li>\n<li><a class=\"reference internal\" href=\"#indices-and-tables\">Indices and tables</a></li>\n</ul>\n</div>\n            \n          \n        </div>\n      </div>\n    </nav>\n\n    <section data-toggle=\"wy-nav-shift\" class=\"wy-nav-content-wrap\">\n\n      \n      <nav class=\"wy-nav-top\" aria-label=\"top navigation\">\n        \n          <i data-toggle=\"wy-nav-top\" class=\"fa fa-bars\"></i>\n          <a href=\"#\">wukong-robot</a>\n        \n      </nav>\n\n\n      <div class=\"wy-nav-content\">\n        \n        <div class=\"rst-content\">\n        \n          \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<div role=\"navigation\" aria-label=\"breadcrumbs navigation\">\n\n  <ul class=\"wy-breadcrumbs\">\n    \n      <li><a href=\"#\">Docs</a> &raquo;</li>\n        \n      <li>Welcome to wukong-robot’s documentation!</li>\n    \n    \n      <li class=\"wy-breadcrumbs-aside\">\n        \n            \n            <a href=\"_sources/index.rst.txt\" rel=\"nofollow\"> View page source</a>\n          \n        \n      </li>\n    \n  </ul>\n\n  \n  <hr/>\n</div>\n          <div role=\"main\" class=\"document\" itemscope=\"itemscope\" itemtype=\"http://schema.org/Article\">\n           <div itemprop=\"articleBody\">\n            \n  <div class=\"section\" id=\"welcome-to-wukong-robot-s-documentation\">\n<h1>Welcome to wukong-robot’s documentation!<a class=\"headerlink\" href=\"#welcome-to-wukong-robot-s-documentation\" title=\"永久链接至标题\">¶</a></h1>\n<div class=\"toctree-wrapper compound\">\n</div>\n<span class=\"target\" id=\"module-wukong\"></span></div>\n<div class=\"section\" id=\"indices-and-tables\">\n<h1>Indices and tables<a class=\"headerlink\" href=\"#indices-and-tables\" title=\"永久链接至标题\">¶</a></h1>\n<ul class=\"simple\">\n<li><a class=\"reference internal\" href=\"genindex.html\"><span class=\"std std-ref\">索引</span></a></li>\n<li><a class=\"reference internal\" href=\"py-modindex.html\"><span class=\"std std-ref\">模块索引</span></a></li>\n<li><a class=\"reference internal\" href=\"search.html\"><span class=\"std std-ref\">搜索页面</span></a></li>\n</ul>\n</div>\n\n\n           </div>\n           \n          </div>\n          <footer>\n  \n\n  <hr/>\n\n  <div role=\"contentinfo\">\n    <p>\n        &copy; Copyright 2019, wzpan\n\n    </p>\n  </div>\n  Built with <a href=\"http://sphinx-doc.org/\">Sphinx</a> using a <a href=\"https://github.com/rtfd/sphinx_rtd_theme\">theme</a> provided by <a href=\"https://readthedocs.org\">Read the Docs</a>. \n\n</footer>\n\n        </div>\n      </div>\n\n    </section>\n\n  </div>\n  \n\n\n  <script type=\"text/javascript\">\n      jQuery(function () {\n          SphinxRtdTheme.Navigation.enable(true);\n      });\n  </script>\n\n  \n  \n    \n   \n\n</body>\n</html>"
  },
  {
    "path": "docs/logging.html",
    "content": "\n\n<!DOCTYPE html>\n<!--[if IE 8]><html class=\"no-js lt-ie9\" lang=\"zh-CN\" > <![endif]-->\n<!--[if gt IE 8]><!--> <html class=\"no-js\" lang=\"zh-CN\" > <!--<![endif]-->\n<head>\n  <meta charset=\"utf-8\">\n  \n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  \n  <title>logging module &mdash; wukong-robot 1.2.0 文档</title>\n  \n\n  \n  \n  \n  \n\n  \n  <script type=\"text/javascript\" src=\"_static/js/modernizr.min.js\"></script>\n  \n    \n      <script type=\"text/javascript\" id=\"documentation_options\" data-url_root=\"./\" src=\"_static/documentation_options.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/jquery.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/underscore.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/doctools.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/language_data.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/translations.js\"></script>\n    \n    <script type=\"text/javascript\" src=\"_static/js/theme.js\"></script>\n\n    \n\n  \n  <link rel=\"stylesheet\" href=\"_static/css/theme.css\" type=\"text/css\" />\n  <link rel=\"stylesheet\" href=\"_static/pygments.css\" type=\"text/css\" />\n    <link rel=\"index\" title=\"索引\" href=\"genindex.html\" />\n    <link rel=\"search\" title=\"搜索\" href=\"search.html\" /> \n</head>\n\n<body class=\"wy-body-for-nav\">\n\n   \n  <div class=\"wy-grid-for-nav\">\n    \n    <nav data-toggle=\"wy-nav-shift\" class=\"wy-nav-side\">\n      <div class=\"wy-side-scroll\">\n        <div class=\"wy-side-nav-search\" >\n          \n\n          \n            <a href=\"index.html\" class=\"icon icon-home\"> wukong-robot\n          \n\n          \n          </a>\n\n          \n            \n            \n          \n\n          \n<div role=\"search\">\n  <form id=\"rtd-search-form\" class=\"wy-form\" action=\"search.html\" method=\"get\">\n    <input type=\"text\" name=\"q\" placeholder=\"Search docs\" />\n    <input type=\"hidden\" name=\"check_keywords\" value=\"yes\" />\n    <input type=\"hidden\" name=\"area\" value=\"default\" />\n  </form>\n</div>\n\n          \n        </div>\n\n        <div class=\"wy-menu wy-menu-vertical\" data-spy=\"affix\" role=\"navigation\" aria-label=\"main navigation\">\n          \n            \n            \n              \n            \n            \n              <!-- Local TOC -->\n              <div class=\"local-toc\"><ul>\n<li><a class=\"reference internal\" href=\"#\">logging module</a></li>\n</ul>\n</div>\n            \n          \n        </div>\n      </div>\n    </nav>\n\n    <section data-toggle=\"wy-nav-shift\" class=\"wy-nav-content-wrap\">\n\n      \n      <nav class=\"wy-nav-top\" aria-label=\"top navigation\">\n        \n          <i data-toggle=\"wy-nav-top\" class=\"fa fa-bars\"></i>\n          <a href=\"index.html\">wukong-robot</a>\n        \n      </nav>\n\n\n      <div class=\"wy-nav-content\">\n        \n        <div class=\"rst-content\">\n        \n          \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<div role=\"navigation\" aria-label=\"breadcrumbs navigation\">\n\n  <ul class=\"wy-breadcrumbs\">\n    \n      <li><a href=\"index.html\">Docs</a> &raquo;</li>\n        \n      <li>logging module</li>\n    \n    \n      <li class=\"wy-breadcrumbs-aside\">\n        \n            \n            <a href=\"_sources/logging.rst.txt\" rel=\"nofollow\"> View page source</a>\n          \n        \n      </li>\n    \n  </ul>\n\n  \n  <hr/>\n</div>\n          <div role=\"main\" class=\"document\" itemscope=\"itemscope\" itemtype=\"http://schema.org/Article\">\n           <div itemprop=\"articleBody\">\n            \n  <div class=\"section\" id=\"module-logging\">\n<span id=\"logging-module\"></span><h1>logging module<a class=\"headerlink\" href=\"#module-logging\" title=\"永久链接至标题\">¶</a></h1>\n<p>Logging package for Python. Based on PEP 282 and comments thereto in\ncomp.lang.python.</p>\n<p>Copyright (C) 2001-2016 Vinay Sajip. All Rights Reserved.</p>\n<p>To use, simply ‘import logging’ and log away!</p>\n<dl class=\"class\">\n<dt id=\"logging.BufferingFormatter\">\n<em class=\"property\">class </em><code class=\"descclassname\">logging.</code><code class=\"descname\">BufferingFormatter</code><span class=\"sig-paren\">(</span><em>linefmt=None</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#BufferingFormatter\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.BufferingFormatter\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>基类：<code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">object</span></code></p>\n<p>A formatter suitable for formatting a number of records.</p>\n<dl class=\"method\">\n<dt id=\"logging.BufferingFormatter.format\">\n<code class=\"descname\">format</code><span class=\"sig-paren\">(</span><em>records</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#BufferingFormatter.format\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.BufferingFormatter.format\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Format the specified records and return the result as a string.</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"logging.BufferingFormatter.formatFooter\">\n<code class=\"descname\">formatFooter</code><span class=\"sig-paren\">(</span><em>records</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#BufferingFormatter.formatFooter\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.BufferingFormatter.formatFooter\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Return the footer string for the specified records.</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"logging.BufferingFormatter.formatHeader\">\n<code class=\"descname\">formatHeader</code><span class=\"sig-paren\">(</span><em>records</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#BufferingFormatter.formatHeader\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.BufferingFormatter.formatHeader\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Return the header string for the specified records.</p>\n</dd></dl>\n\n</dd></dl>\n\n<dl class=\"class\">\n<dt id=\"logging.FileHandler\">\n<em class=\"property\">class </em><code class=\"descclassname\">logging.</code><code class=\"descname\">FileHandler</code><span class=\"sig-paren\">(</span><em>filename</em>, <em>mode='a'</em>, <em>encoding=None</em>, <em>delay=False</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#FileHandler\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.FileHandler\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>基类：<a class=\"reference internal\" href=\"#logging.StreamHandler\" title=\"logging.StreamHandler\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">logging.StreamHandler</span></code></a></p>\n<p>A handler class which writes formatted logging records to disk files.</p>\n<dl class=\"method\">\n<dt id=\"logging.FileHandler.close\">\n<code class=\"descname\">close</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#FileHandler.close\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.FileHandler.close\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Closes the stream.</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"logging.FileHandler.emit\">\n<code class=\"descname\">emit</code><span class=\"sig-paren\">(</span><em>record</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#FileHandler.emit\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.FileHandler.emit\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Emit a record.</p>\n<p>If the stream was not opened because ‘delay’ was specified in the\nconstructor, open it before calling the superclass’s emit.</p>\n</dd></dl>\n\n</dd></dl>\n\n<dl class=\"class\">\n<dt id=\"logging.Filter\">\n<em class=\"property\">class </em><code class=\"descclassname\">logging.</code><code class=\"descname\">Filter</code><span class=\"sig-paren\">(</span><em>name=''</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#Filter\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.Filter\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>基类：<code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">object</span></code></p>\n<p>Filter instances are used to perform arbitrary filtering of LogRecords.</p>\n<p>Loggers and Handlers can optionally use Filter instances to filter\nrecords as desired. The base filter class only allows events which are\nbelow a certain point in the logger hierarchy. For example, a filter\ninitialized with “A.B” will allow events logged by loggers “A.B”,\n“A.B.C”, “A.B.C.D”, “A.B.D” etc. but not “A.BB”, “B.A.B” etc. If\ninitialized with the empty string, all events are passed.</p>\n<dl class=\"method\">\n<dt id=\"logging.Filter.filter\">\n<code class=\"descname\">filter</code><span class=\"sig-paren\">(</span><em>record</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#Filter.filter\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.Filter.filter\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Determine if the specified record is to be logged.</p>\n<p>Is the specified record to be logged? Returns 0 for no, nonzero for\nyes. If deemed appropriate, the record may be modified in-place.</p>\n</dd></dl>\n\n</dd></dl>\n\n<dl class=\"class\">\n<dt id=\"logging.Formatter\">\n<em class=\"property\">class </em><code class=\"descclassname\">logging.</code><code class=\"descname\">Formatter</code><span class=\"sig-paren\">(</span><em>fmt=None</em>, <em>datefmt=None</em>, <em>style='%'</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#Formatter\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.Formatter\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>基类：<code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">object</span></code></p>\n<p>Formatter instances are used to convert a LogRecord to text.</p>\n<p>Formatters need to know how a LogRecord is constructed. They are\nresponsible for converting a LogRecord to (usually) a string which can\nbe interpreted by either a human or an external system. The base Formatter\nallows a formatting string to be specified. If none is supplied, the\ndefault value of “%s(message)” is used.</p>\n<p>The Formatter can be initialized with a format string which makes use of\nknowledge of the LogRecord attributes - e.g. the default value mentioned\nabove makes use of the fact that the user’s message and arguments are pre-\nformatted into a LogRecord’s message attribute. Currently, the useful\nattributes in a LogRecord are described by:</p>\n<p>%(name)s            Name of the logger (logging channel)\n%(levelno)s         Numeric logging level for the message (DEBUG, INFO,</p>\n<blockquote>\n<div>WARNING, ERROR, CRITICAL)</div></blockquote>\n<dl class=\"docutils\">\n<dt>%(levelname)s       Text logging level for the message (“DEBUG”, “INFO”,</dt>\n<dd>“WARNING”, “ERROR”, “CRITICAL”)</dd>\n<dt>%(pathname)s        Full pathname of the source file where the logging</dt>\n<dd>call was issued (if available)</dd>\n</dl>\n<p>%(filename)s        Filename portion of pathname\n%(module)s          Module (name portion of filename)\n%(lineno)d          Source line number where the logging call was issued</p>\n<blockquote>\n<div>(if available)</div></blockquote>\n<p>%(funcName)s        Function name\n%(created)f         Time when the LogRecord was created (time.time()</p>\n<blockquote>\n<div>return value)</div></blockquote>\n<p>%(asctime)s         Textual time when the LogRecord was created\n%(msecs)d           Millisecond portion of the creation time\n%(relativeCreated)d Time in milliseconds when the LogRecord was created,</p>\n<blockquote>\n<div>relative to the time the logging module was loaded\n(typically at application startup time)</div></blockquote>\n<p>%(thread)d          Thread ID (if available)\n%(threadName)s      Thread name (if available)\n%(process)d         Process ID (if available)\n%(message)s         The result of record.getMessage(), computed just as</p>\n<blockquote>\n<div>the record is emitted</div></blockquote>\n<dl class=\"method\">\n<dt id=\"logging.Formatter.converter\">\n<code class=\"descname\">converter</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"headerlink\" href=\"#logging.Formatter.converter\" title=\"永久链接至目标\">¶</a></dt>\n<dd><dl class=\"docutils\">\n<dt>localtime([seconds]) -&gt; (tm_year,tm_mon,tm_mday,tm_hour,tm_min,</dt>\n<dd>tm_sec,tm_wday,tm_yday,tm_isdst)</dd>\n</dl>\n<p>Convert seconds since the Epoch to a time tuple expressing local time.\nWhen ‘seconds’ is not passed in, convert the current time instead.</p>\n</dd></dl>\n\n<dl class=\"attribute\">\n<dt id=\"logging.Formatter.default_msec_format\">\n<code class=\"descname\">default_msec_format</code><em class=\"property\"> = '%s,%03d'</em><a class=\"headerlink\" href=\"#logging.Formatter.default_msec_format\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"attribute\">\n<dt id=\"logging.Formatter.default_time_format\">\n<code class=\"descname\">default_time_format</code><em class=\"property\"> = '%Y-%m-%d %H:%M:%S'</em><a class=\"headerlink\" href=\"#logging.Formatter.default_time_format\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"logging.Formatter.format\">\n<code class=\"descname\">format</code><span class=\"sig-paren\">(</span><em>record</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#Formatter.format\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.Formatter.format\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Format the specified record as text.</p>\n<p>The record’s attribute dictionary is used as the operand to a\nstring formatting operation which yields the returned string.\nBefore formatting the dictionary, a couple of preparatory steps\nare carried out. The message attribute of the record is computed\nusing LogRecord.getMessage(). If the formatting string uses the\ntime (as determined by a call to usesTime(), formatTime() is\ncalled to format the event time. If there is exception information,\nit is formatted using formatException() and appended to the message.</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"logging.Formatter.formatException\">\n<code class=\"descname\">formatException</code><span class=\"sig-paren\">(</span><em>ei</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#Formatter.formatException\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.Formatter.formatException\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Format and return the specified exception information as a string.</p>\n<p>This default implementation just uses\ntraceback.print_exception()</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"logging.Formatter.formatMessage\">\n<code class=\"descname\">formatMessage</code><span class=\"sig-paren\">(</span><em>record</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#Formatter.formatMessage\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.Formatter.formatMessage\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"logging.Formatter.formatStack\">\n<code class=\"descname\">formatStack</code><span class=\"sig-paren\">(</span><em>stack_info</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#Formatter.formatStack\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.Formatter.formatStack\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>This method is provided as an extension point for specialized\nformatting of stack information.</p>\n<p>The input data is a string as returned from a call to\n<code class=\"xref py py-func docutils literal notranslate\"><span class=\"pre\">traceback.print_stack()</span></code>, but with the last trailing newline\nremoved.</p>\n<p>The base implementation just returns the value passed in.</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"logging.Formatter.formatTime\">\n<code class=\"descname\">formatTime</code><span class=\"sig-paren\">(</span><em>record</em>, <em>datefmt=None</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#Formatter.formatTime\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.Formatter.formatTime\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Return the creation time of the specified LogRecord as formatted text.</p>\n<p>This method should be called from format() by a formatter which\nwants to make use of a formatted time. This method can be overridden\nin formatters to provide for any specific requirement, but the\nbasic behaviour is as follows: if datefmt (a string) is specified,\nit is used with time.strftime() to format the creation time of the\nrecord. Otherwise, the ISO8601 format is used. The resulting\nstring is returned. This function uses a user-configurable function\nto convert the creation time to a tuple. By default, time.localtime()\nis used; to change this for a particular formatter instance, set the\n‘converter’ attribute to a function with the same signature as\ntime.localtime() or time.gmtime(). To change it for all formatters,\nfor example if you want all logging times to be shown in GMT,\nset the ‘converter’ attribute in the Formatter class.</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"logging.Formatter.usesTime\">\n<code class=\"descname\">usesTime</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#Formatter.usesTime\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.Formatter.usesTime\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Check if the format uses the creation time of the record.</p>\n</dd></dl>\n\n</dd></dl>\n\n<dl class=\"class\">\n<dt id=\"logging.Handler\">\n<em class=\"property\">class </em><code class=\"descclassname\">logging.</code><code class=\"descname\">Handler</code><span class=\"sig-paren\">(</span><em>level=0</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#Handler\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.Handler\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>基类：<code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">logging.Filterer</span></code></p>\n<p>Handler instances dispatch logging events to specific destinations.</p>\n<p>The base handler class. Acts as a placeholder which defines the Handler\ninterface. Handlers can optionally use Formatter instances to format\nrecords as desired. By default, no formatter is specified; in this case,\nthe ‘raw’ message as determined by record.message is logged.</p>\n<dl class=\"method\">\n<dt id=\"logging.Handler.acquire\">\n<code class=\"descname\">acquire</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#Handler.acquire\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.Handler.acquire\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Acquire the I/O thread lock.</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"logging.Handler.close\">\n<code class=\"descname\">close</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#Handler.close\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.Handler.close\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Tidy up any resources used by the handler.</p>\n<p>This version removes the handler from an internal map of handlers,\n_handlers, which is used for handler lookup by name. Subclasses\nshould ensure that this gets called from overridden close()\nmethods.</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"logging.Handler.createLock\">\n<code class=\"descname\">createLock</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#Handler.createLock\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.Handler.createLock\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Acquire a thread lock for serializing access to the underlying I/O.</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"logging.Handler.emit\">\n<code class=\"descname\">emit</code><span class=\"sig-paren\">(</span><em>record</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#Handler.emit\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.Handler.emit\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Do whatever it takes to actually log the specified logging record.</p>\n<p>This version is intended to be implemented by subclasses and so\nraises a NotImplementedError.</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"logging.Handler.flush\">\n<code class=\"descname\">flush</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#Handler.flush\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.Handler.flush\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Ensure all logging output has been flushed.</p>\n<p>This version does nothing and is intended to be implemented by\nsubclasses.</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"logging.Handler.format\">\n<code class=\"descname\">format</code><span class=\"sig-paren\">(</span><em>record</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#Handler.format\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.Handler.format\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Format the specified record.</p>\n<p>If a formatter is set, use it. Otherwise, use the default formatter\nfor the module.</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"logging.Handler.get_name\">\n<code class=\"descname\">get_name</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#Handler.get_name\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.Handler.get_name\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"logging.Handler.handle\">\n<code class=\"descname\">handle</code><span class=\"sig-paren\">(</span><em>record</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#Handler.handle\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.Handler.handle\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Conditionally emit the specified logging record.</p>\n<p>Emission depends on filters which may have been added to the handler.\nWrap the actual emission of the record with acquisition/release of\nthe I/O thread lock. Returns whether the filter passed the record for\nemission.</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"logging.Handler.handleError\">\n<code class=\"descname\">handleError</code><span class=\"sig-paren\">(</span><em>record</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#Handler.handleError\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.Handler.handleError\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Handle errors which occur during an emit() call.</p>\n<p>This method should be called from handlers when an exception is\nencountered during an emit() call. If raiseExceptions is false,\nexceptions get silently ignored. This is what is mostly wanted\nfor a logging system - most users will not care about errors in\nthe logging system, they are more interested in application errors.\nYou could, however, replace this with a custom handler if you wish.\nThe record which was being processed is passed in to this method.</p>\n</dd></dl>\n\n<dl class=\"attribute\">\n<dt id=\"logging.Handler.name\">\n<code class=\"descname\">name</code><a class=\"headerlink\" href=\"#logging.Handler.name\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"logging.Handler.release\">\n<code class=\"descname\">release</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#Handler.release\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.Handler.release\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Release the I/O thread lock.</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"logging.Handler.setFormatter\">\n<code class=\"descname\">setFormatter</code><span class=\"sig-paren\">(</span><em>fmt</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#Handler.setFormatter\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.Handler.setFormatter\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Set the formatter for this handler.</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"logging.Handler.setLevel\">\n<code class=\"descname\">setLevel</code><span class=\"sig-paren\">(</span><em>level</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#Handler.setLevel\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.Handler.setLevel\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Set the logging level of this handler.  level must be an int or a str.</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"logging.Handler.set_name\">\n<code class=\"descname\">set_name</code><span class=\"sig-paren\">(</span><em>name</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#Handler.set_name\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.Handler.set_name\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n</dd></dl>\n\n<dl class=\"class\">\n<dt id=\"logging.LogRecord\">\n<em class=\"property\">class </em><code class=\"descclassname\">logging.</code><code class=\"descname\">LogRecord</code><span class=\"sig-paren\">(</span><em>name</em>, <em>level</em>, <em>pathname</em>, <em>lineno</em>, <em>msg</em>, <em>args</em>, <em>exc_info</em>, <em>func=None</em>, <em>sinfo=None</em>, <em>**kwargs</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#LogRecord\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.LogRecord\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>基类：<code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">object</span></code></p>\n<p>A LogRecord instance represents an event being logged.</p>\n<p>LogRecord instances are created every time something is logged. They\ncontain all the information pertinent to the event being logged. The\nmain information passed in is in msg and args, which are combined\nusing str(msg) % args to create the message field of the record. The\nrecord also includes information such as when the record was created,\nthe source line where the logging call was made, and any exception\ninformation to be logged.</p>\n<dl class=\"method\">\n<dt id=\"logging.LogRecord.getMessage\">\n<code class=\"descname\">getMessage</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#LogRecord.getMessage\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.LogRecord.getMessage\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Return the message for this LogRecord.</p>\n<p>Return the message for this LogRecord after merging any user-supplied\narguments with the message.</p>\n</dd></dl>\n\n</dd></dl>\n\n<dl class=\"class\">\n<dt id=\"logging.Logger\">\n<em class=\"property\">class </em><code class=\"descclassname\">logging.</code><code class=\"descname\">Logger</code><span class=\"sig-paren\">(</span><em>name</em>, <em>level=0</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#Logger\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.Logger\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>基类：<code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">logging.Filterer</span></code></p>\n<p>Instances of the Logger class represent a single logging channel. A\n“logging channel” indicates an area of an application. Exactly how an\n“area” is defined is up to the application developer. Since an\napplication can have any number of areas, logging channels are identified\nby a unique string. Application areas can be nested (e.g. an area\nof “input processing” might include sub-areas “read CSV files”, “read\nXLS files” and “read Gnumeric files”). To cater for this natural nesting,\nchannel names are organized into a namespace hierarchy where levels are\nseparated by periods, much like the Java or Python package namespace. So\nin the instance given above, channel names might be “input” for the upper\nlevel, and “input.csv”, “input.xls” and “input.gnu” for the sub-levels.\nThere is no arbitrary limit to the depth of nesting.</p>\n<dl class=\"method\">\n<dt id=\"logging.Logger.addHandler\">\n<code class=\"descname\">addHandler</code><span class=\"sig-paren\">(</span><em>hdlr</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#Logger.addHandler\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.Logger.addHandler\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Add the specified handler to this logger.</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"logging.Logger.callHandlers\">\n<code class=\"descname\">callHandlers</code><span class=\"sig-paren\">(</span><em>record</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#Logger.callHandlers\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.Logger.callHandlers\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Pass a record to all relevant handlers.</p>\n<p>Loop through all handlers for this logger and its parents in the\nlogger hierarchy. If no handler was found, output a one-off error\nmessage to sys.stderr. Stop searching up the hierarchy whenever a\nlogger with the “propagate” attribute set to zero is found - that\nwill be the last logger whose handlers are called.</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"logging.Logger.critical\">\n<code class=\"descname\">critical</code><span class=\"sig-paren\">(</span><em>msg</em>, <em>*args</em>, <em>**kwargs</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#Logger.critical\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.Logger.critical\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Log ‘msg % args’ with severity ‘CRITICAL’.</p>\n<p>To pass exception information, use the keyword argument exc_info with\na true value, e.g.</p>\n<p>logger.critical(“Houston, we have a %s”, “major disaster”, exc_info=1)</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"logging.Logger.debug\">\n<code class=\"descname\">debug</code><span class=\"sig-paren\">(</span><em>msg</em>, <em>*args</em>, <em>**kwargs</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#Logger.debug\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.Logger.debug\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Log ‘msg % args’ with severity ‘DEBUG’.</p>\n<p>To pass exception information, use the keyword argument exc_info with\na true value, e.g.</p>\n<p>logger.debug(“Houston, we have a %s”, “thorny problem”, exc_info=1)</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"logging.Logger.error\">\n<code class=\"descname\">error</code><span class=\"sig-paren\">(</span><em>msg</em>, <em>*args</em>, <em>**kwargs</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#Logger.error\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.Logger.error\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Log ‘msg % args’ with severity ‘ERROR’.</p>\n<p>To pass exception information, use the keyword argument exc_info with\na true value, e.g.</p>\n<p>logger.error(“Houston, we have a %s”, “major problem”, exc_info=1)</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"logging.Logger.exception\">\n<code class=\"descname\">exception</code><span class=\"sig-paren\">(</span><em>msg</em>, <em>*args</em>, <em>exc_info=True</em>, <em>**kwargs</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#Logger.exception\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.Logger.exception\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Convenience method for logging an ERROR with exception information.</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"logging.Logger.fatal\">\n<code class=\"descname\">fatal</code><span class=\"sig-paren\">(</span><em>msg</em>, <em>*args</em>, <em>**kwargs</em><span class=\"sig-paren\">)</span><a class=\"headerlink\" href=\"#logging.Logger.fatal\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Log ‘msg % args’ with severity ‘CRITICAL’.</p>\n<p>To pass exception information, use the keyword argument exc_info with\na true value, e.g.</p>\n<p>logger.critical(“Houston, we have a %s”, “major disaster”, exc_info=1)</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"logging.Logger.findCaller\">\n<code class=\"descname\">findCaller</code><span class=\"sig-paren\">(</span><em>stack_info=False</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#Logger.findCaller\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.Logger.findCaller\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Find the stack frame of the caller so that we can note the source\nfile name, line number and function name.</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"logging.Logger.getChild\">\n<code class=\"descname\">getChild</code><span class=\"sig-paren\">(</span><em>suffix</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#Logger.getChild\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.Logger.getChild\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Get a logger which is a descendant to this one.</p>\n<p>This is a convenience method, such that</p>\n<p>logging.getLogger(‘abc’).getChild(‘def.ghi’)</p>\n<p>is the same as</p>\n<p>logging.getLogger(‘abc.def.ghi’)</p>\n<p>It’s useful, for example, when the parent logger is named using\n__name__ rather than a literal string.</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"logging.Logger.getEffectiveLevel\">\n<code class=\"descname\">getEffectiveLevel</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#Logger.getEffectiveLevel\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.Logger.getEffectiveLevel\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Get the effective level for this logger.</p>\n<p>Loop through this logger and its parents in the logger hierarchy,\nlooking for a non-zero logging level. Return the first one found.</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"logging.Logger.handle\">\n<code class=\"descname\">handle</code><span class=\"sig-paren\">(</span><em>record</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#Logger.handle\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.Logger.handle\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Call the handlers for the specified record.</p>\n<p>This method is used for unpickled records received from a socket, as\nwell as those created locally. Logger-level filtering is applied.</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"logging.Logger.hasHandlers\">\n<code class=\"descname\">hasHandlers</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#Logger.hasHandlers\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.Logger.hasHandlers\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>See if this logger has any handlers configured.</p>\n<p>Loop through all handlers for this logger and its parents in the\nlogger hierarchy. Return True if a handler was found, else False.\nStop searching up the hierarchy whenever a logger with the “propagate”\nattribute set to zero is found - that will be the last logger which\nis checked for the existence of handlers.</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"logging.Logger.info\">\n<code class=\"descname\">info</code><span class=\"sig-paren\">(</span><em>msg</em>, <em>*args</em>, <em>**kwargs</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#Logger.info\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.Logger.info\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Log ‘msg % args’ with severity ‘INFO’.</p>\n<p>To pass exception information, use the keyword argument exc_info with\na true value, e.g.</p>\n<p>logger.info(“Houston, we have a %s”, “interesting problem”, exc_info=1)</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"logging.Logger.isEnabledFor\">\n<code class=\"descname\">isEnabledFor</code><span class=\"sig-paren\">(</span><em>level</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#Logger.isEnabledFor\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.Logger.isEnabledFor\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Is this logger enabled for level ‘level’?</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"logging.Logger.log\">\n<code class=\"descname\">log</code><span class=\"sig-paren\">(</span><em>level</em>, <em>msg</em>, <em>*args</em>, <em>**kwargs</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#Logger.log\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.Logger.log\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Log ‘msg % args’ with the integer severity ‘level’.</p>\n<p>To pass exception information, use the keyword argument exc_info with\na true value, e.g.</p>\n<p>logger.log(level, “We have a %s”, “mysterious problem”, exc_info=1)</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"logging.Logger.makeRecord\">\n<code class=\"descname\">makeRecord</code><span class=\"sig-paren\">(</span><em>name</em>, <em>level</em>, <em>fn</em>, <em>lno</em>, <em>msg</em>, <em>args</em>, <em>exc_info</em>, <em>func=None</em>, <em>extra=None</em>, <em>sinfo=None</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#Logger.makeRecord\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.Logger.makeRecord\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>A factory method which can be overridden in subclasses to create\nspecialized LogRecords.</p>\n</dd></dl>\n\n<dl class=\"attribute\">\n<dt id=\"logging.Logger.manager\">\n<code class=\"descname\">manager</code><em class=\"property\"> = &lt;logging.Manager object&gt;</em><a class=\"headerlink\" href=\"#logging.Logger.manager\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"logging.Logger.removeHandler\">\n<code class=\"descname\">removeHandler</code><span class=\"sig-paren\">(</span><em>hdlr</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#Logger.removeHandler\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.Logger.removeHandler\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Remove the specified handler from this logger.</p>\n</dd></dl>\n\n<dl class=\"attribute\">\n<dt id=\"logging.Logger.root\">\n<code class=\"descname\">root</code><em class=\"property\"> = &lt;logging.RootLogger object&gt;</em><a class=\"headerlink\" href=\"#logging.Logger.root\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"logging.Logger.setLevel\">\n<code class=\"descname\">setLevel</code><span class=\"sig-paren\">(</span><em>level</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#Logger.setLevel\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.Logger.setLevel\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Set the logging level of this logger.  level must be an int or a str.</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"logging.Logger.warn\">\n<code class=\"descname\">warn</code><span class=\"sig-paren\">(</span><em>msg</em>, <em>*args</em>, <em>**kwargs</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#Logger.warn\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.Logger.warn\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"logging.Logger.warning\">\n<code class=\"descname\">warning</code><span class=\"sig-paren\">(</span><em>msg</em>, <em>*args</em>, <em>**kwargs</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#Logger.warning\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.Logger.warning\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Log ‘msg % args’ with severity ‘WARNING’.</p>\n<p>To pass exception information, use the keyword argument exc_info with\na true value, e.g.</p>\n<p>logger.warning(“Houston, we have a %s”, “bit of a problem”, exc_info=1)</p>\n</dd></dl>\n\n</dd></dl>\n\n<dl class=\"class\">\n<dt id=\"logging.LoggerAdapter\">\n<em class=\"property\">class </em><code class=\"descclassname\">logging.</code><code class=\"descname\">LoggerAdapter</code><span class=\"sig-paren\">(</span><em>logger</em>, <em>extra</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#LoggerAdapter\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.LoggerAdapter\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>基类：<code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">object</span></code></p>\n<p>An adapter for loggers which makes it easier to specify contextual\ninformation in logging output.</p>\n<dl class=\"method\">\n<dt id=\"logging.LoggerAdapter.critical\">\n<code class=\"descname\">critical</code><span class=\"sig-paren\">(</span><em>msg</em>, <em>*args</em>, <em>**kwargs</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#LoggerAdapter.critical\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.LoggerAdapter.critical\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Delegate a critical call to the underlying logger.</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"logging.LoggerAdapter.debug\">\n<code class=\"descname\">debug</code><span class=\"sig-paren\">(</span><em>msg</em>, <em>*args</em>, <em>**kwargs</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#LoggerAdapter.debug\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.LoggerAdapter.debug\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Delegate a debug call to the underlying logger.</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"logging.LoggerAdapter.error\">\n<code class=\"descname\">error</code><span class=\"sig-paren\">(</span><em>msg</em>, <em>*args</em>, <em>**kwargs</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#LoggerAdapter.error\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.LoggerAdapter.error\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Delegate an error call to the underlying logger.</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"logging.LoggerAdapter.exception\">\n<code class=\"descname\">exception</code><span class=\"sig-paren\">(</span><em>msg</em>, <em>*args</em>, <em>exc_info=True</em>, <em>**kwargs</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#LoggerAdapter.exception\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.LoggerAdapter.exception\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Delegate an exception call to the underlying logger.</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"logging.LoggerAdapter.getEffectiveLevel\">\n<code class=\"descname\">getEffectiveLevel</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#LoggerAdapter.getEffectiveLevel\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.LoggerAdapter.getEffectiveLevel\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Get the effective level for the underlying logger.</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"logging.LoggerAdapter.hasHandlers\">\n<code class=\"descname\">hasHandlers</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#LoggerAdapter.hasHandlers\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.LoggerAdapter.hasHandlers\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>See if the underlying logger has any handlers.</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"logging.LoggerAdapter.info\">\n<code class=\"descname\">info</code><span class=\"sig-paren\">(</span><em>msg</em>, <em>*args</em>, <em>**kwargs</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#LoggerAdapter.info\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.LoggerAdapter.info\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Delegate an info call to the underlying logger.</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"logging.LoggerAdapter.isEnabledFor\">\n<code class=\"descname\">isEnabledFor</code><span class=\"sig-paren\">(</span><em>level</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#LoggerAdapter.isEnabledFor\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.LoggerAdapter.isEnabledFor\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Is this logger enabled for level ‘level’?</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"logging.LoggerAdapter.log\">\n<code class=\"descname\">log</code><span class=\"sig-paren\">(</span><em>level</em>, <em>msg</em>, <em>*args</em>, <em>**kwargs</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#LoggerAdapter.log\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.LoggerAdapter.log\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Delegate a log call to the underlying logger, after adding\ncontextual information from this adapter instance.</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"logging.LoggerAdapter.process\">\n<code class=\"descname\">process</code><span class=\"sig-paren\">(</span><em>msg</em>, <em>kwargs</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#LoggerAdapter.process\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.LoggerAdapter.process\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Process the logging message and keyword arguments passed in to\na logging call to insert contextual information. You can either\nmanipulate the message itself, the keyword args or both. Return\nthe message and kwargs modified (or not) to suit your needs.</p>\n<p>Normally, you’ll only need to override this one method in a\nLoggerAdapter subclass for your specific needs.</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"logging.LoggerAdapter.setLevel\">\n<code class=\"descname\">setLevel</code><span class=\"sig-paren\">(</span><em>level</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#LoggerAdapter.setLevel\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.LoggerAdapter.setLevel\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Set the specified level on the underlying logger.</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"logging.LoggerAdapter.warn\">\n<code class=\"descname\">warn</code><span class=\"sig-paren\">(</span><em>msg</em>, <em>*args</em>, <em>**kwargs</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#LoggerAdapter.warn\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.LoggerAdapter.warn\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"logging.LoggerAdapter.warning\">\n<code class=\"descname\">warning</code><span class=\"sig-paren\">(</span><em>msg</em>, <em>*args</em>, <em>**kwargs</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#LoggerAdapter.warning\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.LoggerAdapter.warning\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Delegate a warning call to the underlying logger.</p>\n</dd></dl>\n\n</dd></dl>\n\n<dl class=\"class\">\n<dt id=\"logging.NullHandler\">\n<em class=\"property\">class </em><code class=\"descclassname\">logging.</code><code class=\"descname\">NullHandler</code><span class=\"sig-paren\">(</span><em>level=0</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#NullHandler\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.NullHandler\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>基类：<a class=\"reference internal\" href=\"#logging.Handler\" title=\"logging.Handler\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">logging.Handler</span></code></a></p>\n<p>This handler does nothing. It’s intended to be used to avoid the\n“No handlers could be found for logger XXX” one-off warning. This is\nimportant for library code, which may contain code to log events. If a user\nof the library does not configure logging, the one-off warning might be\nproduced; to avoid this, the library developer simply needs to instantiate\na NullHandler and add it to the top-level logger of the library module or\npackage.</p>\n<dl class=\"method\">\n<dt id=\"logging.NullHandler.createLock\">\n<code class=\"descname\">createLock</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#NullHandler.createLock\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.NullHandler.createLock\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Acquire a thread lock for serializing access to the underlying I/O.</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"logging.NullHandler.emit\">\n<code class=\"descname\">emit</code><span class=\"sig-paren\">(</span><em>record</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#NullHandler.emit\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.NullHandler.emit\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Stub.</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"logging.NullHandler.handle\">\n<code class=\"descname\">handle</code><span class=\"sig-paren\">(</span><em>record</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#NullHandler.handle\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.NullHandler.handle\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Stub.</p>\n</dd></dl>\n\n</dd></dl>\n\n<dl class=\"class\">\n<dt id=\"logging.StreamHandler\">\n<em class=\"property\">class </em><code class=\"descclassname\">logging.</code><code class=\"descname\">StreamHandler</code><span class=\"sig-paren\">(</span><em>stream=None</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#StreamHandler\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.StreamHandler\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>基类：<a class=\"reference internal\" href=\"#logging.Handler\" title=\"logging.Handler\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">logging.Handler</span></code></a></p>\n<p>A handler class which writes logging records, appropriately formatted,\nto a stream. Note that this class does not close the stream, as\nsys.stdout or sys.stderr may be used.</p>\n<dl class=\"method\">\n<dt id=\"logging.StreamHandler.emit\">\n<code class=\"descname\">emit</code><span class=\"sig-paren\">(</span><em>record</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#StreamHandler.emit\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.StreamHandler.emit\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Emit a record.</p>\n<p>If a formatter is specified, it is used to format the record.\nThe record is then written to the stream with a trailing newline.  If\nexception information is present, it is formatted using\ntraceback.print_exception and appended to the stream.  If the stream\nhas an ‘encoding’ attribute, it is used to determine how to do the\noutput to the stream.</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"logging.StreamHandler.flush\">\n<code class=\"descname\">flush</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#StreamHandler.flush\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.StreamHandler.flush\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Flushes the stream.</p>\n</dd></dl>\n\n<dl class=\"attribute\">\n<dt id=\"logging.StreamHandler.terminator\">\n<code class=\"descname\">terminator</code><em class=\"property\"> = '\\n'</em><a class=\"headerlink\" href=\"#logging.StreamHandler.terminator\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n</dd></dl>\n\n<dl class=\"function\">\n<dt id=\"logging.addLevelName\">\n<code class=\"descclassname\">logging.</code><code class=\"descname\">addLevelName</code><span class=\"sig-paren\">(</span><em>level</em>, <em>levelName</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#addLevelName\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.addLevelName\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Associate ‘levelName’ with ‘level’.</p>\n<p>This is used when converting levels to text during message formatting.</p>\n</dd></dl>\n\n<dl class=\"function\">\n<dt id=\"logging.basicConfig\">\n<code class=\"descclassname\">logging.</code><code class=\"descname\">basicConfig</code><span class=\"sig-paren\">(</span><em>**kwargs</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#basicConfig\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.basicConfig\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Do basic configuration for the logging system.</p>\n<p>This function does nothing if the root logger already has handlers\nconfigured. It is a convenience method intended for use by simple scripts\nto do one-shot configuration of the logging package.</p>\n<p>The default behaviour is to create a StreamHandler which writes to\nsys.stderr, set a formatter using the BASIC_FORMAT format string, and\nadd the handler to the root logger.</p>\n<p>A number of optional keyword arguments may be specified, which can alter\nthe default behaviour.</p>\n<dl class=\"docutils\">\n<dt>filename  Specifies that a FileHandler be created, using the specified</dt>\n<dd>filename, rather than a StreamHandler.</dd>\n<dt>filemode  Specifies the mode to open the file, if filename is specified</dt>\n<dd>(if filemode is unspecified, it defaults to ‘a’).</dd>\n</dl>\n<p>format    Use the specified format string for the handler.\ndatefmt   Use the specified date/time format.\nstyle     If a format string is specified, use this to specify the</p>\n<blockquote>\n<div>type of format string (possible values ‘%’, ‘{‘, ‘$’, for\n%-formatting, <code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">str.format()</span></code> and <code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">string.Template</span></code>\n- defaults to ‘%’).</div></blockquote>\n<p>level     Set the root logger level to the specified level.\nstream    Use the specified stream to initialize the StreamHandler. Note</p>\n<blockquote>\n<div>that this argument is incompatible with ‘filename’ - if both\nare present, ‘stream’ is ignored.</div></blockquote>\n<dl class=\"docutils\">\n<dt>handlers  If specified, this should be an iterable of already created</dt>\n<dd>handlers, which will be added to the root handler. Any handler\nin the list which does not have a formatter assigned will be\nassigned the formatter created in this function.</dd>\n</dl>\n<p>Note that you could specify a stream created using open(filename, mode)\nrather than passing the filename and mode in. However, it should be\nremembered that StreamHandler does not close its stream (since it may be\nusing sys.stdout or sys.stderr), whereas FileHandler closes its stream\nwhen the handler is closed.</p>\n<div class=\"versionchanged\">\n<p><span class=\"versionmodified\">在 3.2 版更改: </span>Added the <code class=\"docutils literal notranslate\"><span class=\"pre\">style</span></code> parameter.</p>\n</div>\n<div class=\"versionchanged\">\n<p><span class=\"versionmodified\">在 3.3 版更改: </span>Added the <code class=\"docutils literal notranslate\"><span class=\"pre\">handlers</span></code> parameter. A <code class=\"docutils literal notranslate\"><span class=\"pre\">ValueError</span></code> is now thrown for\nincompatible arguments (e.g. <code class=\"docutils literal notranslate\"><span class=\"pre\">handlers</span></code> specified together with\n<code class=\"docutils literal notranslate\"><span class=\"pre\">filename</span></code>/<code class=\"docutils literal notranslate\"><span class=\"pre\">filemode</span></code>, or <code class=\"docutils literal notranslate\"><span class=\"pre\">filename</span></code>/<code class=\"docutils literal notranslate\"><span class=\"pre\">filemode</span></code> specified\ntogether with <code class=\"docutils literal notranslate\"><span class=\"pre\">stream</span></code>, or <code class=\"docutils literal notranslate\"><span class=\"pre\">handlers</span></code> specified together with\n<code class=\"docutils literal notranslate\"><span class=\"pre\">stream</span></code>.</p>\n</div>\n</dd></dl>\n\n<dl class=\"function\">\n<dt id=\"logging.captureWarnings\">\n<code class=\"descclassname\">logging.</code><code class=\"descname\">captureWarnings</code><span class=\"sig-paren\">(</span><em>capture</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#captureWarnings\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.captureWarnings\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>If capture is true, redirect all warnings to the logging package.\nIf capture is False, ensure that warnings are not redirected to logging\nbut to their original destinations.</p>\n</dd></dl>\n\n<dl class=\"function\">\n<dt id=\"logging.critical\">\n<code class=\"descclassname\">logging.</code><code class=\"descname\">critical</code><span class=\"sig-paren\">(</span><em>msg</em>, <em>*args</em>, <em>**kwargs</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#critical\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.critical\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Log a message with severity ‘CRITICAL’ on the root logger. If the logger\nhas no handlers, call basicConfig() to add a console handler with a\npre-defined format.</p>\n</dd></dl>\n\n<dl class=\"function\">\n<dt id=\"logging.debug\">\n<code class=\"descclassname\">logging.</code><code class=\"descname\">debug</code><span class=\"sig-paren\">(</span><em>msg</em>, <em>*args</em>, <em>**kwargs</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#debug\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.debug\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Log a message with severity ‘DEBUG’ on the root logger. If the logger has\nno handlers, call basicConfig() to add a console handler with a pre-defined\nformat.</p>\n</dd></dl>\n\n<dl class=\"function\">\n<dt id=\"logging.disable\">\n<code class=\"descclassname\">logging.</code><code class=\"descname\">disable</code><span class=\"sig-paren\">(</span><em>level</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#disable\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.disable\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Disable all logging calls of severity ‘level’ and below.</p>\n</dd></dl>\n\n<dl class=\"function\">\n<dt id=\"logging.error\">\n<code class=\"descclassname\">logging.</code><code class=\"descname\">error</code><span class=\"sig-paren\">(</span><em>msg</em>, <em>*args</em>, <em>**kwargs</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#error\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.error\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Log a message with severity ‘ERROR’ on the root logger. If the logger has\nno handlers, call basicConfig() to add a console handler with a pre-defined\nformat.</p>\n</dd></dl>\n\n<dl class=\"function\">\n<dt id=\"logging.exception\">\n<code class=\"descclassname\">logging.</code><code class=\"descname\">exception</code><span class=\"sig-paren\">(</span><em>msg</em>, <em>*args</em>, <em>exc_info=True</em>, <em>**kwargs</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#exception\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.exception\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Log a message with severity ‘ERROR’ on the root logger, with exception\ninformation. If the logger has no handlers, basicConfig() is called to add\na console handler with a pre-defined format.</p>\n</dd></dl>\n\n<dl class=\"function\">\n<dt id=\"logging.fatal\">\n<code class=\"descclassname\">logging.</code><code class=\"descname\">fatal</code><span class=\"sig-paren\">(</span><em>msg</em>, <em>*args</em>, <em>**kwargs</em><span class=\"sig-paren\">)</span><a class=\"headerlink\" href=\"#logging.fatal\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Log a message with severity ‘CRITICAL’ on the root logger. If the logger\nhas no handlers, call basicConfig() to add a console handler with a\npre-defined format.</p>\n</dd></dl>\n\n<dl class=\"function\">\n<dt id=\"logging.getLevelName\">\n<code class=\"descclassname\">logging.</code><code class=\"descname\">getLevelName</code><span class=\"sig-paren\">(</span><em>level</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#getLevelName\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.getLevelName\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Return the textual representation of logging level ‘level’.</p>\n<p>If the level is one of the predefined levels (CRITICAL, ERROR, WARNING,\nINFO, DEBUG) then you get the corresponding string. If you have\nassociated levels with names using addLevelName then the name you have\nassociated with ‘level’ is returned.</p>\n<p>If a numeric value corresponding to one of the defined levels is passed\nin, the corresponding string representation is returned.</p>\n<p>Otherwise, the string “Level %s” % level is returned.</p>\n</dd></dl>\n\n<dl class=\"function\">\n<dt id=\"logging.getLogger\">\n<code class=\"descclassname\">logging.</code><code class=\"descname\">getLogger</code><span class=\"sig-paren\">(</span><em>name=None</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#getLogger\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.getLogger\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Return a logger with the specified name, creating it if necessary.</p>\n<p>If no name is specified, return the root logger.</p>\n</dd></dl>\n\n<dl class=\"function\">\n<dt id=\"logging.getLoggerClass\">\n<code class=\"descclassname\">logging.</code><code class=\"descname\">getLoggerClass</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#getLoggerClass\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.getLoggerClass\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Return the class to be used when instantiating a logger.</p>\n</dd></dl>\n\n<dl class=\"function\">\n<dt id=\"logging.info\">\n<code class=\"descclassname\">logging.</code><code class=\"descname\">info</code><span class=\"sig-paren\">(</span><em>msg</em>, <em>*args</em>, <em>**kwargs</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#info\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.info\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Log a message with severity ‘INFO’ on the root logger. If the logger has\nno handlers, call basicConfig() to add a console handler with a pre-defined\nformat.</p>\n</dd></dl>\n\n<dl class=\"function\">\n<dt id=\"logging.log\">\n<code class=\"descclassname\">logging.</code><code class=\"descname\">log</code><span class=\"sig-paren\">(</span><em>level</em>, <em>msg</em>, <em>*args</em>, <em>**kwargs</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#log\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.log\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Log ‘msg % args’ with the integer severity ‘level’ on the root logger. If\nthe logger has no handlers, call basicConfig() to add a console handler\nwith a pre-defined format.</p>\n</dd></dl>\n\n<dl class=\"function\">\n<dt id=\"logging.makeLogRecord\">\n<code class=\"descclassname\">logging.</code><code class=\"descname\">makeLogRecord</code><span class=\"sig-paren\">(</span><em>dict</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#makeLogRecord\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.makeLogRecord\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Make a LogRecord whose attributes are defined by the specified dictionary,\nThis function is useful for converting a logging event received over\na socket connection (which is sent as a dictionary) into a LogRecord\ninstance.</p>\n</dd></dl>\n\n<dl class=\"function\">\n<dt id=\"logging.setLoggerClass\">\n<code class=\"descclassname\">logging.</code><code class=\"descname\">setLoggerClass</code><span class=\"sig-paren\">(</span><em>klass</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#setLoggerClass\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.setLoggerClass\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Set the class to be used when instantiating a logger. The class should\ndefine __init__() such that only a name argument is required, and the\n__init__() should call Logger.__init__()</p>\n</dd></dl>\n\n<dl class=\"function\">\n<dt id=\"logging.warn\">\n<code class=\"descclassname\">logging.</code><code class=\"descname\">warn</code><span class=\"sig-paren\">(</span><em>msg</em>, <em>*args</em>, <em>**kwargs</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#warn\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.warn\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"function\">\n<dt id=\"logging.warning\">\n<code class=\"descclassname\">logging.</code><code class=\"descname\">warning</code><span class=\"sig-paren\">(</span><em>msg</em>, <em>*args</em>, <em>**kwargs</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#warning\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.warning\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Log a message with severity ‘WARNING’ on the root logger. If the logger has\nno handlers, call basicConfig() to add a console handler with a pre-defined\nformat.</p>\n</dd></dl>\n\n<dl class=\"function\">\n<dt id=\"logging.getLogRecordFactory\">\n<code class=\"descclassname\">logging.</code><code class=\"descname\">getLogRecordFactory</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#getLogRecordFactory\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.getLogRecordFactory\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Return the factory to be used when instantiating a log record.</p>\n</dd></dl>\n\n<dl class=\"function\">\n<dt id=\"logging.setLogRecordFactory\">\n<code class=\"descclassname\">logging.</code><code class=\"descname\">setLogRecordFactory</code><span class=\"sig-paren\">(</span><em>factory</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/logging.html#setLogRecordFactory\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#logging.setLogRecordFactory\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Set the factory to be used when instantiating a log record.</p>\n<table class=\"docutils field-list\" frame=\"void\" rules=\"none\">\n<col class=\"field-name\" />\n<col class=\"field-body\" />\n<tbody valign=\"top\">\n<tr class=\"field-odd field\"><th class=\"field-name\">参数:</th><td class=\"field-body\"><strong>factory</strong> – A callable which will be called to instantiate</td>\n</tr>\n</tbody>\n</table>\n<p>a log record.</p>\n</dd></dl>\n\n</div>\n\n\n           </div>\n           \n          </div>\n          <footer>\n  \n\n  <hr/>\n\n  <div role=\"contentinfo\">\n    <p>\n        &copy; Copyright 2019, wzpan\n\n    </p>\n  </div>\n  Built with <a href=\"http://sphinx-doc.org/\">Sphinx</a> using a <a href=\"https://github.com/rtfd/sphinx_rtd_theme\">theme</a> provided by <a href=\"https://readthedocs.org\">Read the Docs</a>. \n\n</footer>\n\n        </div>\n      </div>\n\n    </section>\n\n  </div>\n  \n\n\n  <script type=\"text/javascript\">\n      jQuery(function () {\n          SphinxRtdTheme.Navigation.enable(true);\n      });\n  </script>\n\n  \n  \n    \n   \n\n</body>\n</html>"
  },
  {
    "path": "docs/modules.html",
    "content": "\n\n<!DOCTYPE html>\n<!--[if IE 8]><html class=\"no-js lt-ie9\" lang=\"zh-CN\" > <![endif]-->\n<!--[if gt IE 8]><!--> <html class=\"no-js\" lang=\"zh-CN\" > <!--<![endif]-->\n<head>\n  <meta charset=\"utf-8\">\n  \n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  \n  <title>wukong-robot &mdash; wukong-robot 1.2.0 文档</title>\n  \n\n  \n  \n  \n  \n\n  \n  <script type=\"text/javascript\" src=\"_static/js/modernizr.min.js\"></script>\n  \n    \n      <script type=\"text/javascript\" id=\"documentation_options\" data-url_root=\"./\" src=\"_static/documentation_options.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/jquery.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/underscore.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/doctools.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/language_data.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/translations.js\"></script>\n    \n    <script type=\"text/javascript\" src=\"_static/js/theme.js\"></script>\n\n    \n\n  \n  <link rel=\"stylesheet\" href=\"_static/css/theme.css\" type=\"text/css\" />\n  <link rel=\"stylesheet\" href=\"_static/pygments.css\" type=\"text/css\" />\n    <link rel=\"index\" title=\"索引\" href=\"genindex.html\" />\n    <link rel=\"search\" title=\"搜索\" href=\"search.html\" /> \n</head>\n\n<body class=\"wy-body-for-nav\">\n\n   \n  <div class=\"wy-grid-for-nav\">\n    \n    <nav data-toggle=\"wy-nav-shift\" class=\"wy-nav-side\">\n      <div class=\"wy-side-scroll\">\n        <div class=\"wy-side-nav-search\" >\n          \n\n          \n            <a href=\"index.html\" class=\"icon icon-home\"> wukong-robot\n          \n\n          \n          </a>\n\n          \n            \n            \n          \n\n          \n<div role=\"search\">\n  <form id=\"rtd-search-form\" class=\"wy-form\" action=\"search.html\" method=\"get\">\n    <input type=\"text\" name=\"q\" placeholder=\"Search docs\" />\n    <input type=\"hidden\" name=\"check_keywords\" value=\"yes\" />\n    <input type=\"hidden\" name=\"area\" value=\"default\" />\n  </form>\n</div>\n\n          \n        </div>\n\n        <div class=\"wy-menu wy-menu-vertical\" data-spy=\"affix\" role=\"navigation\" aria-label=\"main navigation\">\n          \n            \n            \n              \n            \n            \n              <!-- Local TOC -->\n              <div class=\"local-toc\"><ul>\n<li><a class=\"reference internal\" href=\"#\">wukong-robot</a></li>\n</ul>\n</div>\n            \n          \n        </div>\n      </div>\n    </nav>\n\n    <section data-toggle=\"wy-nav-shift\" class=\"wy-nav-content-wrap\">\n\n      \n      <nav class=\"wy-nav-top\" aria-label=\"top navigation\">\n        \n          <i data-toggle=\"wy-nav-top\" class=\"fa fa-bars\"></i>\n          <a href=\"index.html\">wukong-robot</a>\n        \n      </nav>\n\n\n      <div class=\"wy-nav-content\">\n        \n        <div class=\"rst-content\">\n        \n          \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<div role=\"navigation\" aria-label=\"breadcrumbs navigation\">\n\n  <ul class=\"wy-breadcrumbs\">\n    \n      <li><a href=\"index.html\">Docs</a> &raquo;</li>\n        \n      <li>wukong-robot</li>\n    \n    \n      <li class=\"wy-breadcrumbs-aside\">\n        \n            \n            <a href=\"_sources/modules.rst.txt\" rel=\"nofollow\"> View page source</a>\n          \n        \n      </li>\n    \n  </ul>\n\n  \n  <hr/>\n</div>\n          <div role=\"main\" class=\"document\" itemscope=\"itemscope\" itemtype=\"http://schema.org/Article\">\n           <div itemprop=\"articleBody\">\n            \n  <div class=\"section\" id=\"wukong-robot\">\n<h1>wukong-robot<a class=\"headerlink\" href=\"#wukong-robot\" title=\"永久链接至标题\">¶</a></h1>\n<div class=\"toctree-wrapper compound\">\n<ul>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"plugins.html\">plugins package</a><ul>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"plugins.html#submodules\">Submodules</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"plugins.html#module-plugins.Camera\">plugins.Camera module</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"plugins.html#module-plugins.CleanCache\">plugins.CleanCache module</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"plugins.html#module-plugins.Echo\">plugins.Echo module</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"plugins.html#module-plugins.Email\">plugins.Email module</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"plugins.html#module-plugins.Geek\">plugins.Geek module</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"plugins.html#module-plugins.LocalPlayer\">plugins.LocalPlayer module</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"plugins.html#module-plugins.Poem\">plugins.Poem module</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"plugins.html#module-plugins\">Module contents</a></li>\n</ul>\n</li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"robot.html\">robot package</a><ul>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"robot.html#subpackages\">Subpackages</a><ul>\n<li class=\"toctree-l3\"><a class=\"reference internal\" href=\"robot.sdk.html\">robot.sdk package</a><ul>\n<li class=\"toctree-l4\"><a class=\"reference internal\" href=\"robot.sdk.html#submodules\">Submodules</a></li>\n<li class=\"toctree-l4\"><a class=\"reference internal\" href=\"robot.sdk.html#module-robot.sdk.AbstractPlugin\">robot.sdk.AbstractPlugin module</a></li>\n<li class=\"toctree-l4\"><a class=\"reference internal\" href=\"robot.sdk.html#module-robot.sdk.AliSpeech\">robot.sdk.AliSpeech module</a></li>\n<li class=\"toctree-l4\"><a class=\"reference internal\" href=\"robot.sdk.html#module-robot.sdk.RASRsdk\">robot.sdk.RASRsdk module</a></li>\n<li class=\"toctree-l4\"><a class=\"reference internal\" href=\"robot.sdk.html#module-robot.sdk.TencentSpeech\">robot.sdk.TencentSpeech module</a></li>\n<li class=\"toctree-l4\"><a class=\"reference internal\" href=\"robot.sdk.html#module-robot.sdk.XunfeiSpeech\">robot.sdk.XunfeiSpeech module</a></li>\n<li class=\"toctree-l4\"><a class=\"reference internal\" href=\"robot.sdk.html#module-robot.sdk.unit\">robot.sdk.unit module</a></li>\n<li class=\"toctree-l4\"><a class=\"reference internal\" href=\"robot.sdk.html#module-robot.sdk\">Module contents</a></li>\n</ul>\n</li>\n</ul>\n</li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"robot.html#submodules\">Submodules</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"robot.html#module-robot.AI\">robot.AI module</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"robot.html#module-robot.ASR\">robot.ASR module</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"robot.html#module-robot.Brain\">robot.Brain module</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"robot.html#module-robot.ConfigMonitor\">robot.ConfigMonitor module</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"robot.html#module-robot.Conversation\">robot.Conversation module</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"robot.html#module-robot.NLU\">robot.NLU module</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"robot.html#module-robot.Player\">robot.Player module</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"robot.html#module-robot.TTS\">robot.TTS module</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"robot.html#module-robot.Updater\">robot.Updater module</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"robot.html#module-robot.config\">robot.config module</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"robot.html#module-robot.constants\">robot.constants module</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"robot.html#module-robot.logging\">robot.logging module</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"robot.html#module-robot.plugin_loader\">robot.plugin_loader module</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"robot.html#module-robot.statistic\">robot.statistic module</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"robot.html#module-robot.utils\">robot.utils module</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"robot.html#module-robot\">Module contents</a></li>\n</ul>\n</li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"snowboy.html\">snowboy package</a><ul>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"snowboy.html#submodules\">Submodules</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"snowboy.html#module-snowboy.snowboydecoder\">snowboy.snowboydecoder module</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"snowboy.html#module-snowboy.snowboydetect\">snowboy.snowboydetect module</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"snowboy.html#module-snowboy\">Module contents</a></li>\n</ul>\n</li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"wukong.html\">wukong module</a></li>\n</ul>\n</div>\n</div>\n\n\n           </div>\n           \n          </div>\n          <footer>\n  \n\n  <hr/>\n\n  <div role=\"contentinfo\">\n    <p>\n        &copy; Copyright 2019, wzpan\n\n    </p>\n  </div>\n  Built with <a href=\"http://sphinx-doc.org/\">Sphinx</a> using a <a href=\"https://github.com/rtfd/sphinx_rtd_theme\">theme</a> provided by <a href=\"https://readthedocs.org\">Read the Docs</a>. \n\n</footer>\n\n        </div>\n      </div>\n\n    </section>\n\n  </div>\n  \n\n\n  <script type=\"text/javascript\">\n      jQuery(function () {\n          SphinxRtdTheme.Navigation.enable(true);\n      });\n  </script>\n\n  \n  \n    \n   \n\n</body>\n</html>"
  },
  {
    "path": "docs/plugin_loader.html",
    "content": "\n\n<!DOCTYPE html>\n<!--[if IE 8]><html class=\"no-js lt-ie9\" lang=\"zh-CN\" > <![endif]-->\n<!--[if gt IE 8]><!--> <html class=\"no-js\" lang=\"zh-CN\" > <!--<![endif]-->\n<head>\n  <meta charset=\"utf-8\">\n  \n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  \n  <title>plugin_loader module &mdash; wukong-robot 1.2.0 文档</title>\n  \n\n  \n  \n  \n  \n\n  \n  <script type=\"text/javascript\" src=\"_static/js/modernizr.min.js\"></script>\n  \n    \n      <script type=\"text/javascript\" id=\"documentation_options\" data-url_root=\"./\" src=\"_static/documentation_options.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/jquery.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/underscore.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/doctools.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/language_data.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/translations.js\"></script>\n    \n    <script type=\"text/javascript\" src=\"_static/js/theme.js\"></script>\n\n    \n\n  \n  <link rel=\"stylesheet\" href=\"_static/css/theme.css\" type=\"text/css\" />\n  <link rel=\"stylesheet\" href=\"_static/pygments.css\" type=\"text/css\" />\n    <link rel=\"index\" title=\"索引\" href=\"genindex.html\" />\n    <link rel=\"search\" title=\"搜索\" href=\"search.html\" /> \n</head>\n\n<body class=\"wy-body-for-nav\">\n\n   \n  <div class=\"wy-grid-for-nav\">\n    \n    <nav data-toggle=\"wy-nav-shift\" class=\"wy-nav-side\">\n      <div class=\"wy-side-scroll\">\n        <div class=\"wy-side-nav-search\" >\n          \n\n          \n            <a href=\"index.html\" class=\"icon icon-home\"> wukong-robot\n          \n\n          \n          </a>\n\n          \n            \n            \n          \n\n          \n<div role=\"search\">\n  <form id=\"rtd-search-form\" class=\"wy-form\" action=\"search.html\" method=\"get\">\n    <input type=\"text\" name=\"q\" placeholder=\"Search docs\" />\n    <input type=\"hidden\" name=\"check_keywords\" value=\"yes\" />\n    <input type=\"hidden\" name=\"area\" value=\"default\" />\n  </form>\n</div>\n\n          \n        </div>\n\n        <div class=\"wy-menu wy-menu-vertical\" data-spy=\"affix\" role=\"navigation\" aria-label=\"main navigation\">\n          \n            \n            \n              \n            \n            \n              <!-- Local TOC -->\n              <div class=\"local-toc\"><ul>\n<li><a class=\"reference internal\" href=\"#\">plugin_loader module</a></li>\n</ul>\n</div>\n            \n          \n        </div>\n      </div>\n    </nav>\n\n    <section data-toggle=\"wy-nav-shift\" class=\"wy-nav-content-wrap\">\n\n      \n      <nav class=\"wy-nav-top\" aria-label=\"top navigation\">\n        \n          <i data-toggle=\"wy-nav-top\" class=\"fa fa-bars\"></i>\n          <a href=\"index.html\">wukong-robot</a>\n        \n      </nav>\n\n\n      <div class=\"wy-nav-content\">\n        \n        <div class=\"rst-content\">\n        \n          \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<div role=\"navigation\" aria-label=\"breadcrumbs navigation\">\n\n  <ul class=\"wy-breadcrumbs\">\n    \n      <li><a href=\"index.html\">Docs</a> &raquo;</li>\n        \n      <li>plugin_loader module</li>\n    \n    \n      <li class=\"wy-breadcrumbs-aside\">\n        \n            \n            <a href=\"_sources/plugin_loader.rst.txt\" rel=\"nofollow\"> View page source</a>\n          \n        \n      </li>\n    \n  </ul>\n\n  \n  <hr/>\n</div>\n          <div role=\"main\" class=\"document\" itemscope=\"itemscope\" itemtype=\"http://schema.org/Article\">\n           <div itemprop=\"articleBody\">\n            \n  <div class=\"section\" id=\"plugin-loader-module\">\n<h1>plugin_loader module<a class=\"headerlink\" href=\"#plugin-loader-module\" title=\"永久链接至标题\">¶</a></h1>\n</div>\n\n\n           </div>\n           \n          </div>\n          <footer>\n  \n\n  <hr/>\n\n  <div role=\"contentinfo\">\n    <p>\n        &copy; Copyright 2019, wzpan\n\n    </p>\n  </div>\n  Built with <a href=\"http://sphinx-doc.org/\">Sphinx</a> using a <a href=\"https://github.com/rtfd/sphinx_rtd_theme\">theme</a> provided by <a href=\"https://readthedocs.org\">Read the Docs</a>. \n\n</footer>\n\n        </div>\n      </div>\n\n    </section>\n\n  </div>\n  \n\n\n  <script type=\"text/javascript\">\n      jQuery(function () {\n          SphinxRtdTheme.Navigation.enable(true);\n      });\n  </script>\n\n  \n  \n    \n   \n\n</body>\n</html>"
  },
  {
    "path": "docs/plugins.html",
    "content": "\n\n<!DOCTYPE html>\n<!--[if IE 8]><html class=\"no-js lt-ie9\" lang=\"zh-CN\" > <![endif]-->\n<!--[if gt IE 8]><!--> <html class=\"no-js\" lang=\"zh-CN\" > <!--<![endif]-->\n<head>\n  <meta charset=\"utf-8\">\n  \n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  \n  <title>plugins package &mdash; wukong-robot 1.2.0 文档</title>\n  \n\n  \n  \n  \n  \n\n  \n  <script type=\"text/javascript\" src=\"_static/js/modernizr.min.js\"></script>\n  \n    \n      <script type=\"text/javascript\" id=\"documentation_options\" data-url_root=\"./\" src=\"_static/documentation_options.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/jquery.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/underscore.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/doctools.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/language_data.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/translations.js\"></script>\n    \n    <script type=\"text/javascript\" src=\"_static/js/theme.js\"></script>\n\n    \n\n  \n  <link rel=\"stylesheet\" href=\"_static/css/theme.css\" type=\"text/css\" />\n  <link rel=\"stylesheet\" href=\"_static/pygments.css\" type=\"text/css\" />\n    <link rel=\"index\" title=\"索引\" href=\"genindex.html\" />\n    <link rel=\"search\" title=\"搜索\" href=\"search.html\" /> \n</head>\n\n<body class=\"wy-body-for-nav\">\n\n   \n  <div class=\"wy-grid-for-nav\">\n    \n    <nav data-toggle=\"wy-nav-shift\" class=\"wy-nav-side\">\n      <div class=\"wy-side-scroll\">\n        <div class=\"wy-side-nav-search\" >\n          \n\n          \n            <a href=\"index.html\" class=\"icon icon-home\"> wukong-robot\n          \n\n          \n          </a>\n\n          \n            \n            \n          \n\n          \n<div role=\"search\">\n  <form id=\"rtd-search-form\" class=\"wy-form\" action=\"search.html\" method=\"get\">\n    <input type=\"text\" name=\"q\" placeholder=\"Search docs\" />\n    <input type=\"hidden\" name=\"check_keywords\" value=\"yes\" />\n    <input type=\"hidden\" name=\"area\" value=\"default\" />\n  </form>\n</div>\n\n          \n        </div>\n\n        <div class=\"wy-menu wy-menu-vertical\" data-spy=\"affix\" role=\"navigation\" aria-label=\"main navigation\">\n          \n            \n            \n              \n            \n            \n              <!-- Local TOC -->\n              <div class=\"local-toc\"><ul>\n<li><a class=\"reference internal\" href=\"#\">plugins package</a><ul>\n<li><a class=\"reference internal\" href=\"#submodules\">Submodules</a></li>\n<li><a class=\"reference internal\" href=\"#module-plugins.Camera\">plugins.Camera module</a></li>\n<li><a class=\"reference internal\" href=\"#module-plugins.CleanCache\">plugins.CleanCache module</a></li>\n<li><a class=\"reference internal\" href=\"#module-plugins.Echo\">plugins.Echo module</a></li>\n<li><a class=\"reference internal\" href=\"#module-plugins.Email\">plugins.Email module</a></li>\n<li><a class=\"reference internal\" href=\"#module-plugins.Geek\">plugins.Geek module</a></li>\n<li><a class=\"reference internal\" href=\"#module-plugins.LocalPlayer\">plugins.LocalPlayer module</a></li>\n<li><a class=\"reference internal\" href=\"#module-plugins.Poem\">plugins.Poem module</a></li>\n<li><a class=\"reference internal\" href=\"#module-plugins\">Module contents</a></li>\n</ul>\n</li>\n</ul>\n</div>\n            \n          \n        </div>\n      </div>\n    </nav>\n\n    <section data-toggle=\"wy-nav-shift\" class=\"wy-nav-content-wrap\">\n\n      \n      <nav class=\"wy-nav-top\" aria-label=\"top navigation\">\n        \n          <i data-toggle=\"wy-nav-top\" class=\"fa fa-bars\"></i>\n          <a href=\"index.html\">wukong-robot</a>\n        \n      </nav>\n\n\n      <div class=\"wy-nav-content\">\n        \n        <div class=\"rst-content\">\n        \n          \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<div role=\"navigation\" aria-label=\"breadcrumbs navigation\">\n\n  <ul class=\"wy-breadcrumbs\">\n    \n      <li><a href=\"index.html\">Docs</a> &raquo;</li>\n        \n      <li>plugins package</li>\n    \n    \n      <li class=\"wy-breadcrumbs-aside\">\n        \n            \n            <a href=\"_sources/plugins.rst.txt\" rel=\"nofollow\"> View page source</a>\n          \n        \n      </li>\n    \n  </ul>\n\n  \n  <hr/>\n</div>\n          <div role=\"main\" class=\"document\" itemscope=\"itemscope\" itemtype=\"http://schema.org/Article\">\n           <div itemprop=\"articleBody\">\n            \n  <div class=\"section\" id=\"plugins-package\">\n<h1>plugins package<a class=\"headerlink\" href=\"#plugins-package\" title=\"永久链接至标题\">¶</a></h1>\n<div class=\"section\" id=\"submodules\">\n<h2>Submodules<a class=\"headerlink\" href=\"#submodules\" title=\"永久链接至标题\">¶</a></h2>\n</div>\n<div class=\"section\" id=\"module-plugins.Camera\">\n<span id=\"plugins-camera-module\"></span><h2>plugins.Camera module<a class=\"headerlink\" href=\"#module-plugins.Camera\" title=\"永久链接至标题\">¶</a></h2>\n<dl class=\"class\">\n<dt id=\"plugins.Camera.Plugin\">\n<em class=\"property\">class </em><code class=\"descclassname\">plugins.Camera.</code><code class=\"descname\">Plugin</code><span class=\"sig-paren\">(</span><em>con</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/plugins/Camera.html#Plugin\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#plugins.Camera.Plugin\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>基类：<a class=\"reference internal\" href=\"robot.sdk.html#robot.sdk.AbstractPlugin.AbstractPlugin\" title=\"robot.sdk.AbstractPlugin.AbstractPlugin\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">robot.sdk.AbstractPlugin.AbstractPlugin</span></code></a></p>\n<dl class=\"attribute\">\n<dt id=\"plugins.Camera.Plugin.SLUG\">\n<code class=\"descname\">SLUG</code><em class=\"property\"> = 'camera'</em><a class=\"headerlink\" href=\"#plugins.Camera.Plugin.SLUG\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"plugins.Camera.Plugin.handle\">\n<code class=\"descname\">handle</code><span class=\"sig-paren\">(</span><em>text</em>, <em>parsed</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/plugins/Camera.html#Plugin.handle\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#plugins.Camera.Plugin.handle\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>处理逻辑</p>\n<p>参数：\nquery – 用户的指令字符串\nparsed – 用户指令经过 NLU 解析后的结果</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"plugins.Camera.Plugin.isValid\">\n<code class=\"descname\">isValid</code><span class=\"sig-paren\">(</span><em>text</em>, <em>parsed</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/plugins/Camera.html#Plugin.isValid\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#plugins.Camera.Plugin.isValid\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>是否适合由该插件处理</p>\n<p>参数：\nquery – 用户的指令字符串\nparsed – 用户指令经过 NLU 解析后的结果</p>\n<p>返回：\nTrue: 适合由该插件处理\nFalse: 不适合由该插件处理</p>\n</dd></dl>\n\n</dd></dl>\n\n</div>\n<div class=\"section\" id=\"module-plugins.CleanCache\">\n<span id=\"plugins-cleancache-module\"></span><h2>plugins.CleanCache module<a class=\"headerlink\" href=\"#module-plugins.CleanCache\" title=\"永久链接至标题\">¶</a></h2>\n<dl class=\"class\">\n<dt id=\"plugins.CleanCache.Plugin\">\n<em class=\"property\">class </em><code class=\"descclassname\">plugins.CleanCache.</code><code class=\"descname\">Plugin</code><span class=\"sig-paren\">(</span><em>con</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/plugins/CleanCache.html#Plugin\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#plugins.CleanCache.Plugin\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>基类：<a class=\"reference internal\" href=\"robot.sdk.html#robot.sdk.AbstractPlugin.AbstractPlugin\" title=\"robot.sdk.AbstractPlugin.AbstractPlugin\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">robot.sdk.AbstractPlugin.AbstractPlugin</span></code></a></p>\n<dl class=\"attribute\">\n<dt id=\"plugins.CleanCache.Plugin.SLUG\">\n<code class=\"descname\">SLUG</code><em class=\"property\"> = 'cleancache'</em><a class=\"headerlink\" href=\"#plugins.CleanCache.Plugin.SLUG\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"plugins.CleanCache.Plugin.handle\">\n<code class=\"descname\">handle</code><span class=\"sig-paren\">(</span><em>text</em>, <em>parsed</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/plugins/CleanCache.html#Plugin.handle\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#plugins.CleanCache.Plugin.handle\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>处理逻辑</p>\n<p>参数：\nquery – 用户的指令字符串\nparsed – 用户指令经过 NLU 解析后的结果</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"plugins.CleanCache.Plugin.isValid\">\n<code class=\"descname\">isValid</code><span class=\"sig-paren\">(</span><em>text</em>, <em>parsed</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/plugins/CleanCache.html#Plugin.isValid\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#plugins.CleanCache.Plugin.isValid\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>是否适合由该插件处理</p>\n<p>参数：\nquery – 用户的指令字符串\nparsed – 用户指令经过 NLU 解析后的结果</p>\n<p>返回：\nTrue: 适合由该插件处理\nFalse: 不适合由该插件处理</p>\n</dd></dl>\n\n</dd></dl>\n\n</div>\n<div class=\"section\" id=\"module-plugins.Echo\">\n<span id=\"plugins-echo-module\"></span><h2>plugins.Echo module<a class=\"headerlink\" href=\"#module-plugins.Echo\" title=\"永久链接至标题\">¶</a></h2>\n<dl class=\"class\">\n<dt id=\"plugins.Echo.Plugin\">\n<em class=\"property\">class </em><code class=\"descclassname\">plugins.Echo.</code><code class=\"descname\">Plugin</code><span class=\"sig-paren\">(</span><em>con</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/plugins/Echo.html#Plugin\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#plugins.Echo.Plugin\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>基类：<a class=\"reference internal\" href=\"robot.sdk.html#robot.sdk.AbstractPlugin.AbstractPlugin\" title=\"robot.sdk.AbstractPlugin.AbstractPlugin\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">robot.sdk.AbstractPlugin.AbstractPlugin</span></code></a></p>\n<dl class=\"method\">\n<dt id=\"plugins.Echo.Plugin.handle\">\n<code class=\"descname\">handle</code><span class=\"sig-paren\">(</span><em>text</em>, <em>parsed</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/plugins/Echo.html#Plugin.handle\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#plugins.Echo.Plugin.handle\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>处理逻辑</p>\n<p>参数：\nquery – 用户的指令字符串\nparsed – 用户指令经过 NLU 解析后的结果</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"plugins.Echo.Plugin.isValid\">\n<code class=\"descname\">isValid</code><span class=\"sig-paren\">(</span><em>text</em>, <em>parsed</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/plugins/Echo.html#Plugin.isValid\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#plugins.Echo.Plugin.isValid\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>是否适合由该插件处理</p>\n<p>参数：\nquery – 用户的指令字符串\nparsed – 用户指令经过 NLU 解析后的结果</p>\n<p>返回：\nTrue: 适合由该插件处理\nFalse: 不适合由该插件处理</p>\n</dd></dl>\n\n</dd></dl>\n\n</div>\n<div class=\"section\" id=\"module-plugins.Email\">\n<span id=\"plugins-email-module\"></span><h2>plugins.Email module<a class=\"headerlink\" href=\"#module-plugins.Email\" title=\"永久链接至标题\">¶</a></h2>\n<dl class=\"class\">\n<dt id=\"plugins.Email.Plugin\">\n<em class=\"property\">class </em><code class=\"descclassname\">plugins.Email.</code><code class=\"descname\">Plugin</code><span class=\"sig-paren\">(</span><em>con</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/plugins/Email.html#Plugin\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#plugins.Email.Plugin\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>基类：<a class=\"reference internal\" href=\"robot.sdk.html#robot.sdk.AbstractPlugin.AbstractPlugin\" title=\"robot.sdk.AbstractPlugin.AbstractPlugin\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">robot.sdk.AbstractPlugin.AbstractPlugin</span></code></a></p>\n<dl class=\"attribute\">\n<dt id=\"plugins.Email.Plugin.SLUG\">\n<code class=\"descname\">SLUG</code><em class=\"property\"> = 'email'</em><a class=\"headerlink\" href=\"#plugins.Email.Plugin.SLUG\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"plugins.Email.Plugin.fetchUnreadEmails\">\n<code class=\"descname\">fetchUnreadEmails</code><span class=\"sig-paren\">(</span><em>since=None</em>, <em>markRead=False</em>, <em>limit=None</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/plugins/Email.html#Plugin.fetchUnreadEmails\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#plugins.Email.Plugin.fetchUnreadEmails\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Fetches a list of unread email objects from a user’s email inbox.</p>\n<p>Arguments:\nsince – if provided, no emails before this date will be returned\nmarkRead – if True, marks all returned emails as read in target inbox</p>\n<p>Returns:\nA list of unread email objects.</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"plugins.Email.Plugin.getDate\">\n<code class=\"descname\">getDate</code><span class=\"sig-paren\">(</span><em>email</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/plugins/Email.html#Plugin.getDate\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#plugins.Email.Plugin.getDate\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"plugins.Email.Plugin.getMostRecentDate\">\n<code class=\"descname\">getMostRecentDate</code><span class=\"sig-paren\">(</span><em>emails</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/plugins/Email.html#Plugin.getMostRecentDate\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#plugins.Email.Plugin.getMostRecentDate\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Returns the most recent date of any email in the list provided.</p>\n<p>Arguments:\nemails – a list of emails to check</p>\n<p>Returns:\nDate of the most recent email.</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"plugins.Email.Plugin.getSender\">\n<code class=\"descname\">getSender</code><span class=\"sig-paren\">(</span><em>msg</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/plugins/Email.html#Plugin.getSender\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#plugins.Email.Plugin.getSender\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Returns the best-guess sender of an email.</p>\n<p>Arguments:\nmsg – the email whose sender is desired</p>\n<p>Returns:\nSender of the sender.</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"plugins.Email.Plugin.getSubject\">\n<code class=\"descname\">getSubject</code><span class=\"sig-paren\">(</span><em>msg</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/plugins/Email.html#Plugin.getSubject\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#plugins.Email.Plugin.getSubject\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Returns the title of an email</p>\n<p>Arguments:\nmsg – the email</p>\n<p>Returns:\nTitle of the email.</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"plugins.Email.Plugin.handle\">\n<code class=\"descname\">handle</code><span class=\"sig-paren\">(</span><em>text</em>, <em>parsed</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/plugins/Email.html#Plugin.handle\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#plugins.Email.Plugin.handle\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>处理逻辑</p>\n<p>参数：\nquery – 用户的指令字符串\nparsed – 用户指令经过 NLU 解析后的结果</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"plugins.Email.Plugin.isNewEmail\">\n<code class=\"descname\">isNewEmail</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/plugins/Email.html#Plugin.isNewEmail\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#plugins.Email.Plugin.isNewEmail\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Wether an email is a new email</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"plugins.Email.Plugin.isSelfEmail\">\n<code class=\"descname\">isSelfEmail</code><span class=\"sig-paren\">(</span><em>msg</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/plugins/Email.html#Plugin.isSelfEmail\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#plugins.Email.Plugin.isSelfEmail\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Whether the email is sent by the user</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"plugins.Email.Plugin.isValid\">\n<code class=\"descname\">isValid</code><span class=\"sig-paren\">(</span><em>text</em>, <em>parsed</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/plugins/Email.html#Plugin.isValid\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#plugins.Email.Plugin.isValid\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>是否适合由该插件处理</p>\n<p>参数：\nquery – 用户的指令字符串\nparsed – 用户指令经过 NLU 解析后的结果</p>\n<p>返回：\nTrue: 适合由该插件处理\nFalse: 不适合由该插件处理</p>\n</dd></dl>\n\n</dd></dl>\n\n</div>\n<div class=\"section\" id=\"module-plugins.Geek\">\n<span id=\"plugins-geek-module\"></span><h2>plugins.Geek module<a class=\"headerlink\" href=\"#module-plugins.Geek\" title=\"永久链接至标题\">¶</a></h2>\n<dl class=\"class\">\n<dt id=\"plugins.Geek.Plugin\">\n<em class=\"property\">class </em><code class=\"descclassname\">plugins.Geek.</code><code class=\"descname\">Plugin</code><span class=\"sig-paren\">(</span><em>con</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/plugins/Geek.html#Plugin\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#plugins.Geek.Plugin\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>基类：<a class=\"reference internal\" href=\"robot.sdk.html#robot.sdk.AbstractPlugin.AbstractPlugin\" title=\"robot.sdk.AbstractPlugin.AbstractPlugin\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">robot.sdk.AbstractPlugin.AbstractPlugin</span></code></a></p>\n<dl class=\"attribute\">\n<dt id=\"plugins.Geek.Plugin.IS_IMMERSIVE\">\n<code class=\"descname\">IS_IMMERSIVE</code><em class=\"property\"> = True</em><a class=\"headerlink\" href=\"#plugins.Geek.Plugin.IS_IMMERSIVE\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"plugins.Geek.Plugin.handle\">\n<code class=\"descname\">handle</code><span class=\"sig-paren\">(</span><em>text</em>, <em>parsed</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/plugins/Geek.html#Plugin.handle\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#plugins.Geek.Plugin.handle\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>处理逻辑</p>\n<p>参数：\nquery – 用户的指令字符串\nparsed – 用户指令经过 NLU 解析后的结果</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"plugins.Geek.Plugin.isValid\">\n<code class=\"descname\">isValid</code><span class=\"sig-paren\">(</span><em>text</em>, <em>parsed</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/plugins/Geek.html#Plugin.isValid\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#plugins.Geek.Plugin.isValid\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>是否适合由该插件处理</p>\n<p>参数：\nquery – 用户的指令字符串\nparsed – 用户指令经过 NLU 解析后的结果</p>\n<p>返回：\nTrue: 适合由该插件处理\nFalse: 不适合由该插件处理</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"plugins.Geek.Plugin.isValidImmersive\">\n<code class=\"descname\">isValidImmersive</code><span class=\"sig-paren\">(</span><em>text</em>, <em>parsed</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/plugins/Geek.html#Plugin.isValidImmersive\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#plugins.Geek.Plugin.isValidImmersive\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>是否适合在沉浸模式下处理，\n仅适用于有沉浸模式的插件（如音乐等）\n当用户唤醒时，可以响应更多指令集。\n例如：“”上一首”、”下一首” 等</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"plugins.Geek.Plugin.onAsk\">\n<code class=\"descname\">onAsk</code><span class=\"sig-paren\">(</span><em>input</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/plugins/Geek.html#Plugin.onAsk\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#plugins.Geek.Plugin.onAsk\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"plugins.Geek.Plugin.restore\">\n<code class=\"descname\">restore</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/plugins/Geek.html#Plugin.restore\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#plugins.Geek.Plugin.restore\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>恢复当前插件，\n仅适用于有沉浸模式的插件（如音乐等）\n当用户误唤醒或者唤醒进行闲聊后，\n可以自动恢复当前插件的处理逻辑</p>\n</dd></dl>\n\n</dd></dl>\n\n</div>\n<div class=\"section\" id=\"module-plugins.LocalPlayer\">\n<span id=\"plugins-localplayer-module\"></span><h2>plugins.LocalPlayer module<a class=\"headerlink\" href=\"#module-plugins.LocalPlayer\" title=\"永久链接至标题\">¶</a></h2>\n<dl class=\"class\">\n<dt id=\"plugins.LocalPlayer.Plugin\">\n<em class=\"property\">class </em><code class=\"descclassname\">plugins.LocalPlayer.</code><code class=\"descname\">Plugin</code><span class=\"sig-paren\">(</span><em>con</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/plugins/LocalPlayer.html#Plugin\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#plugins.LocalPlayer.Plugin\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>基类：<a class=\"reference internal\" href=\"robot.sdk.html#robot.sdk.AbstractPlugin.AbstractPlugin\" title=\"robot.sdk.AbstractPlugin.AbstractPlugin\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">robot.sdk.AbstractPlugin.AbstractPlugin</span></code></a></p>\n<dl class=\"attribute\">\n<dt id=\"plugins.LocalPlayer.Plugin.IS_IMMERSIVE\">\n<code class=\"descname\">IS_IMMERSIVE</code><em class=\"property\"> = True</em><a class=\"headerlink\" href=\"#plugins.LocalPlayer.Plugin.IS_IMMERSIVE\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"plugins.LocalPlayer.Plugin.get_song_list\">\n<code class=\"descname\">get_song_list</code><span class=\"sig-paren\">(</span><em>path</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/plugins/LocalPlayer.html#Plugin.get_song_list\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#plugins.LocalPlayer.Plugin.get_song_list\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"plugins.LocalPlayer.Plugin.handle\">\n<code class=\"descname\">handle</code><span class=\"sig-paren\">(</span><em>text</em>, <em>parsed</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/plugins/LocalPlayer.html#Plugin.handle\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#plugins.LocalPlayer.Plugin.handle\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>处理逻辑</p>\n<p>参数：\nquery – 用户的指令字符串\nparsed – 用户指令经过 NLU 解析后的结果</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"plugins.LocalPlayer.Plugin.init_music_player\">\n<code class=\"descname\">init_music_player</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/plugins/LocalPlayer.html#Plugin.init_music_player\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#plugins.LocalPlayer.Plugin.init_music_player\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"plugins.LocalPlayer.Plugin.isValid\">\n<code class=\"descname\">isValid</code><span class=\"sig-paren\">(</span><em>text</em>, <em>parsed</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/plugins/LocalPlayer.html#Plugin.isValid\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#plugins.LocalPlayer.Plugin.isValid\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>是否适合由该插件处理</p>\n<p>参数：\nquery – 用户的指令字符串\nparsed – 用户指令经过 NLU 解析后的结果</p>\n<p>返回：\nTrue: 适合由该插件处理\nFalse: 不适合由该插件处理</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"plugins.LocalPlayer.Plugin.isValidImmersive\">\n<code class=\"descname\">isValidImmersive</code><span class=\"sig-paren\">(</span><em>text</em>, <em>parsed</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/plugins/LocalPlayer.html#Plugin.isValidImmersive\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#plugins.LocalPlayer.Plugin.isValidImmersive\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>是否适合在沉浸模式下处理，\n仅适用于有沉浸模式的插件（如音乐等）\n当用户唤醒时，可以响应更多指令集。\n例如：“”上一首”、”下一首” 等</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"plugins.LocalPlayer.Plugin.pause\">\n<code class=\"descname\">pause</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/plugins/LocalPlayer.html#Plugin.pause\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#plugins.LocalPlayer.Plugin.pause\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>暂停当前正在处理的任务，\n当处于该沉浸模式下且被唤醒时，\n将自动触发这个方法，\n可以用于强制暂停一个耗时的操作</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"plugins.LocalPlayer.Plugin.restore\">\n<code class=\"descname\">restore</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/plugins/LocalPlayer.html#Plugin.restore\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#plugins.LocalPlayer.Plugin.restore\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>恢复当前插件，\n仅适用于有沉浸模式的插件（如音乐等）\n当用户误唤醒或者唤醒进行闲聊后，\n可以自动恢复当前插件的处理逻辑</p>\n</dd></dl>\n\n</dd></dl>\n\n</div>\n<div class=\"section\" id=\"module-plugins.Poem\">\n<span id=\"plugins-poem-module\"></span><h2>plugins.Poem module<a class=\"headerlink\" href=\"#module-plugins.Poem\" title=\"永久链接至标题\">¶</a></h2>\n<dl class=\"class\">\n<dt id=\"plugins.Poem.Plugin\">\n<em class=\"property\">class </em><code class=\"descclassname\">plugins.Poem.</code><code class=\"descname\">Plugin</code><span class=\"sig-paren\">(</span><em>con</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/plugins/Poem.html#Plugin\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#plugins.Poem.Plugin\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>基类：<a class=\"reference internal\" href=\"robot.sdk.html#robot.sdk.AbstractPlugin.AbstractPlugin\" title=\"robot.sdk.AbstractPlugin.AbstractPlugin\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">robot.sdk.AbstractPlugin.AbstractPlugin</span></code></a></p>\n<dl class=\"attribute\">\n<dt id=\"plugins.Poem.Plugin.SLUG\">\n<code class=\"descname\">SLUG</code><em class=\"property\"> = 'poem'</em><a class=\"headerlink\" href=\"#plugins.Poem.Plugin.SLUG\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"plugins.Poem.Plugin.handle\">\n<code class=\"descname\">handle</code><span class=\"sig-paren\">(</span><em>text</em>, <em>parsed</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/plugins/Poem.html#Plugin.handle\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#plugins.Poem.Plugin.handle\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>处理逻辑</p>\n<p>参数：\nquery – 用户的指令字符串\nparsed – 用户指令经过 NLU 解析后的结果</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"plugins.Poem.Plugin.isValid\">\n<code class=\"descname\">isValid</code><span class=\"sig-paren\">(</span><em>text</em>, <em>parsed</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/plugins/Poem.html#Plugin.isValid\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#plugins.Poem.Plugin.isValid\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>是否适合由该插件处理</p>\n<p>参数：\nquery – 用户的指令字符串\nparsed – 用户指令经过 NLU 解析后的结果</p>\n<p>返回：\nTrue: 适合由该插件处理\nFalse: 不适合由该插件处理</p>\n</dd></dl>\n\n</dd></dl>\n\n</div>\n<div class=\"section\" id=\"module-plugins\">\n<span id=\"module-contents\"></span><h2>Module contents<a class=\"headerlink\" href=\"#module-plugins\" title=\"永久链接至标题\">¶</a></h2>\n</div>\n</div>\n\n\n           </div>\n           \n          </div>\n          <footer>\n  \n\n  <hr/>\n\n  <div role=\"contentinfo\">\n    <p>\n        &copy; Copyright 2019, wzpan\n\n    </p>\n  </div>\n  Built with <a href=\"http://sphinx-doc.org/\">Sphinx</a> using a <a href=\"https://github.com/rtfd/sphinx_rtd_theme\">theme</a> provided by <a href=\"https://readthedocs.org\">Read the Docs</a>. \n\n</footer>\n\n        </div>\n      </div>\n\n    </section>\n\n  </div>\n  \n\n\n  <script type=\"text/javascript\">\n      jQuery(function () {\n          SphinxRtdTheme.Navigation.enable(true);\n      });\n  </script>\n\n  \n  \n    \n   \n\n</body>\n</html>"
  },
  {
    "path": "docs/py-modindex.html",
    "content": "\n\n<!DOCTYPE html>\n<!--[if IE 8]><html class=\"no-js lt-ie9\" lang=\"zh-CN\" > <![endif]-->\n<!--[if gt IE 8]><!--> <html class=\"no-js\" lang=\"zh-CN\" > <!--<![endif]-->\n<head>\n  <meta charset=\"utf-8\">\n  \n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  \n  <title>Python 模块索引 &mdash; wukong-robot 1.2.0 文档</title>\n  \n\n  \n  \n  \n  \n\n  \n  <script type=\"text/javascript\" src=\"_static/js/modernizr.min.js\"></script>\n  \n    \n      <script type=\"text/javascript\" id=\"documentation_options\" data-url_root=\"./\" src=\"_static/documentation_options.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/jquery.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/underscore.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/doctools.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/language_data.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/translations.js\"></script>\n    \n    <script type=\"text/javascript\" src=\"_static/js/theme.js\"></script>\n\n    \n\n  \n  <link rel=\"stylesheet\" href=\"_static/css/theme.css\" type=\"text/css\" />\n  <link rel=\"stylesheet\" href=\"_static/pygments.css\" type=\"text/css\" />\n    <link rel=\"index\" title=\"索引\" href=\"genindex.html\" />\n    <link rel=\"search\" title=\"搜索\" href=\"search.html\" />\n \n\n\n</head>\n\n<body class=\"wy-body-for-nav\">\n\n   \n  <div class=\"wy-grid-for-nav\">\n    \n    <nav data-toggle=\"wy-nav-shift\" class=\"wy-nav-side\">\n      <div class=\"wy-side-scroll\">\n        <div class=\"wy-side-nav-search\" >\n          \n\n          \n            <a href=\"index.html\" class=\"icon icon-home\"> wukong-robot\n          \n\n          \n          </a>\n\n          \n            \n            \n          \n\n          \n<div role=\"search\">\n  <form id=\"rtd-search-form\" class=\"wy-form\" action=\"search.html\" method=\"get\">\n    <input type=\"text\" name=\"q\" placeholder=\"Search docs\" />\n    <input type=\"hidden\" name=\"check_keywords\" value=\"yes\" />\n    <input type=\"hidden\" name=\"area\" value=\"default\" />\n  </form>\n</div>\n\n          \n        </div>\n\n        <div class=\"wy-menu wy-menu-vertical\" data-spy=\"affix\" role=\"navigation\" aria-label=\"main navigation\">\n          \n            \n            \n              \n            \n            \n              <!-- Local TOC -->\n              <div class=\"local-toc\"></div>\n            \n          \n        </div>\n      </div>\n    </nav>\n\n    <section data-toggle=\"wy-nav-shift\" class=\"wy-nav-content-wrap\">\n\n      \n      <nav class=\"wy-nav-top\" aria-label=\"top navigation\">\n        \n          <i data-toggle=\"wy-nav-top\" class=\"fa fa-bars\"></i>\n          <a href=\"index.html\">wukong-robot</a>\n        \n      </nav>\n\n\n      <div class=\"wy-nav-content\">\n        \n        <div class=\"rst-content\">\n        \n          \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<div role=\"navigation\" aria-label=\"breadcrumbs navigation\">\n\n  <ul class=\"wy-breadcrumbs\">\n    \n      <li><a href=\"index.html\">Docs</a> &raquo;</li>\n        \n      <li>Python 模块索引</li>\n    \n    \n      <li class=\"wy-breadcrumbs-aside\">\n        \n      </li>\n    \n  </ul>\n\n  \n  <hr/>\n</div>\n          <div role=\"main\" class=\"document\" itemscope=\"itemscope\" itemtype=\"http://schema.org/Article\">\n           <div itemprop=\"articleBody\">\n            \n\n   <h1>Python 模块索引</h1>\n\n   <div class=\"modindex-jumpbox\">\n   <a href=\"#cap-p\"><strong>p</strong></a> | \n   <a href=\"#cap-r\"><strong>r</strong></a> | \n   <a href=\"#cap-s\"><strong>s</strong></a> | \n   <a href=\"#cap-w\"><strong>w</strong></a>\n   </div>\n\n   <table class=\"indextable modindextable\">\n     <tr class=\"pcap\"><td></td><td>&#160;</td><td></td></tr>\n     <tr class=\"cap\" id=\"cap-p\"><td></td><td>\n       <strong>p</strong></td><td></td></tr>\n     <tr>\n       <td><img src=\"_static/minus.png\" class=\"toggler\"\n              id=\"toggle-1\" style=\"display: none\" alt=\"-\" /></td>\n       <td>\n       <a href=\"plugins.html#module-plugins\"><code class=\"xref\">plugins</code></a></td><td>\n       <em></em></td></tr>\n     <tr class=\"cg-1\">\n       <td></td>\n       <td>&#160;&#160;&#160;\n       <a href=\"plugins.html#module-plugins.Camera\"><code class=\"xref\">plugins.Camera</code></a></td><td>\n       <em></em></td></tr>\n     <tr class=\"cg-1\">\n       <td></td>\n       <td>&#160;&#160;&#160;\n       <a href=\"plugins.html#module-plugins.CleanCache\"><code class=\"xref\">plugins.CleanCache</code></a></td><td>\n       <em></em></td></tr>\n     <tr class=\"cg-1\">\n       <td></td>\n       <td>&#160;&#160;&#160;\n       <a href=\"plugins.html#module-plugins.Echo\"><code class=\"xref\">plugins.Echo</code></a></td><td>\n       <em></em></td></tr>\n     <tr class=\"cg-1\">\n       <td></td>\n       <td>&#160;&#160;&#160;\n       <a href=\"plugins.html#module-plugins.Email\"><code class=\"xref\">plugins.Email</code></a></td><td>\n       <em></em></td></tr>\n     <tr class=\"cg-1\">\n       <td></td>\n       <td>&#160;&#160;&#160;\n       <a href=\"plugins.html#module-plugins.Geek\"><code class=\"xref\">plugins.Geek</code></a></td><td>\n       <em></em></td></tr>\n     <tr class=\"cg-1\">\n       <td></td>\n       <td>&#160;&#160;&#160;\n       <a href=\"plugins.html#module-plugins.LocalPlayer\"><code class=\"xref\">plugins.LocalPlayer</code></a></td><td>\n       <em></em></td></tr>\n     <tr class=\"cg-1\">\n       <td></td>\n       <td>&#160;&#160;&#160;\n       <a href=\"plugins.html#module-plugins.Poem\"><code class=\"xref\">plugins.Poem</code></a></td><td>\n       <em></em></td></tr>\n     <tr class=\"pcap\"><td></td><td>&#160;</td><td></td></tr>\n     <tr class=\"cap\" id=\"cap-r\"><td></td><td>\n       <strong>r</strong></td><td></td></tr>\n     <tr>\n       <td><img src=\"_static/minus.png\" class=\"toggler\"\n              id=\"toggle-2\" style=\"display: none\" alt=\"-\" /></td>\n       <td>\n       <a href=\"robot.html#module-robot\"><code class=\"xref\">robot</code></a></td><td>\n       <em></em></td></tr>\n     <tr class=\"cg-2\">\n       <td></td>\n       <td>&#160;&#160;&#160;\n       <a href=\"robot.html#module-robot.AI\"><code class=\"xref\">robot.AI</code></a></td><td>\n       <em></em></td></tr>\n     <tr class=\"cg-2\">\n       <td></td>\n       <td>&#160;&#160;&#160;\n       <a href=\"robot.html#module-robot.ASR\"><code class=\"xref\">robot.ASR</code></a></td><td>\n       <em></em></td></tr>\n     <tr class=\"cg-2\">\n       <td></td>\n       <td>&#160;&#160;&#160;\n       <a href=\"robot.html#module-robot.Brain\"><code class=\"xref\">robot.Brain</code></a></td><td>\n       <em></em></td></tr>\n     <tr class=\"cg-2\">\n       <td></td>\n       <td>&#160;&#160;&#160;\n       <a href=\"robot.html#module-robot.config\"><code class=\"xref\">robot.config</code></a></td><td>\n       <em></em></td></tr>\n     <tr class=\"cg-2\">\n       <td></td>\n       <td>&#160;&#160;&#160;\n       <a href=\"robot.html#module-robot.ConfigMonitor\"><code class=\"xref\">robot.ConfigMonitor</code></a></td><td>\n       <em></em></td></tr>\n     <tr class=\"cg-2\">\n       <td></td>\n       <td>&#160;&#160;&#160;\n       <a href=\"robot.html#module-robot.constants\"><code class=\"xref\">robot.constants</code></a></td><td>\n       <em></em></td></tr>\n     <tr class=\"cg-2\">\n       <td></td>\n       <td>&#160;&#160;&#160;\n       <a href=\"robot.html#module-robot.Conversation\"><code class=\"xref\">robot.Conversation</code></a></td><td>\n       <em></em></td></tr>\n     <tr class=\"cg-2\">\n       <td></td>\n       <td>&#160;&#160;&#160;\n       <a href=\"robot.drivers.html#module-robot.drivers\"><code class=\"xref\">robot.drivers</code></a></td><td>\n       <em></em></td></tr>\n     <tr class=\"cg-2\">\n       <td></td>\n       <td>&#160;&#160;&#160;\n       <a href=\"robot.html#module-robot.logging\"><code class=\"xref\">robot.logging</code></a></td><td>\n       <em></em></td></tr>\n     <tr class=\"cg-2\">\n       <td></td>\n       <td>&#160;&#160;&#160;\n       <a href=\"robot.html#module-robot.NLU\"><code class=\"xref\">robot.NLU</code></a></td><td>\n       <em></em></td></tr>\n     <tr class=\"cg-2\">\n       <td></td>\n       <td>&#160;&#160;&#160;\n       <a href=\"robot.html#module-robot.Player\"><code class=\"xref\">robot.Player</code></a></td><td>\n       <em></em></td></tr>\n     <tr class=\"cg-2\">\n       <td></td>\n       <td>&#160;&#160;&#160;\n       <a href=\"robot.html#module-robot.plugin_loader\"><code class=\"xref\">robot.plugin_loader</code></a></td><td>\n       <em></em></td></tr>\n     <tr class=\"cg-2\">\n       <td></td>\n       <td>&#160;&#160;&#160;\n       <a href=\"robot.sdk.html#module-robot.sdk\"><code class=\"xref\">robot.sdk</code></a></td><td>\n       <em></em></td></tr>\n     <tr class=\"cg-2\">\n       <td></td>\n       <td>&#160;&#160;&#160;\n       <a href=\"robot.sdk.html#module-robot.sdk.AbstractPlugin\"><code class=\"xref\">robot.sdk.AbstractPlugin</code></a></td><td>\n       <em></em></td></tr>\n     <tr class=\"cg-2\">\n       <td></td>\n       <td>&#160;&#160;&#160;\n       <a href=\"robot.sdk.html#module-robot.sdk.AliSpeech\"><code class=\"xref\">robot.sdk.AliSpeech</code></a></td><td>\n       <em></em></td></tr>\n     <tr class=\"cg-2\">\n       <td></td>\n       <td>&#160;&#160;&#160;\n       <a href=\"robot.sdk.html#module-robot.sdk.RASRsdk\"><code class=\"xref\">robot.sdk.RASRsdk</code></a></td><td>\n       <em></em></td></tr>\n     <tr class=\"cg-2\">\n       <td></td>\n       <td>&#160;&#160;&#160;\n       <a href=\"robot.sdk.html#module-robot.sdk.TencentSpeech\"><code class=\"xref\">robot.sdk.TencentSpeech</code></a></td><td>\n       <em></em></td></tr>\n     <tr class=\"cg-2\">\n       <td></td>\n       <td>&#160;&#160;&#160;\n       <a href=\"robot.sdk.html#module-robot.sdk.unit\"><code class=\"xref\">robot.sdk.unit</code></a></td><td>\n       <em></em></td></tr>\n     <tr class=\"cg-2\">\n       <td></td>\n       <td>&#160;&#160;&#160;\n       <a href=\"robot.sdk.html#module-robot.sdk.XunfeiSpeech\"><code class=\"xref\">robot.sdk.XunfeiSpeech</code></a></td><td>\n       <em></em></td></tr>\n     <tr class=\"cg-2\">\n       <td></td>\n       <td>&#160;&#160;&#160;\n       <a href=\"robot.html#module-robot.statistic\"><code class=\"xref\">robot.statistic</code></a></td><td>\n       <em></em></td></tr>\n     <tr class=\"cg-2\">\n       <td></td>\n       <td>&#160;&#160;&#160;\n       <a href=\"robot.html#module-robot.TTS\"><code class=\"xref\">robot.TTS</code></a></td><td>\n       <em></em></td></tr>\n     <tr class=\"cg-2\">\n       <td></td>\n       <td>&#160;&#160;&#160;\n       <a href=\"robot.html#module-robot.Updater\"><code class=\"xref\">robot.Updater</code></a></td><td>\n       <em></em></td></tr>\n     <tr class=\"cg-2\">\n       <td></td>\n       <td>&#160;&#160;&#160;\n       <a href=\"robot.html#module-robot.utils\"><code class=\"xref\">robot.utils</code></a></td><td>\n       <em></em></td></tr>\n     <tr class=\"pcap\"><td></td><td>&#160;</td><td></td></tr>\n     <tr class=\"cap\" id=\"cap-s\"><td></td><td>\n       <strong>s</strong></td><td></td></tr>\n     <tr>\n       <td><img src=\"_static/minus.png\" class=\"toggler\"\n              id=\"toggle-3\" style=\"display: none\" alt=\"-\" /></td>\n       <td>\n       <a href=\"snowboy.html#module-snowboy\"><code class=\"xref\">snowboy</code></a></td><td>\n       <em></em></td></tr>\n     <tr class=\"cg-3\">\n       <td></td>\n       <td>&#160;&#160;&#160;\n       <a href=\"snowboy.html#module-snowboy.snowboydecoder\"><code class=\"xref\">snowboy.snowboydecoder</code></a></td><td>\n       <em></em></td></tr>\n     <tr class=\"cg-3\">\n       <td></td>\n       <td>&#160;&#160;&#160;\n       <a href=\"snowboy.html#module-snowboy.snowboydetect\"><code class=\"xref\">snowboy.snowboydetect</code></a></td><td>\n       <em></em></td></tr>\n     <tr class=\"pcap\"><td></td><td>&#160;</td><td></td></tr>\n     <tr class=\"cap\" id=\"cap-w\"><td></td><td>\n       <strong>w</strong></td><td></td></tr>\n     <tr>\n       <td></td>\n       <td>\n       <a href=\"wukong.html#module-wukong\"><code class=\"xref\">wukong</code></a></td><td>\n       <em></em></td></tr>\n   </table>\n\n\n           </div>\n           \n          </div>\n          <footer>\n  \n\n  <hr/>\n\n  <div role=\"contentinfo\">\n    <p>\n        &copy; Copyright 2019, wzpan\n\n    </p>\n  </div>\n  Built with <a href=\"http://sphinx-doc.org/\">Sphinx</a> using a <a href=\"https://github.com/rtfd/sphinx_rtd_theme\">theme</a> provided by <a href=\"https://readthedocs.org\">Read the Docs</a>. \n\n</footer>\n\n        </div>\n      </div>\n\n    </section>\n\n  </div>\n  \n\n\n  <script type=\"text/javascript\">\n      jQuery(function () {\n          SphinxRtdTheme.Navigation.enable(true);\n      });\n  </script>\n\n  \n  \n    \n   \n\n</body>\n</html>"
  },
  {
    "path": "docs/robot.drivers.html",
    "content": "\n\n<!DOCTYPE html>\n<!--[if IE 8]><html class=\"no-js lt-ie9\" lang=\"zh-CN\" > <![endif]-->\n<!--[if gt IE 8]><!--> <html class=\"no-js\" lang=\"zh-CN\" > <!--<![endif]-->\n<head>\n  <meta charset=\"utf-8\">\n  \n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  \n  <title>robot.drivers package &mdash; wukong-robot 1.2.0 文档</title>\n  \n\n  \n  \n  \n  \n\n  \n  <script type=\"text/javascript\" src=\"_static/js/modernizr.min.js\"></script>\n  \n    \n      <script type=\"text/javascript\" id=\"documentation_options\" data-url_root=\"./\" src=\"_static/documentation_options.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/jquery.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/underscore.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/doctools.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/language_data.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/translations.js\"></script>\n    \n    <script type=\"text/javascript\" src=\"_static/js/theme.js\"></script>\n\n    \n\n  \n  <link rel=\"stylesheet\" href=\"_static/css/theme.css\" type=\"text/css\" />\n  <link rel=\"stylesheet\" href=\"_static/pygments.css\" type=\"text/css\" />\n    <link rel=\"index\" title=\"索引\" href=\"genindex.html\" />\n    <link rel=\"search\" title=\"搜索\" href=\"search.html\" /> \n</head>\n\n<body class=\"wy-body-for-nav\">\n\n   \n  <div class=\"wy-grid-for-nav\">\n    \n    <nav data-toggle=\"wy-nav-shift\" class=\"wy-nav-side\">\n      <div class=\"wy-side-scroll\">\n        <div class=\"wy-side-nav-search\" >\n          \n\n          \n            <a href=\"index.html\" class=\"icon icon-home\"> wukong-robot\n          \n\n          \n          </a>\n\n          \n            \n            \n          \n\n          \n<div role=\"search\">\n  <form id=\"rtd-search-form\" class=\"wy-form\" action=\"search.html\" method=\"get\">\n    <input type=\"text\" name=\"q\" placeholder=\"Search docs\" />\n    <input type=\"hidden\" name=\"check_keywords\" value=\"yes\" />\n    <input type=\"hidden\" name=\"area\" value=\"default\" />\n  </form>\n</div>\n\n          \n        </div>\n\n        <div class=\"wy-menu wy-menu-vertical\" data-spy=\"affix\" role=\"navigation\" aria-label=\"main navigation\">\n          \n            \n            \n              \n            \n            \n              <!-- Local TOC -->\n              <div class=\"local-toc\"><ul>\n<li><a class=\"reference internal\" href=\"#\">robot.drivers package</a><ul>\n<li><a class=\"reference internal\" href=\"#submodules\">Submodules</a></li>\n<li><a class=\"reference internal\" href=\"#robot-drivers-apa102-module\">robot.drivers.apa102 module</a></li>\n<li><a class=\"reference internal\" href=\"#robot-drivers-pixels-module\">robot.drivers.pixels module</a></li>\n<li><a class=\"reference internal\" href=\"#module-robot.drivers\">Module contents</a></li>\n</ul>\n</li>\n</ul>\n</div>\n            \n          \n        </div>\n      </div>\n    </nav>\n\n    <section data-toggle=\"wy-nav-shift\" class=\"wy-nav-content-wrap\">\n\n      \n      <nav class=\"wy-nav-top\" aria-label=\"top navigation\">\n        \n          <i data-toggle=\"wy-nav-top\" class=\"fa fa-bars\"></i>\n          <a href=\"index.html\">wukong-robot</a>\n        \n      </nav>\n\n\n      <div class=\"wy-nav-content\">\n        \n        <div class=\"rst-content\">\n        \n          \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<div role=\"navigation\" aria-label=\"breadcrumbs navigation\">\n\n  <ul class=\"wy-breadcrumbs\">\n    \n      <li><a href=\"index.html\">Docs</a> &raquo;</li>\n        \n      <li>robot.drivers package</li>\n    \n    \n      <li class=\"wy-breadcrumbs-aside\">\n        \n            \n            <a href=\"_sources/robot.drivers.rst.txt\" rel=\"nofollow\"> View page source</a>\n          \n        \n      </li>\n    \n  </ul>\n\n  \n  <hr/>\n</div>\n          <div role=\"main\" class=\"document\" itemscope=\"itemscope\" itemtype=\"http://schema.org/Article\">\n           <div itemprop=\"articleBody\">\n            \n  <div class=\"section\" id=\"robot-drivers-package\">\n<h1>robot.drivers package<a class=\"headerlink\" href=\"#robot-drivers-package\" title=\"永久链接至标题\">¶</a></h1>\n<div class=\"section\" id=\"submodules\">\n<h2>Submodules<a class=\"headerlink\" href=\"#submodules\" title=\"永久链接至标题\">¶</a></h2>\n</div>\n<div class=\"section\" id=\"robot-drivers-apa102-module\">\n<h2>robot.drivers.apa102 module<a class=\"headerlink\" href=\"#robot-drivers-apa102-module\" title=\"永久链接至标题\">¶</a></h2>\n</div>\n<div class=\"section\" id=\"robot-drivers-pixels-module\">\n<h2>robot.drivers.pixels module<a class=\"headerlink\" href=\"#robot-drivers-pixels-module\" title=\"永久链接至标题\">¶</a></h2>\n</div>\n<div class=\"section\" id=\"module-robot.drivers\">\n<span id=\"module-contents\"></span><h2>Module contents<a class=\"headerlink\" href=\"#module-robot.drivers\" title=\"永久链接至标题\">¶</a></h2>\n</div>\n</div>\n\n\n           </div>\n           \n          </div>\n          <footer>\n  \n\n  <hr/>\n\n  <div role=\"contentinfo\">\n    <p>\n        &copy; Copyright 2019, wzpan\n\n    </p>\n  </div>\n  Built with <a href=\"http://sphinx-doc.org/\">Sphinx</a> using a <a href=\"https://github.com/rtfd/sphinx_rtd_theme\">theme</a> provided by <a href=\"https://readthedocs.org\">Read the Docs</a>. \n\n</footer>\n\n        </div>\n      </div>\n\n    </section>\n\n  </div>\n  \n\n\n  <script type=\"text/javascript\">\n      jQuery(function () {\n          SphinxRtdTheme.Navigation.enable(true);\n      });\n  </script>\n\n  \n  \n    \n   \n\n</body>\n</html>"
  },
  {
    "path": "docs/robot.html",
    "content": "\n\n<!DOCTYPE html>\n<!--[if IE 8]><html class=\"no-js lt-ie9\" lang=\"zh-CN\" > <![endif]-->\n<!--[if gt IE 8]><!--> <html class=\"no-js\" lang=\"zh-CN\" > <!--<![endif]-->\n<head>\n  <meta charset=\"utf-8\">\n  \n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  \n  <title>robot package &mdash; wukong-robot 1.2.0 文档</title>\n  \n\n  \n  \n  \n  \n\n  \n  <script type=\"text/javascript\" src=\"_static/js/modernizr.min.js\"></script>\n  \n    \n      <script type=\"text/javascript\" id=\"documentation_options\" data-url_root=\"./\" src=\"_static/documentation_options.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/jquery.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/underscore.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/doctools.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/language_data.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/translations.js\"></script>\n    \n    <script type=\"text/javascript\" src=\"_static/js/theme.js\"></script>\n\n    \n\n  \n  <link rel=\"stylesheet\" href=\"_static/css/theme.css\" type=\"text/css\" />\n  <link rel=\"stylesheet\" href=\"_static/pygments.css\" type=\"text/css\" />\n    <link rel=\"index\" title=\"索引\" href=\"genindex.html\" />\n    <link rel=\"search\" title=\"搜索\" href=\"search.html\" /> \n</head>\n\n<body class=\"wy-body-for-nav\">\n\n   \n  <div class=\"wy-grid-for-nav\">\n    \n    <nav data-toggle=\"wy-nav-shift\" class=\"wy-nav-side\">\n      <div class=\"wy-side-scroll\">\n        <div class=\"wy-side-nav-search\" >\n          \n\n          \n            <a href=\"index.html\" class=\"icon icon-home\"> wukong-robot\n          \n\n          \n          </a>\n\n          \n            \n            \n          \n\n          \n<div role=\"search\">\n  <form id=\"rtd-search-form\" class=\"wy-form\" action=\"search.html\" method=\"get\">\n    <input type=\"text\" name=\"q\" placeholder=\"Search docs\" />\n    <input type=\"hidden\" name=\"check_keywords\" value=\"yes\" />\n    <input type=\"hidden\" name=\"area\" value=\"default\" />\n  </form>\n</div>\n\n          \n        </div>\n\n        <div class=\"wy-menu wy-menu-vertical\" data-spy=\"affix\" role=\"navigation\" aria-label=\"main navigation\">\n          \n            \n            \n              \n            \n            \n              <!-- Local TOC -->\n              <div class=\"local-toc\"><ul>\n<li><a class=\"reference internal\" href=\"#\">robot package</a><ul>\n<li><a class=\"reference internal\" href=\"#subpackages\">Subpackages</a></li>\n<li><a class=\"reference internal\" href=\"#submodules\">Submodules</a></li>\n<li><a class=\"reference internal\" href=\"#module-robot.AI\">robot.AI module</a></li>\n<li><a class=\"reference internal\" href=\"#module-robot.ASR\">robot.ASR module</a></li>\n<li><a class=\"reference internal\" href=\"#module-robot.Brain\">robot.Brain module</a></li>\n<li><a class=\"reference internal\" href=\"#module-robot.ConfigMonitor\">robot.ConfigMonitor module</a></li>\n<li><a class=\"reference internal\" href=\"#module-robot.Conversation\">robot.Conversation module</a></li>\n<li><a class=\"reference internal\" href=\"#module-robot.NLU\">robot.NLU module</a></li>\n<li><a class=\"reference internal\" href=\"#module-robot.Player\">robot.Player module</a></li>\n<li><a class=\"reference internal\" href=\"#module-robot.TTS\">robot.TTS module</a></li>\n<li><a class=\"reference internal\" href=\"#module-robot.Updater\">robot.Updater module</a></li>\n<li><a class=\"reference internal\" href=\"#module-robot.config\">robot.config module</a></li>\n<li><a class=\"reference internal\" href=\"#module-robot.constants\">robot.constants module</a></li>\n<li><a class=\"reference internal\" href=\"#module-robot.logging\">robot.logging module</a></li>\n<li><a class=\"reference internal\" href=\"#module-robot.plugin_loader\">robot.plugin_loader module</a></li>\n<li><a class=\"reference internal\" href=\"#module-robot.statistic\">robot.statistic module</a></li>\n<li><a class=\"reference internal\" href=\"#module-robot.utils\">robot.utils module</a></li>\n<li><a class=\"reference internal\" href=\"#module-robot\">Module contents</a></li>\n</ul>\n</li>\n</ul>\n</div>\n            \n          \n        </div>\n      </div>\n    </nav>\n\n    <section data-toggle=\"wy-nav-shift\" class=\"wy-nav-content-wrap\">\n\n      \n      <nav class=\"wy-nav-top\" aria-label=\"top navigation\">\n        \n          <i data-toggle=\"wy-nav-top\" class=\"fa fa-bars\"></i>\n          <a href=\"index.html\">wukong-robot</a>\n        \n      </nav>\n\n\n      <div class=\"wy-nav-content\">\n        \n        <div class=\"rst-content\">\n        \n          \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<div role=\"navigation\" aria-label=\"breadcrumbs navigation\">\n\n  <ul class=\"wy-breadcrumbs\">\n    \n      <li><a href=\"index.html\">Docs</a> &raquo;</li>\n        \n      <li>robot package</li>\n    \n    \n      <li class=\"wy-breadcrumbs-aside\">\n        \n            \n            <a href=\"_sources/robot.rst.txt\" rel=\"nofollow\"> View page source</a>\n          \n        \n      </li>\n    \n  </ul>\n\n  \n  <hr/>\n</div>\n          <div role=\"main\" class=\"document\" itemscope=\"itemscope\" itemtype=\"http://schema.org/Article\">\n           <div itemprop=\"articleBody\">\n            \n  <div class=\"section\" id=\"robot-package\">\n<h1>robot package<a class=\"headerlink\" href=\"#robot-package\" title=\"永久链接至标题\">¶</a></h1>\n<div class=\"section\" id=\"subpackages\">\n<h2>Subpackages<a class=\"headerlink\" href=\"#subpackages\" title=\"永久链接至标题\">¶</a></h2>\n<div class=\"toctree-wrapper compound\">\n<ul>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"robot.sdk.html\">robot.sdk package</a><ul>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"robot.sdk.html#submodules\">Submodules</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"robot.sdk.html#module-robot.sdk.AbstractPlugin\">robot.sdk.AbstractPlugin module</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"robot.sdk.html#module-robot.sdk.AliSpeech\">robot.sdk.AliSpeech module</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"robot.sdk.html#module-robot.sdk.RASRsdk\">robot.sdk.RASRsdk module</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"robot.sdk.html#module-robot.sdk.TencentSpeech\">robot.sdk.TencentSpeech module</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"robot.sdk.html#module-robot.sdk.XunfeiSpeech\">robot.sdk.XunfeiSpeech module</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"robot.sdk.html#module-robot.sdk.unit\">robot.sdk.unit module</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"robot.sdk.html#module-robot.sdk\">Module contents</a></li>\n</ul>\n</li>\n</ul>\n</div>\n</div>\n<div class=\"section\" id=\"submodules\">\n<h2>Submodules<a class=\"headerlink\" href=\"#submodules\" title=\"永久链接至标题\">¶</a></h2>\n</div>\n<div class=\"section\" id=\"module-robot.AI\">\n<span id=\"robot-ai-module\"></span><h2>robot.AI module<a class=\"headerlink\" href=\"#module-robot.AI\" title=\"永久链接至标题\">¶</a></h2>\n<dl class=\"class\">\n<dt id=\"robot.AI.AbstractRobot\">\n<em class=\"property\">class </em><code class=\"descclassname\">robot.AI.</code><code class=\"descname\">AbstractRobot</code><span class=\"sig-paren\">(</span><em>**kwargs</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/AI.html#AbstractRobot\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.AI.AbstractRobot\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>基类：<code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">object</span></code></p>\n<dl class=\"method\">\n<dt id=\"robot.AI.AbstractRobot.chat\">\n<code class=\"descname\">chat</code><span class=\"sig-paren\">(</span><em>texts</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/AI.html#AbstractRobot.chat\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.AI.AbstractRobot.chat\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"classmethod\">\n<dt id=\"robot.AI.AbstractRobot.get_instance\">\n<em class=\"property\">classmethod </em><code class=\"descname\">get_instance</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/AI.html#AbstractRobot.get_instance\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.AI.AbstractRobot.get_instance\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n</dd></dl>\n\n<dl class=\"class\">\n<dt id=\"robot.AI.Emotibot\">\n<em class=\"property\">class </em><code class=\"descclassname\">robot.AI.</code><code class=\"descname\">Emotibot</code><span class=\"sig-paren\">(</span><em>appid</em>, <em>location</em>, <em>more</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/AI.html#Emotibot\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.AI.Emotibot\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>基类：<a class=\"reference internal\" href=\"#robot.AI.AbstractRobot\" title=\"robot.AI.AbstractRobot\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">robot.AI.AbstractRobot</span></code></a></p>\n<dl class=\"attribute\">\n<dt id=\"robot.AI.Emotibot.SLUG\">\n<code class=\"descname\">SLUG</code><em class=\"property\"> = 'emotibot'</em><a class=\"headerlink\" href=\"#robot.AI.Emotibot.SLUG\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.AI.Emotibot.chat\">\n<code class=\"descname\">chat</code><span class=\"sig-paren\">(</span><em>texts</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/AI.html#Emotibot.chat\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.AI.Emotibot.chat\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>使用Emotibot机器人聊天</p>\n<p>Arguments:\ntexts – user input, typically speech, to be parsed by a module</p>\n</dd></dl>\n\n<dl class=\"classmethod\">\n<dt id=\"robot.AI.Emotibot.get_config\">\n<em class=\"property\">classmethod </em><code class=\"descname\">get_config</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/AI.html#Emotibot.get_config\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.AI.Emotibot.get_config\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n</dd></dl>\n\n<dl class=\"class\">\n<dt id=\"robot.AI.TulingRobot\">\n<em class=\"property\">class </em><code class=\"descclassname\">robot.AI.</code><code class=\"descname\">TulingRobot</code><span class=\"sig-paren\">(</span><em>tuling_key</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/AI.html#TulingRobot\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.AI.TulingRobot\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>基类：<a class=\"reference internal\" href=\"#robot.AI.AbstractRobot\" title=\"robot.AI.AbstractRobot\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">robot.AI.AbstractRobot</span></code></a></p>\n<dl class=\"attribute\">\n<dt id=\"robot.AI.TulingRobot.SLUG\">\n<code class=\"descname\">SLUG</code><em class=\"property\"> = 'tuling'</em><a class=\"headerlink\" href=\"#robot.AI.TulingRobot.SLUG\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.AI.TulingRobot.chat\">\n<code class=\"descname\">chat</code><span class=\"sig-paren\">(</span><em>texts</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/AI.html#TulingRobot.chat\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.AI.TulingRobot.chat\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>使用图灵机器人聊天</p>\n<p>Arguments:\ntexts – user input, typically speech, to be parsed by a module</p>\n</dd></dl>\n\n<dl class=\"classmethod\">\n<dt id=\"robot.AI.TulingRobot.get_config\">\n<em class=\"property\">classmethod </em><code class=\"descname\">get_config</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/AI.html#TulingRobot.get_config\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.AI.TulingRobot.get_config\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n</dd></dl>\n\n<dl class=\"function\">\n<dt id=\"robot.AI.get_robot_by_slug\">\n<code class=\"descclassname\">robot.AI.</code><code class=\"descname\">get_robot_by_slug</code><span class=\"sig-paren\">(</span><em>slug</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/AI.html#get_robot_by_slug\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.AI.get_robot_by_slug\" title=\"永久链接至目标\">¶</a></dt>\n<dd><dl class=\"docutils\">\n<dt>Returns:</dt>\n<dd>A robot implementation available on the current platform</dd>\n</dl>\n</dd></dl>\n\n<dl class=\"function\">\n<dt id=\"robot.AI.get_robots\">\n<code class=\"descclassname\">robot.AI.</code><code class=\"descname\">get_robots</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/AI.html#get_robots\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.AI.get_robots\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n</div>\n<div class=\"section\" id=\"module-robot.ASR\">\n<span id=\"robot-asr-module\"></span><h2>robot.ASR module<a class=\"headerlink\" href=\"#module-robot.ASR\" title=\"永久链接至标题\">¶</a></h2>\n<dl class=\"class\">\n<dt id=\"robot.ASR.AbstractASR\">\n<em class=\"property\">class </em><code class=\"descclassname\">robot.ASR.</code><code class=\"descname\">AbstractASR</code><a class=\"reference internal\" href=\"_modules/robot/ASR.html#AbstractASR\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.ASR.AbstractASR\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>基类：<code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">object</span></code></p>\n<p>Generic parent class for all ASR engines</p>\n<dl class=\"classmethod\">\n<dt id=\"robot.ASR.AbstractASR.get_config\">\n<em class=\"property\">classmethod </em><code class=\"descname\">get_config</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/ASR.html#AbstractASR.get_config\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.ASR.AbstractASR.get_config\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"classmethod\">\n<dt id=\"robot.ASR.AbstractASR.get_instance\">\n<em class=\"property\">classmethod </em><code class=\"descname\">get_instance</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/ASR.html#AbstractASR.get_instance\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.ASR.AbstractASR.get_instance\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.ASR.AbstractASR.transcribe\">\n<code class=\"descname\">transcribe</code><span class=\"sig-paren\">(</span><em>fp</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/ASR.html#AbstractASR.transcribe\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.ASR.AbstractASR.transcribe\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n</dd></dl>\n\n<dl class=\"class\">\n<dt id=\"robot.ASR.AliASR\">\n<em class=\"property\">class </em><code class=\"descclassname\">robot.ASR.</code><code class=\"descname\">AliASR</code><span class=\"sig-paren\">(</span><em>appKey</em>, <em>token</em>, <em>**args</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/ASR.html#AliASR\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.ASR.AliASR\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>基类：<a class=\"reference internal\" href=\"#robot.ASR.AbstractASR\" title=\"robot.ASR.AbstractASR\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">robot.ASR.AbstractASR</span></code></a></p>\n<p>阿里的语音识别API.</p>\n<dl class=\"attribute\">\n<dt id=\"robot.ASR.AliASR.SLUG\">\n<code class=\"descname\">SLUG</code><em class=\"property\"> = 'ali-asr'</em><a class=\"headerlink\" href=\"#robot.ASR.AliASR.SLUG\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"classmethod\">\n<dt id=\"robot.ASR.AliASR.get_config\">\n<em class=\"property\">classmethod </em><code class=\"descname\">get_config</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/ASR.html#AliASR.get_config\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.ASR.AliASR.get_config\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.ASR.AliASR.transcribe\">\n<code class=\"descname\">transcribe</code><span class=\"sig-paren\">(</span><em>fp</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/ASR.html#AliASR.transcribe\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.ASR.AliASR.transcribe\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n</dd></dl>\n\n<dl class=\"class\">\n<dt id=\"robot.ASR.BaiduASR\">\n<em class=\"property\">class </em><code class=\"descclassname\">robot.ASR.</code><code class=\"descname\">BaiduASR</code><span class=\"sig-paren\">(</span><em>appid</em>, <em>api_key</em>, <em>secret_key</em>, <em>dev_pid=1936</em>, <em>**args</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/ASR.html#BaiduASR\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.ASR.BaiduASR\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>基类：<a class=\"reference internal\" href=\"#robot.ASR.AbstractASR\" title=\"robot.ASR.AbstractASR\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">robot.ASR.AbstractASR</span></code></a></p>\n<p>百度的语音识别API.\ndev_pid:</p>\n<blockquote>\n<div><ul class=\"simple\">\n<li>1936: 普通话远场</li>\n<li>1536：普通话(支持简单的英文识别)</li>\n<li>1537：普通话(纯中文识别)</li>\n<li>1737：英语</li>\n<li>1637：粤语</li>\n<li>1837：四川话</li>\n</ul>\n</div></blockquote>\n<p>要使用本模块, 首先到 yuyin.baidu.com 注册一个开发者账号,\n之后创建一个新应用, 然后在应用管理的”查看key”中获得 API Key 和 Secret Key\n填入 config.xml 中.\n…</p>\n<blockquote>\n<div><dl class=\"docutils\">\n<dt>baidu_yuyin: </dt>\n<dd>appid: ‘9670645’\napi_key: ‘qg4haN8b2bGvFtCbBGqhrmZy’\nsecret_key: ‘585d4eccb50d306c401d7df138bb02e7’</dd>\n</dl>\n<p>…</p>\n</div></blockquote>\n<dl class=\"attribute\">\n<dt id=\"robot.ASR.BaiduASR.SLUG\">\n<code class=\"descname\">SLUG</code><em class=\"property\"> = 'baidu-asr'</em><a class=\"headerlink\" href=\"#robot.ASR.BaiduASR.SLUG\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"classmethod\">\n<dt id=\"robot.ASR.BaiduASR.get_config\">\n<em class=\"property\">classmethod </em><code class=\"descname\">get_config</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/ASR.html#BaiduASR.get_config\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.ASR.BaiduASR.get_config\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.ASR.BaiduASR.transcribe\">\n<code class=\"descname\">transcribe</code><span class=\"sig-paren\">(</span><em>fp</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/ASR.html#BaiduASR.transcribe\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.ASR.BaiduASR.transcribe\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n</dd></dl>\n\n<dl class=\"class\">\n<dt id=\"robot.ASR.TencentASR\">\n<em class=\"property\">class </em><code class=\"descclassname\">robot.ASR.</code><code class=\"descname\">TencentASR</code><span class=\"sig-paren\">(</span><em>appid</em>, <em>secretid</em>, <em>secret_key</em>, <em>region='ap-guangzhou'</em>, <em>**args</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/ASR.html#TencentASR\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.ASR.TencentASR\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>基类：<a class=\"reference internal\" href=\"#robot.ASR.AbstractASR\" title=\"robot.ASR.AbstractASR\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">robot.ASR.AbstractASR</span></code></a></p>\n<p>腾讯的语音识别API.</p>\n<dl class=\"attribute\">\n<dt id=\"robot.ASR.TencentASR.SLUG\">\n<code class=\"descname\">SLUG</code><em class=\"property\"> = 'tencent-asr'</em><a class=\"headerlink\" href=\"#robot.ASR.TencentASR.SLUG\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"classmethod\">\n<dt id=\"robot.ASR.TencentASR.get_config\">\n<em class=\"property\">classmethod </em><code class=\"descname\">get_config</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/ASR.html#TencentASR.get_config\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.ASR.TencentASR.get_config\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.ASR.TencentASR.transcribe\">\n<code class=\"descname\">transcribe</code><span class=\"sig-paren\">(</span><em>fp</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/ASR.html#TencentASR.transcribe\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.ASR.TencentASR.transcribe\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n</dd></dl>\n\n<dl class=\"class\">\n<dt id=\"robot.ASR.XunfeiASR\">\n<em class=\"property\">class </em><code class=\"descclassname\">robot.ASR.</code><code class=\"descname\">XunfeiASR</code><span class=\"sig-paren\">(</span><em>appid</em>, <em>asr_api_key</em>, <em>asr_api_secret</em>, <em>tts_api_key</em>, <em>voice='xiaoyan'</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/ASR.html#XunfeiASR\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.ASR.XunfeiASR\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>基类：<a class=\"reference internal\" href=\"#robot.ASR.AbstractASR\" title=\"robot.ASR.AbstractASR\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">robot.ASR.AbstractASR</span></code></a></p>\n<p>科大讯飞的语音识别API.\n外网ip查询：<a class=\"reference external\" href=\"https://ip.51240.com/\">https://ip.51240.com/</a></p>\n<dl class=\"attribute\">\n<dt id=\"robot.ASR.XunfeiASR.SLUG\">\n<code class=\"descname\">SLUG</code><em class=\"property\"> = 'xunfei-asr'</em><a class=\"headerlink\" href=\"#robot.ASR.XunfeiASR.SLUG\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"classmethod\">\n<dt id=\"robot.ASR.XunfeiASR.get_config\">\n<em class=\"property\">classmethod </em><code class=\"descname\">get_config</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/ASR.html#XunfeiASR.get_config\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.ASR.XunfeiASR.get_config\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.ASR.XunfeiASR.transcribe\">\n<code class=\"descname\">transcribe</code><span class=\"sig-paren\">(</span><em>fp</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/ASR.html#XunfeiASR.transcribe\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.ASR.XunfeiASR.transcribe\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n</dd></dl>\n\n<dl class=\"function\">\n<dt id=\"robot.ASR.get_engine_by_slug\">\n<code class=\"descclassname\">robot.ASR.</code><code class=\"descname\">get_engine_by_slug</code><span class=\"sig-paren\">(</span><em>slug=None</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/ASR.html#get_engine_by_slug\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.ASR.get_engine_by_slug\" title=\"永久链接至目标\">¶</a></dt>\n<dd><dl class=\"docutils\">\n<dt>Returns:</dt>\n<dd>An ASR Engine implementation available on the current platform</dd>\n<dt>Raises:</dt>\n<dd>ValueError if no speaker implementation is supported on this platform</dd>\n</dl>\n</dd></dl>\n\n<dl class=\"function\">\n<dt id=\"robot.ASR.get_engines\">\n<code class=\"descclassname\">robot.ASR.</code><code class=\"descname\">get_engines</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/ASR.html#get_engines\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.ASR.get_engines\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n</div>\n<div class=\"section\" id=\"module-robot.Brain\">\n<span id=\"robot-brain-module\"></span><h2>robot.Brain module<a class=\"headerlink\" href=\"#module-robot.Brain\" title=\"永久链接至标题\">¶</a></h2>\n<dl class=\"class\">\n<dt id=\"robot.Brain.Brain\">\n<em class=\"property\">class </em><code class=\"descclassname\">robot.Brain.</code><code class=\"descname\">Brain</code><span class=\"sig-paren\">(</span><em>conversation</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/Brain.html#Brain\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.Brain.Brain\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>基类：<code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">object</span></code></p>\n<dl class=\"method\">\n<dt id=\"robot.Brain.Brain.isImmersive\">\n<code class=\"descname\">isImmersive</code><span class=\"sig-paren\">(</span><em>plugin</em>, <em>text</em>, <em>parsed</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/Brain.html#Brain.isImmersive\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.Brain.Brain.isImmersive\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.Brain.Brain.pause\">\n<code class=\"descname\">pause</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/Brain.html#Brain.pause\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.Brain.Brain.pause\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>暂停某个技能的处理</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.Brain.Brain.printPlugins\">\n<code class=\"descname\">printPlugins</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/Brain.html#Brain.printPlugins\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.Brain.Brain.printPlugins\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.Brain.Brain.query\">\n<code class=\"descname\">query</code><span class=\"sig-paren\">(</span><em>text</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/Brain.html#Brain.query\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.Brain.Brain.query\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>query 模块</p>\n<p>Arguments:\ntext – 用户输入</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.Brain.Brain.restore\">\n<code class=\"descname\">restore</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/Brain.html#Brain.restore\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.Brain.Brain.restore\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>恢复某个技能的处理</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.Brain.Brain.say\">\n<code class=\"descname\">say</code><span class=\"sig-paren\">(</span><em>msg</em>, <em>cache=False</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/Brain.html#Brain.say\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.Brain.Brain.say\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.Brain.Brain.understand\">\n<code class=\"descname\">understand</code><span class=\"sig-paren\">(</span><em>fp</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/Brain.html#Brain.understand\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.Brain.Brain.understand\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n</dd></dl>\n\n</div>\n<div class=\"section\" id=\"module-robot.ConfigMonitor\">\n<span id=\"robot-configmonitor-module\"></span><h2>robot.ConfigMonitor module<a class=\"headerlink\" href=\"#module-robot.ConfigMonitor\" title=\"永久链接至标题\">¶</a></h2>\n<dl class=\"class\">\n<dt id=\"robot.ConfigMonitor.ConfigMonitor\">\n<em class=\"property\">class </em><code class=\"descclassname\">robot.ConfigMonitor.</code><code class=\"descname\">ConfigMonitor</code><span class=\"sig-paren\">(</span><em>conversation</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/ConfigMonitor.html#ConfigMonitor\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.ConfigMonitor.ConfigMonitor\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>基类：<code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">watchdog.events.FileSystemEventHandler</span></code></p>\n<dl class=\"method\">\n<dt id=\"robot.ConfigMonitor.ConfigMonitor.on_modified\">\n<code class=\"descname\">on_modified</code><span class=\"sig-paren\">(</span><em>event</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/ConfigMonitor.html#ConfigMonitor.on_modified\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.ConfigMonitor.ConfigMonitor.on_modified\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Called when a file or directory is modified.</p>\n<table class=\"docutils field-list\" frame=\"void\" rules=\"none\">\n<col class=\"field-name\" />\n<col class=\"field-body\" />\n<tbody valign=\"top\">\n<tr class=\"field-odd field\"><th class=\"field-name\">参数:</th><td class=\"field-body\"><strong>event</strong> (<code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">DirModifiedEvent</span></code> or <code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">FileModifiedEvent</span></code>) – Event representing file/directory modification.</td>\n</tr>\n</tbody>\n</table>\n</dd></dl>\n\n</dd></dl>\n\n</div>\n<div class=\"section\" id=\"module-robot.Conversation\">\n<span id=\"robot-conversation-module\"></span><h2>robot.Conversation module<a class=\"headerlink\" href=\"#module-robot.Conversation\" title=\"永久链接至标题\">¶</a></h2>\n<dl class=\"class\">\n<dt id=\"robot.Conversation.Conversation\">\n<em class=\"property\">class </em><code class=\"descclassname\">robot.Conversation.</code><code class=\"descname\">Conversation</code><span class=\"sig-paren\">(</span><em>profiling=False</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/Conversation.html#Conversation\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.Conversation.Conversation\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>基类：<code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">object</span></code></p>\n<dl class=\"method\">\n<dt id=\"robot.Conversation.Conversation.activeListen\">\n<code class=\"descname\">activeListen</code><span class=\"sig-paren\">(</span><em>silent=False</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/Conversation.html#Conversation.activeListen\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.Conversation.Conversation.activeListen\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>主动问一个问题(适用于多轮对话)</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.Conversation.Conversation.appendHistory\">\n<code class=\"descname\">appendHistory</code><span class=\"sig-paren\">(</span><em>t</em>, <em>text</em>, <em>UUID=''</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/Conversation.html#Conversation.appendHistory\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.Conversation.Conversation.appendHistory\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>将会话历史加进历史记录</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.Conversation.Conversation.checkRestore\">\n<code class=\"descname\">checkRestore</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/Conversation.html#Conversation.checkRestore\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.Conversation.Conversation.checkRestore\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.Conversation.Conversation.converse\">\n<code class=\"descname\">converse</code><span class=\"sig-paren\">(</span><em>fp</em>, <em>callback=None</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/Conversation.html#Conversation.converse\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.Conversation.Conversation.converse\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>核心对话逻辑</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.Conversation.Conversation.doConverse\">\n<code class=\"descname\">doConverse</code><span class=\"sig-paren\">(</span><em>fp</em>, <em>callback=None</em>, <em>onSay=None</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/Conversation.html#Conversation.doConverse\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.Conversation.Conversation.doConverse\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.Conversation.Conversation.doParse\">\n<code class=\"descname\">doParse</code><span class=\"sig-paren\">(</span><em>query</em>, <em>**args</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/Conversation.html#Conversation.doParse\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.Conversation.Conversation.doParse\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.Conversation.Conversation.doResponse\">\n<code class=\"descname\">doResponse</code><span class=\"sig-paren\">(</span><em>query</em>, <em>UUID=''</em>, <em>onSay=None</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/Conversation.html#Conversation.doResponse\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.Conversation.Conversation.doResponse\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.Conversation.Conversation.getHistory\">\n<code class=\"descname\">getHistory</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/Conversation.html#Conversation.getHistory\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.Conversation.Conversation.getHistory\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.Conversation.Conversation.getImmersiveMode\">\n<code class=\"descname\">getImmersiveMode</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/Conversation.html#Conversation.getImmersiveMode\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.Conversation.Conversation.getImmersiveMode\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.Conversation.Conversation.interrupt\">\n<code class=\"descname\">interrupt</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/Conversation.html#Conversation.interrupt\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.Conversation.Conversation.interrupt\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.Conversation.Conversation.pardon\">\n<code class=\"descname\">pardon</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/Conversation.html#Conversation.pardon\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.Conversation.Conversation.pardon\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.Conversation.Conversation.play\">\n<code class=\"descname\">play</code><span class=\"sig-paren\">(</span><em>src</em>, <em>delete=False</em>, <em>onCompleted=None</em>, <em>volume=1</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/Conversation.html#Conversation.play\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.Conversation.Conversation.play\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>播放一个音频</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.Conversation.Conversation.reload\">\n<code class=\"descname\">reload</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/Conversation.html#Conversation.reload\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.Conversation.Conversation.reload\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>重新初始化</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.Conversation.Conversation.say\">\n<code class=\"descname\">say</code><span class=\"sig-paren\">(</span><em>msg</em>, <em>cache=False</em>, <em>plugin=''</em>, <em>onCompleted=None</em>, <em>wait=False</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/Conversation.html#Conversation.say\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.Conversation.Conversation.say\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>说一句话\n:param msg: 内容\n:param cache: 是否缓存这句话的音频\n:param plugin: 来自哪个插件的消息（将带上插件的说明）\n:param onCompleted: 完成的回调\n:param wait: 是否要等待说完（为True将阻塞主线程直至说完这句话）</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.Conversation.Conversation.setImmersiveMode\">\n<code class=\"descname\">setImmersiveMode</code><span class=\"sig-paren\">(</span><em>slug</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/Conversation.html#Conversation.setImmersiveMode\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.Conversation.Conversation.setImmersiveMode\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n</dd></dl>\n\n</div>\n<div class=\"section\" id=\"module-robot.NLU\">\n<span id=\"robot-nlu-module\"></span><h2>robot.NLU module<a class=\"headerlink\" href=\"#module-robot.NLU\" title=\"永久链接至标题\">¶</a></h2>\n<dl class=\"class\">\n<dt id=\"robot.NLU.AbstractNLU\">\n<em class=\"property\">class </em><code class=\"descclassname\">robot.NLU.</code><code class=\"descname\">AbstractNLU</code><a class=\"reference internal\" href=\"_modules/robot/NLU.html#AbstractNLU\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.NLU.AbstractNLU\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>基类：<code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">object</span></code></p>\n<p>Generic parent class for all NLU engines</p>\n<dl class=\"method\">\n<dt id=\"robot.NLU.AbstractNLU.getIntent\">\n<code class=\"descname\">getIntent</code><span class=\"sig-paren\">(</span><em>parsed</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/NLU.html#AbstractNLU.getIntent\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.NLU.AbstractNLU.getIntent\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>提取意图</p>\n<table class=\"docutils field-list\" frame=\"void\" rules=\"none\">\n<col class=\"field-name\" />\n<col class=\"field-body\" />\n<tbody valign=\"top\">\n<tr class=\"field-odd field\"><th class=\"field-name\">参数:</th><td class=\"field-body\"><strong>parsed</strong> – 解析结果</td>\n</tr>\n<tr class=\"field-even field\"><th class=\"field-name\">返回:</th><td class=\"field-body\">意图数组</td>\n</tr>\n</tbody>\n</table>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.NLU.AbstractNLU.getSay\">\n<code class=\"descname\">getSay</code><span class=\"sig-paren\">(</span><em>parsed</em>, <em>intent</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/NLU.html#AbstractNLU.getSay\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.NLU.AbstractNLU.getSay\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>提取回复文本</p>\n<table class=\"docutils field-list\" frame=\"void\" rules=\"none\">\n<col class=\"field-name\" />\n<col class=\"field-body\" />\n<tbody valign=\"top\">\n<tr class=\"field-odd field\"><th class=\"field-name\">参数:</th><td class=\"field-body\"><ul class=\"first simple\">\n<li><strong>parsed</strong> – 解析结果</li>\n<li><strong>intent</strong> – 意图的名称</li>\n</ul>\n</td>\n</tr>\n<tr class=\"field-even field\"><th class=\"field-name\">返回:</th><td class=\"field-body\"><p class=\"first last\">回复文本</p>\n</td>\n</tr>\n</tbody>\n</table>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.NLU.AbstractNLU.getSlotWords\">\n<code class=\"descname\">getSlotWords</code><span class=\"sig-paren\">(</span><em>parsed</em>, <em>intent</em>, <em>name</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/NLU.html#AbstractNLU.getSlotWords\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.NLU.AbstractNLU.getSlotWords\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>找出命中某个词槽的内容</p>\n<table class=\"docutils field-list\" frame=\"void\" rules=\"none\">\n<col class=\"field-name\" />\n<col class=\"field-body\" />\n<tbody valign=\"top\">\n<tr class=\"field-odd field\"><th class=\"field-name\">参数:</th><td class=\"field-body\"><ul class=\"first simple\">\n<li><strong>parsed</strong> – 解析结果</li>\n<li><strong>intent</strong> – 意图的名称</li>\n<li><strong>name</strong> – 词槽名</li>\n</ul>\n</td>\n</tr>\n<tr class=\"field-even field\"><th class=\"field-name\">返回:</th><td class=\"field-body\"><p class=\"first last\">命中该词槽的值的列表。</p>\n</td>\n</tr>\n</tbody>\n</table>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.NLU.AbstractNLU.getSlots\">\n<code class=\"descname\">getSlots</code><span class=\"sig-paren\">(</span><em>parsed</em>, <em>intent</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/NLU.html#AbstractNLU.getSlots\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.NLU.AbstractNLU.getSlots\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>提取某个意图的所有词槽</p>\n<table class=\"docutils field-list\" frame=\"void\" rules=\"none\">\n<col class=\"field-name\" />\n<col class=\"field-body\" />\n<tbody valign=\"top\">\n<tr class=\"field-odd field\"><th class=\"field-name\">参数:</th><td class=\"field-body\"><ul class=\"first simple\">\n<li><strong>parsed</strong> – 解析结果</li>\n<li><strong>intent</strong> – 意图的名称</li>\n</ul>\n</td>\n</tr>\n<tr class=\"field-even field\"><th class=\"field-name\">返回:</th><td class=\"field-body\"><p class=\"first last\">词槽列表。你可以通过 name 属性筛选词槽，</p>\n</td>\n</tr>\n</tbody>\n</table>\n<p>再通过 normalized_word 属性取出相应的值</p>\n</dd></dl>\n\n<dl class=\"classmethod\">\n<dt id=\"robot.NLU.AbstractNLU.get_config\">\n<em class=\"property\">classmethod </em><code class=\"descname\">get_config</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/NLU.html#AbstractNLU.get_config\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.NLU.AbstractNLU.get_config\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"classmethod\">\n<dt id=\"robot.NLU.AbstractNLU.get_instance\">\n<em class=\"property\">classmethod </em><code class=\"descname\">get_instance</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/NLU.html#AbstractNLU.get_instance\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.NLU.AbstractNLU.get_instance\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.NLU.AbstractNLU.hasIntent\">\n<code class=\"descname\">hasIntent</code><span class=\"sig-paren\">(</span><em>parsed</em>, <em>intent</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/NLU.html#AbstractNLU.hasIntent\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.NLU.AbstractNLU.hasIntent\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>判断是否包含某个意图</p>\n<table class=\"docutils field-list\" frame=\"void\" rules=\"none\">\n<col class=\"field-name\" />\n<col class=\"field-body\" />\n<tbody valign=\"top\">\n<tr class=\"field-odd field\"><th class=\"field-name\">参数:</th><td class=\"field-body\"><ul class=\"first simple\">\n<li><strong>parsed</strong> – 解析结果</li>\n<li><strong>intent</strong> – 意图的名称</li>\n</ul>\n</td>\n</tr>\n<tr class=\"field-even field\"><th class=\"field-name\">返回:</th><td class=\"field-body\"><p class=\"first last\">True: 包含; False: 不包含</p>\n</td>\n</tr>\n</tbody>\n</table>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.NLU.AbstractNLU.parse\">\n<code class=\"descname\">parse</code><span class=\"sig-paren\">(</span><em>query</em>, <em>**args</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/NLU.html#AbstractNLU.parse\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.NLU.AbstractNLU.parse\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>进行 NLU 解析</p>\n<table class=\"docutils field-list\" frame=\"void\" rules=\"none\">\n<col class=\"field-name\" />\n<col class=\"field-body\" />\n<tbody valign=\"top\">\n<tr class=\"field-odd field\"><th class=\"field-name\">参数:</th><td class=\"field-body\"><ul class=\"first last simple\">\n<li><strong>query</strong> – 用户的指令字符串</li>\n<li><strong>**args</strong> – <p>可选的参数</p>\n</li>\n</ul>\n</td>\n</tr>\n</tbody>\n</table>\n</dd></dl>\n\n</dd></dl>\n\n<dl class=\"class\">\n<dt id=\"robot.NLU.UnitNLU\">\n<em class=\"property\">class </em><code class=\"descclassname\">robot.NLU.</code><code class=\"descname\">UnitNLU</code><a class=\"reference internal\" href=\"_modules/robot/NLU.html#UnitNLU\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.NLU.UnitNLU\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>基类：<a class=\"reference internal\" href=\"#robot.NLU.AbstractNLU\" title=\"robot.NLU.AbstractNLU\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">robot.NLU.AbstractNLU</span></code></a></p>\n<p>百度UNIT的NLU API.</p>\n<dl class=\"attribute\">\n<dt id=\"robot.NLU.UnitNLU.SLUG\">\n<code class=\"descname\">SLUG</code><em class=\"property\"> = 'unit'</em><a class=\"headerlink\" href=\"#robot.NLU.UnitNLU.SLUG\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.NLU.UnitNLU.getIntent\">\n<code class=\"descname\">getIntent</code><span class=\"sig-paren\">(</span><em>parsed</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/NLU.html#UnitNLU.getIntent\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.NLU.UnitNLU.getIntent\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>提取意图</p>\n<table class=\"docutils field-list\" frame=\"void\" rules=\"none\">\n<col class=\"field-name\" />\n<col class=\"field-body\" />\n<tbody valign=\"top\">\n<tr class=\"field-odd field\"><th class=\"field-name\">参数:</th><td class=\"field-body\"><strong>parsed</strong> – 解析结果</td>\n</tr>\n<tr class=\"field-even field\"><th class=\"field-name\">返回:</th><td class=\"field-body\">意图数组</td>\n</tr>\n</tbody>\n</table>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.NLU.UnitNLU.getSay\">\n<code class=\"descname\">getSay</code><span class=\"sig-paren\">(</span><em>parsed</em>, <em>intent</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/NLU.html#UnitNLU.getSay\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.NLU.UnitNLU.getSay\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>提取 UNIT 的回复文本</p>\n<table class=\"docutils field-list\" frame=\"void\" rules=\"none\">\n<col class=\"field-name\" />\n<col class=\"field-body\" />\n<tbody valign=\"top\">\n<tr class=\"field-odd field\"><th class=\"field-name\">参数:</th><td class=\"field-body\"><ul class=\"first simple\">\n<li><strong>parsed</strong> – UNIT 解析结果</li>\n<li><strong>intent</strong> – 意图的名称</li>\n</ul>\n</td>\n</tr>\n<tr class=\"field-even field\"><th class=\"field-name\">返回:</th><td class=\"field-body\"><p class=\"first last\">UNIT 的回复文本</p>\n</td>\n</tr>\n</tbody>\n</table>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.NLU.UnitNLU.getSlotWords\">\n<code class=\"descname\">getSlotWords</code><span class=\"sig-paren\">(</span><em>parsed</em>, <em>intent</em>, <em>name</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/NLU.html#UnitNLU.getSlotWords\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.NLU.UnitNLU.getSlotWords\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>找出命中某个词槽的内容</p>\n<table class=\"docutils field-list\" frame=\"void\" rules=\"none\">\n<col class=\"field-name\" />\n<col class=\"field-body\" />\n<tbody valign=\"top\">\n<tr class=\"field-odd field\"><th class=\"field-name\">参数:</th><td class=\"field-body\"><ul class=\"first simple\">\n<li><strong>parsed</strong> – UNIT 解析结果</li>\n<li><strong>intent</strong> – 意图的名称</li>\n<li><strong>name</strong> – 词槽名</li>\n</ul>\n</td>\n</tr>\n<tr class=\"field-even field\"><th class=\"field-name\">返回:</th><td class=\"field-body\"><p class=\"first last\">命中该词槽的值的列表。</p>\n</td>\n</tr>\n</tbody>\n</table>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.NLU.UnitNLU.getSlots\">\n<code class=\"descname\">getSlots</code><span class=\"sig-paren\">(</span><em>parsed</em>, <em>intent</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/NLU.html#UnitNLU.getSlots\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.NLU.UnitNLU.getSlots\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>提取某个意图的所有词槽</p>\n<table class=\"docutils field-list\" frame=\"void\" rules=\"none\">\n<col class=\"field-name\" />\n<col class=\"field-body\" />\n<tbody valign=\"top\">\n<tr class=\"field-odd field\"><th class=\"field-name\">参数:</th><td class=\"field-body\"><ul class=\"first simple\">\n<li><strong>parsed</strong> – UNIT 解析结果</li>\n<li><strong>intent</strong> – 意图的名称</li>\n</ul>\n</td>\n</tr>\n<tr class=\"field-even field\"><th class=\"field-name\">返回:</th><td class=\"field-body\"><p class=\"first last\">词槽列表。你可以通过 name 属性筛选词槽，</p>\n</td>\n</tr>\n</tbody>\n</table>\n<p>再通过 normalized_word 属性取出相应的值</p>\n</dd></dl>\n\n<dl class=\"classmethod\">\n<dt id=\"robot.NLU.UnitNLU.get_config\">\n<em class=\"property\">classmethod </em><code class=\"descname\">get_config</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/NLU.html#UnitNLU.get_config\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.NLU.UnitNLU.get_config\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>百度UNIT的配置</p>\n<p>无需配置，所以返回 {}</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.NLU.UnitNLU.hasIntent\">\n<code class=\"descname\">hasIntent</code><span class=\"sig-paren\">(</span><em>parsed</em>, <em>intent</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/NLU.html#UnitNLU.hasIntent\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.NLU.UnitNLU.hasIntent\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>判断是否包含某个意图</p>\n<table class=\"docutils field-list\" frame=\"void\" rules=\"none\">\n<col class=\"field-name\" />\n<col class=\"field-body\" />\n<tbody valign=\"top\">\n<tr class=\"field-odd field\"><th class=\"field-name\">参数:</th><td class=\"field-body\"><ul class=\"first simple\">\n<li><strong>parsed</strong> – UNIT 解析结果</li>\n<li><strong>intent</strong> – 意图的名称</li>\n</ul>\n</td>\n</tr>\n<tr class=\"field-even field\"><th class=\"field-name\">返回:</th><td class=\"field-body\"><p class=\"first last\">True: 包含; False: 不包含</p>\n</td>\n</tr>\n</tbody>\n</table>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.NLU.UnitNLU.parse\">\n<code class=\"descname\">parse</code><span class=\"sig-paren\">(</span><em>query</em>, <em>**args</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/NLU.html#UnitNLU.parse\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.NLU.UnitNLU.parse\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>使用百度 UNIT 进行 NLU 解析</p>\n<table class=\"docutils field-list\" frame=\"void\" rules=\"none\">\n<col class=\"field-name\" />\n<col class=\"field-body\" />\n<tbody valign=\"top\">\n<tr class=\"field-odd field\"><th class=\"field-name\">参数:</th><td class=\"field-body\"><ul class=\"first simple\">\n<li><strong>query</strong> – 用户的指令字符串</li>\n<li><strong>**args</strong> – <p>UNIT 的相关参数\n- service_id: UNIT 的 service_id\n- api_key: UNIT apk_key\n- secret_key: UNIT secret_key</p>\n</li>\n</ul>\n</td>\n</tr>\n<tr class=\"field-even field\"><th class=\"field-name\">返回:</th><td class=\"field-body\"><p class=\"first last\">UNIT 解析结果。如果解析失败，返回 None</p>\n</td>\n</tr>\n</tbody>\n</table>\n</dd></dl>\n\n</dd></dl>\n\n<dl class=\"function\">\n<dt id=\"robot.NLU.get_engine_by_slug\">\n<code class=\"descclassname\">robot.NLU.</code><code class=\"descname\">get_engine_by_slug</code><span class=\"sig-paren\">(</span><em>slug=None</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/NLU.html#get_engine_by_slug\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.NLU.get_engine_by_slug\" title=\"永久链接至目标\">¶</a></dt>\n<dd><dl class=\"docutils\">\n<dt>Returns:</dt>\n<dd>An NLU Engine implementation available on the current platform</dd>\n<dt>Raises:</dt>\n<dd>ValueError if no speaker implementation is supported on this platform</dd>\n</dl>\n</dd></dl>\n\n<dl class=\"function\">\n<dt id=\"robot.NLU.get_engines\">\n<code class=\"descclassname\">robot.NLU.</code><code class=\"descname\">get_engines</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/NLU.html#get_engines\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.NLU.get_engines\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n</div>\n<div class=\"section\" id=\"module-robot.Player\">\n<span id=\"robot-player-module\"></span><h2>robot.Player module<a class=\"headerlink\" href=\"#module-robot.Player\" title=\"永久链接至标题\">¶</a></h2>\n<dl class=\"class\">\n<dt id=\"robot.Player.AbstractPlayer\">\n<em class=\"property\">class </em><code class=\"descclassname\">robot.Player.</code><code class=\"descname\">AbstractPlayer</code><span class=\"sig-paren\">(</span><em>**kwargs</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/Player.html#AbstractPlayer\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.Player.AbstractPlayer\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>基类：<code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">object</span></code></p>\n<dl class=\"method\">\n<dt id=\"robot.Player.AbstractPlayer.is_playing\">\n<code class=\"descname\">is_playing</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/Player.html#AbstractPlayer.is_playing\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.Player.AbstractPlayer.is_playing\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.Player.AbstractPlayer.play\">\n<code class=\"descname\">play</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/Player.html#AbstractPlayer.play\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.Player.AbstractPlayer.play\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.Player.AbstractPlayer.play_block\">\n<code class=\"descname\">play_block</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/Player.html#AbstractPlayer.play_block\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.Player.AbstractPlayer.play_block\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.Player.AbstractPlayer.stop\">\n<code class=\"descname\">stop</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/Player.html#AbstractPlayer.stop\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.Player.AbstractPlayer.stop\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n</dd></dl>\n\n<dl class=\"class\">\n<dt id=\"robot.Player.MusicPlayer\">\n<em class=\"property\">class </em><code class=\"descclassname\">robot.Player.</code><code class=\"descname\">MusicPlayer</code><span class=\"sig-paren\">(</span><em>playlist</em>, <em>plugin</em>, <em>**kwargs</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/Player.html#MusicPlayer\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.Player.MusicPlayer\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>基类：<a class=\"reference internal\" href=\"#robot.Player.SoxPlayer\" title=\"robot.Player.SoxPlayer\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">robot.Player.SoxPlayer</span></code></a></p>\n<p>给音乐播放器插件使用的，\n在 SOXPlayer 的基础上增加了列表的支持，\n并支持暂停和恢复播放</p>\n<dl class=\"attribute\">\n<dt id=\"robot.Player.MusicPlayer.SLUG\">\n<code class=\"descname\">SLUG</code><em class=\"property\"> = 'MusicPlayer'</em><a class=\"headerlink\" href=\"#robot.Player.MusicPlayer.SLUG\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.Player.MusicPlayer.is_pausing\">\n<code class=\"descname\">is_pausing</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/Player.html#MusicPlayer.is_pausing\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.Player.MusicPlayer.is_pausing\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.Player.MusicPlayer.is_playing\">\n<code class=\"descname\">is_playing</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/Player.html#MusicPlayer.is_playing\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.Player.MusicPlayer.is_playing\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.Player.MusicPlayer.next\">\n<code class=\"descname\">next</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/Player.html#MusicPlayer.next\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.Player.MusicPlayer.next\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.Player.MusicPlayer.pause\">\n<code class=\"descname\">pause</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/Player.html#MusicPlayer.pause\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.Player.MusicPlayer.pause\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.Player.MusicPlayer.play\">\n<code class=\"descname\">play</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/Player.html#MusicPlayer.play\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.Player.MusicPlayer.play\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.Player.MusicPlayer.prev\">\n<code class=\"descname\">prev</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/Player.html#MusicPlayer.prev\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.Player.MusicPlayer.prev\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.Player.MusicPlayer.resume\">\n<code class=\"descname\">resume</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/Player.html#MusicPlayer.resume\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.Player.MusicPlayer.resume\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.Player.MusicPlayer.stop\">\n<code class=\"descname\">stop</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/Player.html#MusicPlayer.stop\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.Player.MusicPlayer.stop\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.Player.MusicPlayer.turnDown\">\n<code class=\"descname\">turnDown</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/Player.html#MusicPlayer.turnDown\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.Player.MusicPlayer.turnDown\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.Player.MusicPlayer.turnUp\">\n<code class=\"descname\">turnUp</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/Player.html#MusicPlayer.turnUp\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.Player.MusicPlayer.turnUp\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.Player.MusicPlayer.update_playlist\">\n<code class=\"descname\">update_playlist</code><span class=\"sig-paren\">(</span><em>playlist</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/Player.html#MusicPlayer.update_playlist\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.Player.MusicPlayer.update_playlist\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n</dd></dl>\n\n<dl class=\"class\">\n<dt id=\"robot.Player.SoxPlayer\">\n<em class=\"property\">class </em><code class=\"descclassname\">robot.Player.</code><code class=\"descname\">SoxPlayer</code><span class=\"sig-paren\">(</span><em>**kwargs</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/Player.html#SoxPlayer\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.Player.SoxPlayer\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>基类：<a class=\"reference internal\" href=\"#robot.Player.AbstractPlayer\" title=\"robot.Player.AbstractPlayer\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">robot.Player.AbstractPlayer</span></code></a></p>\n<dl class=\"attribute\">\n<dt id=\"robot.Player.SoxPlayer.SLUG\">\n<code class=\"descname\">SLUG</code><em class=\"property\"> = 'SoxPlayer'</em><a class=\"headerlink\" href=\"#robot.Player.SoxPlayer.SLUG\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.Player.SoxPlayer.appendOnCompleted\">\n<code class=\"descname\">appendOnCompleted</code><span class=\"sig-paren\">(</span><em>onCompleted</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/Player.html#SoxPlayer.appendOnCompleted\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.Player.SoxPlayer.appendOnCompleted\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.Player.SoxPlayer.doPlay\">\n<code class=\"descname\">doPlay</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/Player.html#SoxPlayer.doPlay\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.Player.SoxPlayer.doPlay\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.Player.SoxPlayer.is_playing\">\n<code class=\"descname\">is_playing</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/Player.html#SoxPlayer.is_playing\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.Player.SoxPlayer.is_playing\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.Player.SoxPlayer.play\">\n<code class=\"descname\">play</code><span class=\"sig-paren\">(</span><em>src</em>, <em>delete=False</em>, <em>onCompleted=None</em>, <em>wait=False</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/Player.html#SoxPlayer.play\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.Player.SoxPlayer.play\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.Player.SoxPlayer.play_block\">\n<code class=\"descname\">play_block</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/Player.html#SoxPlayer.play_block\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.Player.SoxPlayer.play_block\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.Player.SoxPlayer.stop\">\n<code class=\"descname\">stop</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/Player.html#SoxPlayer.stop\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.Player.SoxPlayer.stop\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n</dd></dl>\n\n<dl class=\"function\">\n<dt id=\"robot.Player.getPlayerByFileName\">\n<code class=\"descclassname\">robot.Player.</code><code class=\"descname\">getPlayerByFileName</code><span class=\"sig-paren\">(</span><em>fname</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/Player.html#getPlayerByFileName\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.Player.getPlayerByFileName\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"function\">\n<dt id=\"robot.Player.no_alsa_error\">\n<code class=\"descclassname\">robot.Player.</code><code class=\"descname\">no_alsa_error</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/Player.html#no_alsa_error\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.Player.no_alsa_error\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"function\">\n<dt id=\"robot.Player.play\">\n<code class=\"descclassname\">robot.Player.</code><code class=\"descname\">play</code><span class=\"sig-paren\">(</span><em>fname</em>, <em>onCompleted=None</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/Player.html#play\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.Player.play\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"function\">\n<dt id=\"robot.Player.py_error_handler\">\n<code class=\"descclassname\">robot.Player.</code><code class=\"descname\">py_error_handler</code><span class=\"sig-paren\">(</span><em>filename</em>, <em>line</em>, <em>function</em>, <em>err</em>, <em>fmt</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/Player.html#py_error_handler\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.Player.py_error_handler\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n</div>\n<div class=\"section\" id=\"module-robot.TTS\">\n<span id=\"robot-tts-module\"></span><h2>robot.TTS module<a class=\"headerlink\" href=\"#module-robot.TTS\" title=\"永久链接至标题\">¶</a></h2>\n<dl class=\"class\">\n<dt id=\"robot.TTS.AbstractTTS\">\n<em class=\"property\">class </em><code class=\"descclassname\">robot.TTS.</code><code class=\"descname\">AbstractTTS</code><a class=\"reference internal\" href=\"_modules/robot/TTS.html#AbstractTTS\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.TTS.AbstractTTS\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>基类：<code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">object</span></code></p>\n<p>Generic parent class for all TTS engines</p>\n<dl class=\"classmethod\">\n<dt id=\"robot.TTS.AbstractTTS.get_config\">\n<em class=\"property\">classmethod </em><code class=\"descname\">get_config</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/TTS.html#AbstractTTS.get_config\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.TTS.AbstractTTS.get_config\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"classmethod\">\n<dt id=\"robot.TTS.AbstractTTS.get_instance\">\n<em class=\"property\">classmethod </em><code class=\"descname\">get_instance</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/TTS.html#AbstractTTS.get_instance\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.TTS.AbstractTTS.get_instance\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.TTS.AbstractTTS.get_speech\">\n<code class=\"descname\">get_speech</code><span class=\"sig-paren\">(</span><em>phrase</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/TTS.html#AbstractTTS.get_speech\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.TTS.AbstractTTS.get_speech\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n</dd></dl>\n\n<dl class=\"class\">\n<dt id=\"robot.TTS.AliTTS\">\n<em class=\"property\">class </em><code class=\"descclassname\">robot.TTS.</code><code class=\"descname\">AliTTS</code><span class=\"sig-paren\">(</span><em>appKey</em>, <em>token</em>, <em>voice='xiaoyun'</em>, <em>**args</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/TTS.html#AliTTS\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.TTS.AliTTS\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>基类：<a class=\"reference internal\" href=\"#robot.TTS.AbstractTTS\" title=\"robot.TTS.AbstractTTS\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">robot.TTS.AbstractTTS</span></code></a></p>\n<p>阿里的TTS\nvoice: 发音人，默认是 xiaoyun</p>\n<blockquote>\n<div>全部发音人列表：<a class=\"reference external\" href=\"https://help.aliyun.com/document_detail/84435.html?spm=a2c4g.11186623.2.24.67ce5275q2RGsT\">https://help.aliyun.com/document_detail/84435.html?spm=a2c4g.11186623.2.24.67ce5275q2RGsT</a></div></blockquote>\n<dl class=\"attribute\">\n<dt id=\"robot.TTS.AliTTS.SLUG\">\n<code class=\"descname\">SLUG</code><em class=\"property\"> = 'ali-tts'</em><a class=\"headerlink\" href=\"#robot.TTS.AliTTS.SLUG\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"classmethod\">\n<dt id=\"robot.TTS.AliTTS.get_config\">\n<em class=\"property\">classmethod </em><code class=\"descname\">get_config</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/TTS.html#AliTTS.get_config\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.TTS.AliTTS.get_config\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.TTS.AliTTS.get_speech\">\n<code class=\"descname\">get_speech</code><span class=\"sig-paren\">(</span><em>phrase</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/TTS.html#AliTTS.get_speech\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.TTS.AliTTS.get_speech\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n</dd></dl>\n\n<dl class=\"class\">\n<dt id=\"robot.TTS.BaiduTTS\">\n<em class=\"property\">class </em><code class=\"descclassname\">robot.TTS.</code><code class=\"descname\">BaiduTTS</code><span class=\"sig-paren\">(</span><em>appid</em>, <em>api_key</em>, <em>secret_key</em>, <em>per=1</em>, <em>lan='zh'</em>, <em>**args</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/TTS.html#BaiduTTS\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.TTS.BaiduTTS\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>基类：<a class=\"reference internal\" href=\"#robot.TTS.AbstractTTS\" title=\"robot.TTS.AbstractTTS\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">robot.TTS.AbstractTTS</span></code></a></p>\n<p>使用百度语音合成技术\n要使用本模块, 首先到 yuyin.baidu.com 注册一个开发者账号,\n之后创建一个新应用, 然后在应用管理的”查看key”中获得 API Key 和 Secret Key\n填入 config.yml 中.\n…</p>\n<blockquote>\n<div><dl class=\"docutils\">\n<dt>baidu_yuyin: </dt>\n<dd>appid: ‘9670645’\napi_key: ‘qg4haN8b2bGvFtCbBGqhrmZy’\nsecret_key: ‘585d4eccb50d306c401d7df138bb02e7’\ndev_pid: 1936\nper: 1\nlan: ‘zh’</dd>\n</dl>\n<p>…</p>\n</div></blockquote>\n<dl class=\"attribute\">\n<dt id=\"robot.TTS.BaiduTTS.SLUG\">\n<code class=\"descname\">SLUG</code><em class=\"property\"> = 'baidu-tts'</em><a class=\"headerlink\" href=\"#robot.TTS.BaiduTTS.SLUG\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"classmethod\">\n<dt id=\"robot.TTS.BaiduTTS.get_config\">\n<em class=\"property\">classmethod </em><code class=\"descname\">get_config</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/TTS.html#BaiduTTS.get_config\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.TTS.BaiduTTS.get_config\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.TTS.BaiduTTS.get_speech\">\n<code class=\"descname\">get_speech</code><span class=\"sig-paren\">(</span><em>phrase</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/TTS.html#BaiduTTS.get_speech\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.TTS.BaiduTTS.get_speech\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n</dd></dl>\n\n<dl class=\"class\">\n<dt id=\"robot.TTS.TencentTTS\">\n<em class=\"property\">class </em><code class=\"descclassname\">robot.TTS.</code><code class=\"descname\">TencentTTS</code><span class=\"sig-paren\">(</span><em>appid</em>, <em>secretid</em>, <em>secret_key</em>, <em>region='ap-guangzhou'</em>, <em>voiceType=0</em>, <em>language=1</em>, <em>**args</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/TTS.html#TencentTTS\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.TTS.TencentTTS\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>基类：<a class=\"reference internal\" href=\"#robot.TTS.AbstractTTS\" title=\"robot.TTS.AbstractTTS\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">robot.TTS.AbstractTTS</span></code></a></p>\n<p>腾讯的语音合成\nregion: 服务地域，挑个离自己最近的区域有助于提升速度。</p>\n<blockquote>\n<div>有效值：<a class=\"reference external\" href=\"https://cloud.tencent.com/document/api/441/17365#.E5.9C.B0.E5.9F.9F.E5.88.97.E8.A1.A8\">https://cloud.tencent.com/document/api/441/17365#.E5.9C.B0.E5.9F.9F.E5.88.97.E8.A1.A8</a></div></blockquote>\n<dl class=\"docutils\">\n<dt>voiceType:</dt>\n<dd><ul class=\"first last simple\">\n<li>0：女声1，亲和风格(默认)</li>\n<li>1：男声1，成熟风格</li>\n<li>2：男声2，成熟风格</li>\n</ul>\n</dd>\n<dt>language:</dt>\n<dd><ul class=\"first last simple\">\n<li>1: 中文，最大100个汉字（标点符号算一个汉子）</li>\n<li>2: 英文，最大支持400个字母（标点符号算一个字母）</li>\n</ul>\n</dd>\n</dl>\n<dl class=\"attribute\">\n<dt id=\"robot.TTS.TencentTTS.SLUG\">\n<code class=\"descname\">SLUG</code><em class=\"property\"> = 'tencent-tts'</em><a class=\"headerlink\" href=\"#robot.TTS.TencentTTS.SLUG\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"classmethod\">\n<dt id=\"robot.TTS.TencentTTS.get_config\">\n<em class=\"property\">classmethod </em><code class=\"descname\">get_config</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/TTS.html#TencentTTS.get_config\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.TTS.TencentTTS.get_config\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.TTS.TencentTTS.get_speech\">\n<code class=\"descname\">get_speech</code><span class=\"sig-paren\">(</span><em>phrase</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/TTS.html#TencentTTS.get_speech\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.TTS.TencentTTS.get_speech\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n</dd></dl>\n\n<dl class=\"class\">\n<dt id=\"robot.TTS.XunfeiTTS\">\n<em class=\"property\">class </em><code class=\"descclassname\">robot.TTS.</code><code class=\"descname\">XunfeiTTS</code><span class=\"sig-paren\">(</span><em>appid</em>, <em>asr_api_key</em>, <em>asr_api_secret</em>, <em>tts_api_key</em>, <em>voice='xiaoyan'</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/TTS.html#XunfeiTTS\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.TTS.XunfeiTTS\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>基类：<a class=\"reference internal\" href=\"#robot.TTS.AbstractTTS\" title=\"robot.TTS.AbstractTTS\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">robot.TTS.AbstractTTS</span></code></a></p>\n<p>科大讯飞的语音识别API.\n外网ip查询：<a class=\"reference external\" href=\"https://ip.51240.com/\">https://ip.51240.com/</a>\nvoice_name: <a class=\"reference external\" href=\"https://www.xfyun.cn/services/online_tts\">https://www.xfyun.cn/services/online_tts</a></p>\n<dl class=\"attribute\">\n<dt id=\"robot.TTS.XunfeiTTS.SLUG\">\n<code class=\"descname\">SLUG</code><em class=\"property\"> = 'xunfei-tts'</em><a class=\"headerlink\" href=\"#robot.TTS.XunfeiTTS.SLUG\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.TTS.XunfeiTTS.getBody\">\n<code class=\"descname\">getBody</code><span class=\"sig-paren\">(</span><em>text</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/TTS.html#XunfeiTTS.getBody\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.TTS.XunfeiTTS.getBody\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.TTS.XunfeiTTS.getHeader\">\n<code class=\"descname\">getHeader</code><span class=\"sig-paren\">(</span><em>aue</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/TTS.html#XunfeiTTS.getHeader\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.TTS.XunfeiTTS.getHeader\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"classmethod\">\n<dt id=\"robot.TTS.XunfeiTTS.get_config\">\n<em class=\"property\">classmethod </em><code class=\"descname\">get_config</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/TTS.html#XunfeiTTS.get_config\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.TTS.XunfeiTTS.get_config\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.TTS.XunfeiTTS.get_speech\">\n<code class=\"descname\">get_speech</code><span class=\"sig-paren\">(</span><em>phrase</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/TTS.html#XunfeiTTS.get_speech\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.TTS.XunfeiTTS.get_speech\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n</dd></dl>\n\n<dl class=\"function\">\n<dt id=\"robot.TTS.get_engine_by_slug\">\n<code class=\"descclassname\">robot.TTS.</code><code class=\"descname\">get_engine_by_slug</code><span class=\"sig-paren\">(</span><em>slug=None</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/TTS.html#get_engine_by_slug\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.TTS.get_engine_by_slug\" title=\"永久链接至目标\">¶</a></dt>\n<dd><dl class=\"docutils\">\n<dt>Returns:</dt>\n<dd>A TTS Engine implementation available on the current platform</dd>\n<dt>Raises:</dt>\n<dd>ValueError if no speaker implementation is supported on this platform</dd>\n</dl>\n</dd></dl>\n\n<dl class=\"function\">\n<dt id=\"robot.TTS.get_engines\">\n<code class=\"descclassname\">robot.TTS.</code><code class=\"descname\">get_engines</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/TTS.html#get_engines\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.TTS.get_engines\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n</div>\n<div class=\"section\" id=\"module-robot.Updater\">\n<span id=\"robot-updater-module\"></span><h2>robot.Updater module<a class=\"headerlink\" href=\"#module-robot.Updater\" title=\"永久链接至标题\">¶</a></h2>\n<dl class=\"class\">\n<dt id=\"robot.Updater.Updater\">\n<em class=\"property\">class </em><code class=\"descclassname\">robot.Updater.</code><code class=\"descname\">Updater</code><a class=\"reference internal\" href=\"_modules/robot/Updater.html#Updater\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.Updater.Updater\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>基类：<code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">object</span></code></p>\n<dl class=\"method\">\n<dt id=\"robot.Updater.Updater.fetch\">\n<code class=\"descname\">fetch</code><span class=\"sig-paren\">(</span><em>dev=False</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/Updater.html#Updater.fetch\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.Updater.Updater.fetch\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.Updater.Updater.update\">\n<code class=\"descname\">update</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/Updater.html#Updater.update\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.Updater.Updater.update\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n</dd></dl>\n\n<dl class=\"function\">\n<dt id=\"robot.Updater.fetch\">\n<code class=\"descclassname\">robot.Updater.</code><code class=\"descname\">fetch</code><span class=\"sig-paren\">(</span><em>dev</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/Updater.html#fetch\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.Updater.fetch\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n</div>\n<div class=\"section\" id=\"module-robot.config\">\n<span id=\"robot-config-module\"></span><h2>robot.config module<a class=\"headerlink\" href=\"#module-robot.config\" title=\"永久链接至标题\">¶</a></h2>\n<dl class=\"function\">\n<dt id=\"robot.config.doInit\">\n<code class=\"descclassname\">robot.config.</code><code class=\"descname\">doInit</code><span class=\"sig-paren\">(</span><em>config_file='/Users/panweizhou/Documents/projects/wukong-robot/static/default.yml'</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/config.html#doInit\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.config.doInit\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"function\">\n<dt id=\"robot.config.dump\">\n<code class=\"descclassname\">robot.config.</code><code class=\"descname\">dump</code><span class=\"sig-paren\">(</span><em>configStr</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/config.html#dump\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.config.dump\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"function\">\n<dt id=\"robot.config.get\">\n<code class=\"descclassname\">robot.config.</code><code class=\"descname\">get</code><span class=\"sig-paren\">(</span><em>item=''</em>, <em>default=None</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/config.html#get\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.config.get\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>获取某个配置的值</p>\n<table class=\"docutils field-list\" frame=\"void\" rules=\"none\">\n<col class=\"field-name\" />\n<col class=\"field-body\" />\n<tbody valign=\"top\">\n<tr class=\"field-odd field\"><th class=\"field-name\">参数:</th><td class=\"field-body\"><ul class=\"first simple\">\n<li><strong>item</strong> – 配置项名。如果是多级配置，则以 “/a/b” 的形式提供</li>\n<li><strong>default</strong> – 默认值（可选）</li>\n</ul>\n</td>\n</tr>\n<tr class=\"field-even field\"><th class=\"field-name\">返回:</th><td class=\"field-body\"><p class=\"first last\">这个配置的值。如果没有该配置，则提供一个默认值</p>\n</td>\n</tr>\n</tbody>\n</table>\n</dd></dl>\n\n<dl class=\"function\">\n<dt id=\"robot.config.getConfig\">\n<code class=\"descclassname\">robot.config.</code><code class=\"descname\">getConfig</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/config.html#getConfig\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.config.getConfig\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>返回全部配置数据</p>\n<table class=\"docutils field-list\" frame=\"void\" rules=\"none\">\n<col class=\"field-name\" />\n<col class=\"field-body\" />\n<tbody valign=\"top\">\n<tr class=\"field-odd field\"><th class=\"field-name\">返回:</th><td class=\"field-body\">全部配置数据（字典类型）</td>\n</tr>\n</tbody>\n</table>\n</dd></dl>\n\n<dl class=\"function\">\n<dt id=\"robot.config.getText\">\n<code class=\"descclassname\">robot.config.</code><code class=\"descname\">getText</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/config.html#getText\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.config.getText\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"function\">\n<dt id=\"robot.config.get_path\">\n<code class=\"descclassname\">robot.config.</code><code class=\"descname\">get_path</code><span class=\"sig-paren\">(</span><em>items</em>, <em>default=None</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/config.html#get_path\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.config.get_path\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"function\">\n<dt id=\"robot.config.has\">\n<code class=\"descclassname\">robot.config.</code><code class=\"descname\">has</code><span class=\"sig-paren\">(</span><em>item</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/config.html#has\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.config.has\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>判断配置里是否包含某个配置项</p>\n<table class=\"docutils field-list\" frame=\"void\" rules=\"none\">\n<col class=\"field-name\" />\n<col class=\"field-body\" />\n<tbody valign=\"top\">\n<tr class=\"field-odd field\"><th class=\"field-name\">参数:</th><td class=\"field-body\"><strong>item</strong> – 配置项名</td>\n</tr>\n<tr class=\"field-even field\"><th class=\"field-name\">返回:</th><td class=\"field-body\">True: 包含; False: 不包含</td>\n</tr>\n</tbody>\n</table>\n</dd></dl>\n\n<dl class=\"function\">\n<dt id=\"robot.config.has_path\">\n<code class=\"descclassname\">robot.config.</code><code class=\"descname\">has_path</code><span class=\"sig-paren\">(</span><em>items</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/config.html#has_path\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.config.has_path\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"function\">\n<dt id=\"robot.config.init\">\n<code class=\"descclassname\">robot.config.</code><code class=\"descname\">init</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/config.html#init\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.config.init\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"function\">\n<dt id=\"robot.config.reload\">\n<code class=\"descclassname\">robot.config.</code><code class=\"descname\">reload</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/config.html#reload\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.config.reload\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>重新加载配置</p>\n</dd></dl>\n\n</div>\n<div class=\"section\" id=\"module-robot.constants\">\n<span id=\"robot-constants-module\"></span><h2>robot.constants module<a class=\"headerlink\" href=\"#module-robot.constants\" title=\"永久链接至标题\">¶</a></h2>\n<dl class=\"function\">\n<dt id=\"robot.constants.getConfigData\">\n<code class=\"descclassname\">robot.constants.</code><code class=\"descname\">getConfigData</code><span class=\"sig-paren\">(</span><em>*fname</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/constants.html#getConfigData\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.constants.getConfigData\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>获取配置目录下的指定文件的路径</p>\n<table class=\"docutils field-list\" frame=\"void\" rules=\"none\">\n<col class=\"field-name\" />\n<col class=\"field-body\" />\n<tbody valign=\"top\">\n<tr class=\"field-odd field\"><th class=\"field-name\">参数:</th><td class=\"field-body\"><strong>*fname</strong> – <p>指定文件名。如果传多个，则自动拼接</p>\n</td>\n</tr>\n<tr class=\"field-even field\"><th class=\"field-name\">返回:</th><td class=\"field-body\">配置目录下的某个文件的存储路径</td>\n</tr>\n</tbody>\n</table>\n</dd></dl>\n\n<dl class=\"function\">\n<dt id=\"robot.constants.getConfigPath\">\n<code class=\"descclassname\">robot.constants.</code><code class=\"descname\">getConfigPath</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/constants.html#getConfigPath\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.constants.getConfigPath\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>获取配置文件的路径</p>\n<p>returns: 配置文件的存储路径</p>\n</dd></dl>\n\n<dl class=\"function\">\n<dt id=\"robot.constants.getData\">\n<code class=\"descclassname\">robot.constants.</code><code class=\"descname\">getData</code><span class=\"sig-paren\">(</span><em>*fname</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/constants.html#getData\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.constants.getData\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>获取资源目录下指定文件的路径</p>\n<table class=\"docutils field-list\" frame=\"void\" rules=\"none\">\n<col class=\"field-name\" />\n<col class=\"field-body\" />\n<tbody valign=\"top\">\n<tr class=\"field-odd field\"><th class=\"field-name\">参数:</th><td class=\"field-body\"><strong>*fname</strong> – <p>指定文件名。如果传多个，则自动拼接</p>\n</td>\n</tr>\n<tr class=\"field-even field\"><th class=\"field-name\">返回:</th><td class=\"field-body\">配置文件的存储路径</td>\n</tr>\n</tbody>\n</table>\n</dd></dl>\n\n<dl class=\"function\">\n<dt id=\"robot.constants.getDefaultConfigPath\">\n<code class=\"descclassname\">robot.constants.</code><code class=\"descname\">getDefaultConfigPath</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/constants.html#getDefaultConfigPath\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.constants.getDefaultConfigPath\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"function\">\n<dt id=\"robot.constants.getHotwordModel\">\n<code class=\"descclassname\">robot.constants.</code><code class=\"descname\">getHotwordModel</code><span class=\"sig-paren\">(</span><em>fname</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/constants.html#getHotwordModel\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.constants.getHotwordModel\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"function\">\n<dt id=\"robot.constants.newConfig\">\n<code class=\"descclassname\">robot.constants.</code><code class=\"descname\">newConfig</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/constants.html#newConfig\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.constants.newConfig\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n</div>\n<div class=\"section\" id=\"module-robot.logging\">\n<span id=\"robot-logging-module\"></span><h2>robot.logging module<a class=\"headerlink\" href=\"#module-robot.logging\" title=\"永久链接至标题\">¶</a></h2>\n<dl class=\"function\">\n<dt id=\"robot.logging.getLogger\">\n<code class=\"descclassname\">robot.logging.</code><code class=\"descname\">getLogger</code><span class=\"sig-paren\">(</span><em>name</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/logging.html#getLogger\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.logging.getLogger\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>作用同标准模块 logging.getLogger(name)</p>\n<table class=\"docutils field-list\" frame=\"void\" rules=\"none\">\n<col class=\"field-name\" />\n<col class=\"field-body\" />\n<tbody valign=\"top\">\n<tr class=\"field-odd field\"><th class=\"field-name\">返回:</th><td class=\"field-body\">logger</td>\n</tr>\n</tbody>\n</table>\n</dd></dl>\n\n<dl class=\"function\">\n<dt id=\"robot.logging.readLog\">\n<code class=\"descclassname\">robot.logging.</code><code class=\"descname\">readLog</code><span class=\"sig-paren\">(</span><em>lines=200</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/logging.html#readLog\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.logging.readLog\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>获取最新的指定行数的 log</p>\n<table class=\"docutils field-list\" frame=\"void\" rules=\"none\">\n<col class=\"field-name\" />\n<col class=\"field-body\" />\n<tbody valign=\"top\">\n<tr class=\"field-odd field\"><th class=\"field-name\">参数:</th><td class=\"field-body\"><strong>lines</strong> – 最大的行数</td>\n</tr>\n<tr class=\"field-even field\"><th class=\"field-name\">返回:</th><td class=\"field-body\">最新指定行数的 log</td>\n</tr>\n</tbody>\n</table>\n</dd></dl>\n\n<dl class=\"function\">\n<dt id=\"robot.logging.tail\">\n<code class=\"descclassname\">robot.logging.</code><code class=\"descname\">tail</code><span class=\"sig-paren\">(</span><em>filepath</em>, <em>n=10</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/logging.html#tail\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.logging.tail\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>实现 tail -n</p>\n</dd></dl>\n\n</div>\n<div class=\"section\" id=\"module-robot.plugin_loader\">\n<span id=\"robot-plugin-loader-module\"></span><h2>robot.plugin_loader module<a class=\"headerlink\" href=\"#module-robot.plugin_loader\" title=\"永久链接至标题\">¶</a></h2>\n<dl class=\"function\">\n<dt id=\"robot.plugin_loader.get_plugins\">\n<code class=\"descclassname\">robot.plugin_loader.</code><code class=\"descname\">get_plugins</code><span class=\"sig-paren\">(</span><em>con</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/plugin_loader.html#get_plugins\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.plugin_loader.get_plugins\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"function\">\n<dt id=\"robot.plugin_loader.init_plugins\">\n<code class=\"descclassname\">robot.plugin_loader.</code><code class=\"descname\">init_plugins</code><span class=\"sig-paren\">(</span><em>con</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/plugin_loader.html#init_plugins\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.plugin_loader.init_plugins\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>动态加载技能插件</p>\n<p>参数：\ncon – 会话模块</p>\n</dd></dl>\n\n</div>\n<div class=\"section\" id=\"module-robot.statistic\">\n<span id=\"robot-statistic-module\"></span><h2>robot.statistic module<a class=\"headerlink\" href=\"#module-robot.statistic\" title=\"永久链接至标题\">¶</a></h2>\n<dl class=\"class\">\n<dt id=\"robot.statistic.ReportThread\">\n<em class=\"property\">class </em><code class=\"descclassname\">robot.statistic.</code><code class=\"descname\">ReportThread</code><span class=\"sig-paren\">(</span><em>t</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/statistic.html#ReportThread\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.statistic.ReportThread\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>基类：<code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">threading.Thread</span></code></p>\n<dl class=\"method\">\n<dt id=\"robot.statistic.ReportThread.run\">\n<code class=\"descname\">run</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/statistic.html#ReportThread.run\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.statistic.ReportThread.run\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Method representing the thread’s activity.</p>\n<p>You may override this method in a subclass. The standard run() method\ninvokes the callable object passed to the object’s constructor as the\ntarget argument, if any, with sequential and keyword arguments taken\nfrom the args and kwargs arguments, respectively.</p>\n</dd></dl>\n\n</dd></dl>\n\n<dl class=\"function\">\n<dt id=\"robot.statistic.getUUID\">\n<code class=\"descclassname\">robot.statistic.</code><code class=\"descname\">getUUID</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/statistic.html#getUUID\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.statistic.getUUID\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"function\">\n<dt id=\"robot.statistic.report\">\n<code class=\"descclassname\">robot.statistic.</code><code class=\"descname\">report</code><span class=\"sig-paren\">(</span><em>t</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/statistic.html#report\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.statistic.report\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n</div>\n<div class=\"section\" id=\"module-robot.utils\">\n<span id=\"robot-utils-module\"></span><h2>robot.utils module<a class=\"headerlink\" href=\"#module-robot.utils\" title=\"永久链接至标题\">¶</a></h2>\n<dl class=\"function\">\n<dt id=\"robot.utils.check_and_delete\">\n<code class=\"descclassname\">robot.utils.</code><code class=\"descname\">check_and_delete</code><span class=\"sig-paren\">(</span><em>fp</em>, <em>wait=0</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/utils.html#check_and_delete\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.utils.check_and_delete\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>检查并删除文件/文件夹</p>\n<table class=\"docutils field-list\" frame=\"void\" rules=\"none\">\n<col class=\"field-name\" />\n<col class=\"field-body\" />\n<tbody valign=\"top\">\n<tr class=\"field-odd field\"><th class=\"field-name\">参数:</th><td class=\"field-body\"><strong>fp</strong> – 文件路径</td>\n</tr>\n</tbody>\n</table>\n</dd></dl>\n\n<dl class=\"function\">\n<dt id=\"robot.utils.clean\">\n<code class=\"descclassname\">robot.utils.</code><code class=\"descname\">clean</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/utils.html#clean\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.utils.clean\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>清理垃圾数据</p>\n</dd></dl>\n\n<dl class=\"function\">\n<dt id=\"robot.utils.convert_mp3_to_wav\">\n<code class=\"descclassname\">robot.utils.</code><code class=\"descname\">convert_mp3_to_wav</code><span class=\"sig-paren\">(</span><em>mp3_path</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/utils.html#convert_mp3_to_wav\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.utils.convert_mp3_to_wav\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>将 mp3 文件转成 wav</p>\n<table class=\"docutils field-list\" frame=\"void\" rules=\"none\">\n<col class=\"field-name\" />\n<col class=\"field-body\" />\n<tbody valign=\"top\">\n<tr class=\"field-odd field\"><th class=\"field-name\">参数:</th><td class=\"field-body\"><strong>mp3_path</strong> – mp3 文件路径</td>\n</tr>\n<tr class=\"field-even field\"><th class=\"field-name\">返回:</th><td class=\"field-body\">wav 文件路径</td>\n</tr>\n</tbody>\n</table>\n</dd></dl>\n\n<dl class=\"function\">\n<dt id=\"robot.utils.convert_wav_to_mp3\">\n<code class=\"descclassname\">robot.utils.</code><code class=\"descname\">convert_wav_to_mp3</code><span class=\"sig-paren\">(</span><em>wav_path</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/utils.html#convert_wav_to_mp3\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.utils.convert_wav_to_mp3\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>将 wav 文件转成 mp3</p>\n<table class=\"docutils field-list\" frame=\"void\" rules=\"none\">\n<col class=\"field-name\" />\n<col class=\"field-body\" />\n<tbody valign=\"top\">\n<tr class=\"field-odd field\"><th class=\"field-name\">参数:</th><td class=\"field-body\"><strong>wav_path</strong> – wav 文件路径</td>\n</tr>\n<tr class=\"field-even field\"><th class=\"field-name\">返回:</th><td class=\"field-body\">mp3 文件路径</td>\n</tr>\n</tbody>\n</table>\n</dd></dl>\n\n<dl class=\"function\">\n<dt id=\"robot.utils.emailUser\">\n<code class=\"descclassname\">robot.utils.</code><code class=\"descname\">emailUser</code><span class=\"sig-paren\">(</span><em>SUBJECT=''</em>, <em>BODY=''</em>, <em>ATTACH_LIST=[]</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/utils.html#emailUser\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.utils.emailUser\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>给用户发送邮件</p>\n<table class=\"docutils field-list\" frame=\"void\" rules=\"none\">\n<col class=\"field-name\" />\n<col class=\"field-body\" />\n<tbody valign=\"top\">\n<tr class=\"field-odd field\"><th class=\"field-name\">参数:</th><td class=\"field-body\"><ul class=\"first simple\">\n<li><strong>SUBJECT</strong> – subject line of the email</li>\n<li><strong>BODY</strong> – body text of the email</li>\n</ul>\n</td>\n</tr>\n<tr class=\"field-even field\"><th class=\"field-name\">返回:</th><td class=\"field-body\"><p class=\"first last\">True: 发送成功; False: 发送失败</p>\n</td>\n</tr>\n</tbody>\n</table>\n</dd></dl>\n\n<dl class=\"function\">\n<dt id=\"robot.utils.getCache\">\n<code class=\"descclassname\">robot.utils.</code><code class=\"descname\">getCache</code><span class=\"sig-paren\">(</span><em>msg</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/utils.html#getCache\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.utils.getCache\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>获取缓存的语音</p>\n</dd></dl>\n\n<dl class=\"function\">\n<dt id=\"robot.utils.getTimezone\">\n<code class=\"descclassname\">robot.utils.</code><code class=\"descname\">getTimezone</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/utils.html#getTimezone\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.utils.getTimezone\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>获取时区</p>\n</dd></dl>\n\n<dl class=\"function\">\n<dt id=\"robot.utils.get_do_not_bother_off_hotword\">\n<code class=\"descclassname\">robot.utils.</code><code class=\"descname\">get_do_not_bother_off_hotword</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/utils.html#get_do_not_bother_off_hotword\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.utils.get_do_not_bother_off_hotword\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>关闭勿扰模式唤醒词</p>\n</dd></dl>\n\n<dl class=\"function\">\n<dt id=\"robot.utils.get_do_not_bother_on_hotword\">\n<code class=\"descclassname\">robot.utils.</code><code class=\"descname\">get_do_not_bother_on_hotword</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/utils.html#get_do_not_bother_on_hotword\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.utils.get_do_not_bother_on_hotword\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>打开勿扰模式唤醒词</p>\n</dd></dl>\n\n<dl class=\"function\">\n<dt id=\"robot.utils.get_file_content\">\n<code class=\"descclassname\">robot.utils.</code><code class=\"descname\">get_file_content</code><span class=\"sig-paren\">(</span><em>filePath</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/utils.html#get_file_content\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.utils.get_file_content\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>读取文件内容并返回</p>\n<table class=\"docutils field-list\" frame=\"void\" rules=\"none\">\n<col class=\"field-name\" />\n<col class=\"field-body\" />\n<tbody valign=\"top\">\n<tr class=\"field-odd field\"><th class=\"field-name\">参数:</th><td class=\"field-body\"><strong>filePath</strong> – 文件路径</td>\n</tr>\n<tr class=\"field-even field\"><th class=\"field-name\">返回:</th><td class=\"field-body\">文件内容</td>\n</tr>\n<tr class=\"field-odd field\"><th class=\"field-name\">引发:</th><td class=\"field-body\"><strong>IOError</strong> – 读取失败则抛出 IOError</td>\n</tr>\n</tbody>\n</table>\n</dd></dl>\n\n<dl class=\"function\">\n<dt id=\"robot.utils.get_pcm_from_wav\">\n<code class=\"descclassname\">robot.utils.</code><code class=\"descname\">get_pcm_from_wav</code><span class=\"sig-paren\">(</span><em>wav_path</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/utils.html#get_pcm_from_wav\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.utils.get_pcm_from_wav\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>从 wav 文件中读取 pcm</p>\n<table class=\"docutils field-list\" frame=\"void\" rules=\"none\">\n<col class=\"field-name\" />\n<col class=\"field-body\" />\n<tbody valign=\"top\">\n<tr class=\"field-odd field\"><th class=\"field-name\">参数:</th><td class=\"field-body\"><strong>wav_path</strong> – wav 文件路径</td>\n</tr>\n<tr class=\"field-even field\"><th class=\"field-name\">返回:</th><td class=\"field-body\">pcm 数据</td>\n</tr>\n</tbody>\n</table>\n</dd></dl>\n\n<dl class=\"function\">\n<dt id=\"robot.utils.is_proper_time\">\n<code class=\"descclassname\">robot.utils.</code><code class=\"descname\">is_proper_time</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/utils.html#is_proper_time\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.utils.is_proper_time\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>是否合适时间</p>\n</dd></dl>\n\n<dl class=\"function\">\n<dt id=\"robot.utils.lruCache\">\n<code class=\"descclassname\">robot.utils.</code><code class=\"descname\">lruCache</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/utils.html#lruCache\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.utils.lruCache\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>清理最近未使用的缓存</p>\n</dd></dl>\n\n<dl class=\"function\">\n<dt id=\"robot.utils.saveCache\">\n<code class=\"descclassname\">robot.utils.</code><code class=\"descname\">saveCache</code><span class=\"sig-paren\">(</span><em>voice</em>, <em>msg</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/utils.html#saveCache\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.utils.saveCache\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>获取缓存的语音</p>\n</dd></dl>\n\n<dl class=\"function\">\n<dt id=\"robot.utils.sendEmail\">\n<code class=\"descclassname\">robot.utils.</code><code class=\"descname\">sendEmail</code><span class=\"sig-paren\">(</span><em>SUBJECT</em>, <em>BODY</em>, <em>ATTACH_LIST</em>, <em>TO</em>, <em>FROM</em>, <em>SENDER</em>, <em>PASSWORD</em>, <em>SMTP_SERVER</em>, <em>SMTP_PORT</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/utils.html#sendEmail\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.utils.sendEmail\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>发送邮件</p>\n<table class=\"docutils field-list\" frame=\"void\" rules=\"none\">\n<col class=\"field-name\" />\n<col class=\"field-body\" />\n<tbody valign=\"top\">\n<tr class=\"field-odd field\"><th class=\"field-name\">参数:</th><td class=\"field-body\"><ul class=\"first simple\">\n<li><strong>SUBJECT</strong> – 邮件标题</li>\n<li><strong>BODY</strong> – 邮件正文</li>\n<li><strong>ATTACH_LIST</strong> – 附件</li>\n<li><strong>TO</strong> – 收件人</li>\n<li><strong>FROM</strong> – 发件人</li>\n<li><strong>SENDER</strong> – 发件人信息</li>\n<li><strong>PASSWORD</strong> – 密码</li>\n<li><strong>SMTP_SERVER</strong> – smtp 服务器</li>\n<li><strong>SMTP_PORT</strong> – smtp 端口号</li>\n</ul>\n</td>\n</tr>\n<tr class=\"field-even field\"><th class=\"field-name\">返回:</th><td class=\"field-body\"><p class=\"first last\">True: 发送成功; False: 发送失败</p>\n</td>\n</tr>\n</tbody>\n</table>\n</dd></dl>\n\n<dl class=\"function\">\n<dt id=\"robot.utils.write_temp_file\">\n<code class=\"descclassname\">robot.utils.</code><code class=\"descname\">write_temp_file</code><span class=\"sig-paren\">(</span><em>data</em>, <em>suffix</em>, <em>mode='w+b'</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/utils.html#write_temp_file\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.utils.write_temp_file\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>写入临时文件</p>\n<table class=\"docutils field-list\" frame=\"void\" rules=\"none\">\n<col class=\"field-name\" />\n<col class=\"field-body\" />\n<tbody valign=\"top\">\n<tr class=\"field-odd field\"><th class=\"field-name\">参数:</th><td class=\"field-body\"><ul class=\"first simple\">\n<li><strong>data</strong> – 数据</li>\n<li><strong>suffix</strong> – 后缀名</li>\n<li><strong>mode</strong> – 写入模式，默认为 w+b</li>\n</ul>\n</td>\n</tr>\n<tr class=\"field-even field\"><th class=\"field-name\">返回:</th><td class=\"field-body\"><p class=\"first last\">文件保存后的路径</p>\n</td>\n</tr>\n</tbody>\n</table>\n</dd></dl>\n\n</div>\n<div class=\"section\" id=\"module-robot\">\n<span id=\"module-contents\"></span><h2>Module contents<a class=\"headerlink\" href=\"#module-robot\" title=\"永久链接至标题\">¶</a></h2>\n</div>\n</div>\n\n\n           </div>\n           \n          </div>\n          <footer>\n  \n\n  <hr/>\n\n  <div role=\"contentinfo\">\n    <p>\n        &copy; Copyright 2019, wzpan\n\n    </p>\n  </div>\n  Built with <a href=\"http://sphinx-doc.org/\">Sphinx</a> using a <a href=\"https://github.com/rtfd/sphinx_rtd_theme\">theme</a> provided by <a href=\"https://readthedocs.org\">Read the Docs</a>. \n\n</footer>\n\n        </div>\n      </div>\n\n    </section>\n\n  </div>\n  \n\n\n  <script type=\"text/javascript\">\n      jQuery(function () {\n          SphinxRtdTheme.Navigation.enable(true);\n      });\n  </script>\n\n  \n  \n    \n   \n\n</body>\n</html>"
  },
  {
    "path": "docs/robot.sdk.html",
    "content": "\n\n<!DOCTYPE html>\n<!--[if IE 8]><html class=\"no-js lt-ie9\" lang=\"zh-CN\" > <![endif]-->\n<!--[if gt IE 8]><!--> <html class=\"no-js\" lang=\"zh-CN\" > <!--<![endif]-->\n<head>\n  <meta charset=\"utf-8\">\n  \n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  \n  <title>robot.sdk package &mdash; wukong-robot 1.2.0 文档</title>\n  \n\n  \n  \n  \n  \n\n  \n  <script type=\"text/javascript\" src=\"_static/js/modernizr.min.js\"></script>\n  \n    \n      <script type=\"text/javascript\" id=\"documentation_options\" data-url_root=\"./\" src=\"_static/documentation_options.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/jquery.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/underscore.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/doctools.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/language_data.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/translations.js\"></script>\n    \n    <script type=\"text/javascript\" src=\"_static/js/theme.js\"></script>\n\n    \n\n  \n  <link rel=\"stylesheet\" href=\"_static/css/theme.css\" type=\"text/css\" />\n  <link rel=\"stylesheet\" href=\"_static/pygments.css\" type=\"text/css\" />\n    <link rel=\"index\" title=\"索引\" href=\"genindex.html\" />\n    <link rel=\"search\" title=\"搜索\" href=\"search.html\" /> \n</head>\n\n<body class=\"wy-body-for-nav\">\n\n   \n  <div class=\"wy-grid-for-nav\">\n    \n    <nav data-toggle=\"wy-nav-shift\" class=\"wy-nav-side\">\n      <div class=\"wy-side-scroll\">\n        <div class=\"wy-side-nav-search\" >\n          \n\n          \n            <a href=\"index.html\" class=\"icon icon-home\"> wukong-robot\n          \n\n          \n          </a>\n\n          \n            \n            \n          \n\n          \n<div role=\"search\">\n  <form id=\"rtd-search-form\" class=\"wy-form\" action=\"search.html\" method=\"get\">\n    <input type=\"text\" name=\"q\" placeholder=\"Search docs\" />\n    <input type=\"hidden\" name=\"check_keywords\" value=\"yes\" />\n    <input type=\"hidden\" name=\"area\" value=\"default\" />\n  </form>\n</div>\n\n          \n        </div>\n\n        <div class=\"wy-menu wy-menu-vertical\" data-spy=\"affix\" role=\"navigation\" aria-label=\"main navigation\">\n          \n            \n            \n              \n            \n            \n              <!-- Local TOC -->\n              <div class=\"local-toc\"><ul>\n<li><a class=\"reference internal\" href=\"#\">robot.sdk package</a><ul>\n<li><a class=\"reference internal\" href=\"#submodules\">Submodules</a></li>\n<li><a class=\"reference internal\" href=\"#module-robot.sdk.AbstractPlugin\">robot.sdk.AbstractPlugin module</a></li>\n<li><a class=\"reference internal\" href=\"#module-robot.sdk.AliSpeech\">robot.sdk.AliSpeech module</a></li>\n<li><a class=\"reference internal\" href=\"#module-robot.sdk.RASRsdk\">robot.sdk.RASRsdk module</a></li>\n<li><a class=\"reference internal\" href=\"#module-robot.sdk.TencentSpeech\">robot.sdk.TencentSpeech module</a></li>\n<li><a class=\"reference internal\" href=\"#module-robot.sdk.XunfeiSpeech\">robot.sdk.XunfeiSpeech module</a></li>\n<li><a class=\"reference internal\" href=\"#module-robot.sdk.unit\">robot.sdk.unit module</a></li>\n<li><a class=\"reference internal\" href=\"#module-robot.sdk\">Module contents</a></li>\n</ul>\n</li>\n</ul>\n</div>\n            \n          \n        </div>\n      </div>\n    </nav>\n\n    <section data-toggle=\"wy-nav-shift\" class=\"wy-nav-content-wrap\">\n\n      \n      <nav class=\"wy-nav-top\" aria-label=\"top navigation\">\n        \n          <i data-toggle=\"wy-nav-top\" class=\"fa fa-bars\"></i>\n          <a href=\"index.html\">wukong-robot</a>\n        \n      </nav>\n\n\n      <div class=\"wy-nav-content\">\n        \n        <div class=\"rst-content\">\n        \n          \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<div role=\"navigation\" aria-label=\"breadcrumbs navigation\">\n\n  <ul class=\"wy-breadcrumbs\">\n    \n      <li><a href=\"index.html\">Docs</a> &raquo;</li>\n        \n      <li>robot.sdk package</li>\n    \n    \n      <li class=\"wy-breadcrumbs-aside\">\n        \n            \n            <a href=\"_sources/robot.sdk.rst.txt\" rel=\"nofollow\"> View page source</a>\n          \n        \n      </li>\n    \n  </ul>\n\n  \n  <hr/>\n</div>\n          <div role=\"main\" class=\"document\" itemscope=\"itemscope\" itemtype=\"http://schema.org/Article\">\n           <div itemprop=\"articleBody\">\n            \n  <div class=\"section\" id=\"robot-sdk-package\">\n<h1>robot.sdk package<a class=\"headerlink\" href=\"#robot-sdk-package\" title=\"永久链接至标题\">¶</a></h1>\n<div class=\"section\" id=\"submodules\">\n<h2>Submodules<a class=\"headerlink\" href=\"#submodules\" title=\"永久链接至标题\">¶</a></h2>\n</div>\n<div class=\"section\" id=\"module-robot.sdk.AbstractPlugin\">\n<span id=\"robot-sdk-abstractplugin-module\"></span><h2>robot.sdk.AbstractPlugin module<a class=\"headerlink\" href=\"#module-robot.sdk.AbstractPlugin\" title=\"永久链接至标题\">¶</a></h2>\n<dl class=\"class\">\n<dt id=\"robot.sdk.AbstractPlugin.AbstractPlugin\">\n<em class=\"property\">class </em><code class=\"descclassname\">robot.sdk.AbstractPlugin.</code><code class=\"descname\">AbstractPlugin</code><span class=\"sig-paren\">(</span><em>con</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/sdk/AbstractPlugin.html#AbstractPlugin\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.sdk.AbstractPlugin.AbstractPlugin\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>基类：<code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">object</span></code></p>\n<p>技能插件基类</p>\n<dl class=\"attribute\">\n<dt id=\"robot.sdk.AbstractPlugin.AbstractPlugin.IS_IMMERSIVE\">\n<code class=\"descname\">IS_IMMERSIVE</code><em class=\"property\"> = False</em><a class=\"headerlink\" href=\"#robot.sdk.AbstractPlugin.AbstractPlugin.IS_IMMERSIVE\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"attribute\">\n<dt id=\"robot.sdk.AbstractPlugin.AbstractPlugin.SLUG\">\n<code class=\"descname\">SLUG</code><em class=\"property\"> = 'AbstractPlugin'</em><a class=\"headerlink\" href=\"#robot.sdk.AbstractPlugin.AbstractPlugin.SLUG\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.sdk.AbstractPlugin.AbstractPlugin.activeListen\">\n<code class=\"descname\">activeListen</code><span class=\"sig-paren\">(</span><em>silent=False</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/sdk/AbstractPlugin.html#AbstractPlugin.activeListen\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.sdk.AbstractPlugin.AbstractPlugin.activeListen\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.sdk.AbstractPlugin.AbstractPlugin.clearImmersive\">\n<code class=\"descname\">clearImmersive</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/sdk/AbstractPlugin.html#AbstractPlugin.clearImmersive\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.sdk.AbstractPlugin.AbstractPlugin.clearImmersive\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.sdk.AbstractPlugin.AbstractPlugin.handle\">\n<code class=\"descname\">handle</code><span class=\"sig-paren\">(</span><em>query</em>, <em>parsed</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/sdk/AbstractPlugin.html#AbstractPlugin.handle\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.sdk.AbstractPlugin.AbstractPlugin.handle\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>处理逻辑</p>\n<p>参数：\nquery – 用户的指令字符串\nparsed – 用户指令经过 NLU 解析后的结果</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.sdk.AbstractPlugin.AbstractPlugin.isValid\">\n<code class=\"descname\">isValid</code><span class=\"sig-paren\">(</span><em>query</em>, <em>parsed</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/sdk/AbstractPlugin.html#AbstractPlugin.isValid\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.sdk.AbstractPlugin.AbstractPlugin.isValid\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>是否适合由该插件处理</p>\n<p>参数：\nquery – 用户的指令字符串\nparsed – 用户指令经过 NLU 解析后的结果</p>\n<p>返回：\nTrue: 适合由该插件处理\nFalse: 不适合由该插件处理</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.sdk.AbstractPlugin.AbstractPlugin.isValidImmersive\">\n<code class=\"descname\">isValidImmersive</code><span class=\"sig-paren\">(</span><em>query</em>, <em>parsed</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/sdk/AbstractPlugin.html#AbstractPlugin.isValidImmersive\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.sdk.AbstractPlugin.AbstractPlugin.isValidImmersive\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>是否适合在沉浸模式下处理，\n仅适用于有沉浸模式的插件（如音乐等）\n当用户唤醒时，可以响应更多指令集。\n例如：“”上一首”、”下一首” 等</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.sdk.AbstractPlugin.AbstractPlugin.pause\">\n<code class=\"descname\">pause</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/sdk/AbstractPlugin.html#AbstractPlugin.pause\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.sdk.AbstractPlugin.AbstractPlugin.pause\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>暂停当前正在处理的任务，\n当处于该沉浸模式下且被唤醒时，\n将自动触发这个方法，\n可以用于强制暂停一个耗时的操作</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.sdk.AbstractPlugin.AbstractPlugin.play\">\n<code class=\"descname\">play</code><span class=\"sig-paren\">(</span><em>src</em>, <em>delete=False</em>, <em>onCompleted=None</em>, <em>volume=1</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/sdk/AbstractPlugin.html#AbstractPlugin.play\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.sdk.AbstractPlugin.AbstractPlugin.play\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.sdk.AbstractPlugin.AbstractPlugin.restore\">\n<code class=\"descname\">restore</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/sdk/AbstractPlugin.html#AbstractPlugin.restore\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.sdk.AbstractPlugin.AbstractPlugin.restore\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>恢复当前插件，\n仅适用于有沉浸模式的插件（如音乐等）\n当用户误唤醒或者唤醒进行闲聊后，\n可以自动恢复当前插件的处理逻辑</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.sdk.AbstractPlugin.AbstractPlugin.say\">\n<code class=\"descname\">say</code><span class=\"sig-paren\">(</span><em>text</em>, <em>cache=False</em>, <em>onCompleted=None</em>, <em>wait=False</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/sdk/AbstractPlugin.html#AbstractPlugin.say\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.sdk.AbstractPlugin.AbstractPlugin.say\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n</dd></dl>\n\n</div>\n<div class=\"section\" id=\"module-robot.sdk.AliSpeech\">\n<span id=\"robot-sdk-alispeech-module\"></span><h2>robot.sdk.AliSpeech module<a class=\"headerlink\" href=\"#module-robot.sdk.AliSpeech\" title=\"永久链接至标题\">¶</a></h2>\n<dl class=\"function\">\n<dt id=\"robot.sdk.AliSpeech.asr\">\n<code class=\"descclassname\">robot.sdk.AliSpeech.</code><code class=\"descname\">asr</code><span class=\"sig-paren\">(</span><em>appKey</em>, <em>token</em>, <em>wave_file</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/sdk/AliSpeech.html#asr\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.sdk.AliSpeech.asr\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"function\">\n<dt id=\"robot.sdk.AliSpeech.process\">\n<code class=\"descclassname\">robot.sdk.AliSpeech.</code><code class=\"descname\">process</code><span class=\"sig-paren\">(</span><em>request</em>, <em>token</em>, <em>audioContent</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/sdk/AliSpeech.html#process\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.sdk.AliSpeech.process\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"function\">\n<dt id=\"robot.sdk.AliSpeech.processGETRequest\">\n<code class=\"descclassname\">robot.sdk.AliSpeech.</code><code class=\"descname\">processGETRequest</code><span class=\"sig-paren\">(</span><em>appKey</em>, <em>token</em>, <em>voice</em>, <em>text</em>, <em>format</em>, <em>sampleRate</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/sdk/AliSpeech.html#processGETRequest\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.sdk.AliSpeech.processGETRequest\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"function\">\n<dt id=\"robot.sdk.AliSpeech.processPOSTRequest\">\n<code class=\"descclassname\">robot.sdk.AliSpeech.</code><code class=\"descname\">processPOSTRequest</code><span class=\"sig-paren\">(</span><em>appKey</em>, <em>token</em>, <em>voice</em>, <em>text</em>, <em>format</em>, <em>sampleRate</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/sdk/AliSpeech.html#processPOSTRequest\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.sdk.AliSpeech.processPOSTRequest\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"function\">\n<dt id=\"robot.sdk.AliSpeech.tts\">\n<code class=\"descclassname\">robot.sdk.AliSpeech.</code><code class=\"descname\">tts</code><span class=\"sig-paren\">(</span><em>appKey</em>, <em>token</em>, <em>voice</em>, <em>text</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/sdk/AliSpeech.html#tts\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.sdk.AliSpeech.tts\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n</div>\n<div class=\"section\" id=\"module-robot.sdk.RASRsdk\">\n<span id=\"robot-sdk-rasrsdk-module\"></span><h2>robot.sdk.RASRsdk module<a class=\"headerlink\" href=\"#module-robot.sdk.RASRsdk\" title=\"永久链接至标题\">¶</a></h2>\n<dl class=\"function\">\n<dt id=\"robot.sdk.RASRsdk.formatSignString\">\n<code class=\"descclassname\">robot.sdk.RASRsdk.</code><code class=\"descname\">formatSignString</code><span class=\"sig-paren\">(</span><em>param</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/sdk/RASRsdk.html#formatSignString\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.sdk.RASRsdk.formatSignString\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"function\">\n<dt id=\"robot.sdk.RASRsdk.randstr\">\n<code class=\"descclassname\">robot.sdk.RASRsdk.</code><code class=\"descname\">randstr</code><span class=\"sig-paren\">(</span><em>n</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/sdk/RASRsdk.html#randstr\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.sdk.RASRsdk.randstr\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"function\">\n<dt id=\"robot.sdk.RASRsdk.sendVoice\">\n<code class=\"descclassname\">robot.sdk.RASRsdk.</code><code class=\"descname\">sendVoice</code><span class=\"sig-paren\">(</span><em>secret_key</em>, <em>secretid</em>, <em>appid</em>, <em>engine_model_type</em>, <em>res_type</em>, <em>result_text_format</em>, <em>voice_format</em>, <em>filepath</em>, <em>cutlength</em>, <em>template_name=''</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/sdk/RASRsdk.html#sendVoice\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.sdk.RASRsdk.sendVoice\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"function\">\n<dt id=\"robot.sdk.RASRsdk.sign\">\n<code class=\"descclassname\">robot.sdk.RASRsdk.</code><code class=\"descname\">sign</code><span class=\"sig-paren\">(</span><em>signstr</em>, <em>secret_key</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/sdk/RASRsdk.html#sign\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.sdk.RASRsdk.sign\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n</div>\n<div class=\"section\" id=\"module-robot.sdk.TencentSpeech\">\n<span id=\"robot-sdk-tencentspeech-module\"></span><h2>robot.sdk.TencentSpeech module<a class=\"headerlink\" href=\"#module-robot.sdk.TencentSpeech\" title=\"永久链接至标题\">¶</a></h2>\n<p>Tencent ASR &amp;&amp; TTS API</p>\n<dl class=\"class\">\n<dt id=\"robot.sdk.TencentSpeech.tencentSpeech\">\n<em class=\"property\">class </em><code class=\"descclassname\">robot.sdk.TencentSpeech.</code><code class=\"descname\">tencentSpeech</code><span class=\"sig-paren\">(</span><em>SECRET_KEY</em>, <em>SECRET_ID</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/sdk/TencentSpeech.html#tencentSpeech\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.sdk.TencentSpeech.tencentSpeech\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>基类：<code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">object</span></code></p>\n<dl class=\"method\">\n<dt id=\"robot.sdk.TencentSpeech.tencentSpeech.ASR\">\n<code class=\"descname\">ASR</code><span class=\"sig-paren\">(</span><em>URL</em>, <em>voiceformat</em>, <em>sourcetype</em>, <em>region</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/sdk/TencentSpeech.html#tencentSpeech.ASR\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.sdk.TencentSpeech.tencentSpeech.ASR\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"attribute\">\n<dt id=\"robot.sdk.TencentSpeech.tencentSpeech.PrimaryLanguage\">\n<code class=\"descname\">PrimaryLanguage</code><a class=\"headerlink\" href=\"#robot.sdk.TencentSpeech.tencentSpeech.PrimaryLanguage\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"attribute\">\n<dt id=\"robot.sdk.TencentSpeech.tencentSpeech.Region\">\n<code class=\"descname\">Region</code><a class=\"headerlink\" href=\"#robot.sdk.TencentSpeech.tencentSpeech.Region\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"attribute\">\n<dt id=\"robot.sdk.TencentSpeech.tencentSpeech.SECRET_ID\">\n<code class=\"descname\">SECRET_ID</code><a class=\"headerlink\" href=\"#robot.sdk.TencentSpeech.tencentSpeech.SECRET_ID\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"attribute\">\n<dt id=\"robot.sdk.TencentSpeech.tencentSpeech.SECRET_KEY\">\n<code class=\"descname\">SECRET_KEY</code><a class=\"headerlink\" href=\"#robot.sdk.TencentSpeech.tencentSpeech.SECRET_KEY\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"attribute\">\n<dt id=\"robot.sdk.TencentSpeech.tencentSpeech.SourceType\">\n<code class=\"descname\">SourceType</code><a class=\"headerlink\" href=\"#robot.sdk.TencentSpeech.tencentSpeech.SourceType\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.sdk.TencentSpeech.tencentSpeech.TTS\">\n<code class=\"descname\">TTS</code><span class=\"sig-paren\">(</span><em>text</em>, <em>voicetype</em>, <em>primarylanguage</em>, <em>region</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/sdk/TencentSpeech.html#tencentSpeech.TTS\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.sdk.TencentSpeech.tencentSpeech.TTS\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"attribute\">\n<dt id=\"robot.sdk.TencentSpeech.tencentSpeech.Text\">\n<code class=\"descname\">Text</code><a class=\"headerlink\" href=\"#robot.sdk.TencentSpeech.tencentSpeech.Text\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"attribute\">\n<dt id=\"robot.sdk.TencentSpeech.tencentSpeech.URL\">\n<code class=\"descname\">URL</code><a class=\"headerlink\" href=\"#robot.sdk.TencentSpeech.tencentSpeech.URL\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"attribute\">\n<dt id=\"robot.sdk.TencentSpeech.tencentSpeech.VoiceFormat\">\n<code class=\"descname\">VoiceFormat</code><a class=\"headerlink\" href=\"#robot.sdk.TencentSpeech.tencentSpeech.VoiceFormat\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"attribute\">\n<dt id=\"robot.sdk.TencentSpeech.tencentSpeech.VoiceType\">\n<code class=\"descname\">VoiceType</code><a class=\"headerlink\" href=\"#robot.sdk.TencentSpeech.tencentSpeech.VoiceType\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.sdk.TencentSpeech.tencentSpeech.encode_sign\">\n<code class=\"descname\">encode_sign</code><span class=\"sig-paren\">(</span><em>signstr</em>, <em>SECRET_KEY</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/sdk/TencentSpeech.html#tencentSpeech.encode_sign\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.sdk.TencentSpeech.tencentSpeech.encode_sign\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.sdk.TencentSpeech.tencentSpeech.formatSignString\">\n<code class=\"descname\">formatSignString</code><span class=\"sig-paren\">(</span><em>config_dict</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/sdk/TencentSpeech.html#tencentSpeech.formatSignString\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.sdk.TencentSpeech.tencentSpeech.formatSignString\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.sdk.TencentSpeech.tencentSpeech.oneSentenceRecognition\">\n<code class=\"descname\">oneSentenceRecognition</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/sdk/TencentSpeech.html#tencentSpeech.oneSentenceRecognition\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.sdk.TencentSpeech.tencentSpeech.oneSentenceRecognition\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"attribute\">\n<dt id=\"robot.sdk.TencentSpeech.tencentSpeech.primarylanguage\">\n<code class=\"descname\">primarylanguage</code><a class=\"headerlink\" href=\"#robot.sdk.TencentSpeech.tencentSpeech.primarylanguage\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"attribute\">\n<dt id=\"robot.sdk.TencentSpeech.tencentSpeech.region\">\n<code class=\"descname\">region</code><a class=\"headerlink\" href=\"#robot.sdk.TencentSpeech.tencentSpeech.region\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"attribute\">\n<dt id=\"robot.sdk.TencentSpeech.tencentSpeech.secret_id\">\n<code class=\"descname\">secret_id</code><a class=\"headerlink\" href=\"#robot.sdk.TencentSpeech.tencentSpeech.secret_id\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"attribute\">\n<dt id=\"robot.sdk.TencentSpeech.tencentSpeech.secret_key\">\n<code class=\"descname\">secret_key</code><a class=\"headerlink\" href=\"#robot.sdk.TencentSpeech.tencentSpeech.secret_key\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"attribute\">\n<dt id=\"robot.sdk.TencentSpeech.tencentSpeech.source_type\">\n<code class=\"descname\">source_type</code><a class=\"headerlink\" href=\"#robot.sdk.TencentSpeech.tencentSpeech.source_type\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"attribute\">\n<dt id=\"robot.sdk.TencentSpeech.tencentSpeech.text\">\n<code class=\"descname\">text</code><a class=\"headerlink\" href=\"#robot.sdk.TencentSpeech.tencentSpeech.text\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"robot.sdk.TencentSpeech.tencentSpeech.textToSpeech\">\n<code class=\"descname\">textToSpeech</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/sdk/TencentSpeech.html#tencentSpeech.textToSpeech\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.sdk.TencentSpeech.tencentSpeech.textToSpeech\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"attribute\">\n<dt id=\"robot.sdk.TencentSpeech.tencentSpeech.url\">\n<code class=\"descname\">url</code><a class=\"headerlink\" href=\"#robot.sdk.TencentSpeech.tencentSpeech.url\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"attribute\">\n<dt id=\"robot.sdk.TencentSpeech.tencentSpeech.voiceformat\">\n<code class=\"descname\">voiceformat</code><a class=\"headerlink\" href=\"#robot.sdk.TencentSpeech.tencentSpeech.voiceformat\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"attribute\">\n<dt id=\"robot.sdk.TencentSpeech.tencentSpeech.voicetype\">\n<code class=\"descname\">voicetype</code><a class=\"headerlink\" href=\"#robot.sdk.TencentSpeech.tencentSpeech.voicetype\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n</dd></dl>\n\n</div>\n<div class=\"section\" id=\"module-robot.sdk.XunfeiSpeech\">\n<span id=\"robot-sdk-xunfeispeech-module\"></span><h2>robot.sdk.XunfeiSpeech module<a class=\"headerlink\" href=\"#module-robot.sdk.XunfeiSpeech\" title=\"永久链接至标题\">¶</a></h2>\n<dl class=\"class\">\n<dt id=\"robot.sdk.XunfeiSpeech.Ws_Param\">\n<em class=\"property\">class </em><code class=\"descclassname\">robot.sdk.XunfeiSpeech.</code><code class=\"descname\">Ws_Param</code><span class=\"sig-paren\">(</span><em>APPID</em>, <em>APIKey</em>, <em>APISecret</em>, <em>AudioFile</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/sdk/XunfeiSpeech.html#Ws_Param\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.sdk.XunfeiSpeech.Ws_Param\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>基类：<code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">object</span></code></p>\n<dl class=\"method\">\n<dt id=\"robot.sdk.XunfeiSpeech.Ws_Param.create_url\">\n<code class=\"descname\">create_url</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/sdk/XunfeiSpeech.html#Ws_Param.create_url\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.sdk.XunfeiSpeech.Ws_Param.create_url\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n</dd></dl>\n\n<dl class=\"function\">\n<dt id=\"robot.sdk.XunfeiSpeech.on_close\">\n<code class=\"descclassname\">robot.sdk.XunfeiSpeech.</code><code class=\"descname\">on_close</code><span class=\"sig-paren\">(</span><em>ws</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/sdk/XunfeiSpeech.html#on_close\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.sdk.XunfeiSpeech.on_close\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"function\">\n<dt id=\"robot.sdk.XunfeiSpeech.on_error\">\n<code class=\"descclassname\">robot.sdk.XunfeiSpeech.</code><code class=\"descname\">on_error</code><span class=\"sig-paren\">(</span><em>ws</em>, <em>error</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/sdk/XunfeiSpeech.html#on_error\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.sdk.XunfeiSpeech.on_error\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"function\">\n<dt id=\"robot.sdk.XunfeiSpeech.on_message\">\n<code class=\"descclassname\">robot.sdk.XunfeiSpeech.</code><code class=\"descname\">on_message</code><span class=\"sig-paren\">(</span><em>ws</em>, <em>message</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/sdk/XunfeiSpeech.html#on_message\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.sdk.XunfeiSpeech.on_message\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"function\">\n<dt id=\"robot.sdk.XunfeiSpeech.on_open\">\n<code class=\"descclassname\">robot.sdk.XunfeiSpeech.</code><code class=\"descname\">on_open</code><span class=\"sig-paren\">(</span><em>ws</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/sdk/XunfeiSpeech.html#on_open\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.sdk.XunfeiSpeech.on_open\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"function\">\n<dt id=\"robot.sdk.XunfeiSpeech.transcribe\">\n<code class=\"descclassname\">robot.sdk.XunfeiSpeech.</code><code class=\"descname\">transcribe</code><span class=\"sig-paren\">(</span><em>fpath</em>, <em>appid</em>, <em>api_key</em>, <em>api_secret</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/sdk/XunfeiSpeech.html#transcribe\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.sdk.XunfeiSpeech.transcribe\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>科大讯飞ASR</p>\n</dd></dl>\n\n</div>\n<div class=\"section\" id=\"module-robot.sdk.unit\">\n<span id=\"robot-sdk-unit-module\"></span><h2>robot.sdk.unit module<a class=\"headerlink\" href=\"#module-robot.sdk.unit\" title=\"永久链接至标题\">¶</a></h2>\n<dl class=\"function\">\n<dt id=\"robot.sdk.unit.getIntent\">\n<code class=\"descclassname\">robot.sdk.unit.</code><code class=\"descname\">getIntent</code><span class=\"sig-paren\">(</span><em>parsed</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/sdk/unit.html#getIntent\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.sdk.unit.getIntent\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>提取意图</p>\n<table class=\"docutils field-list\" frame=\"void\" rules=\"none\">\n<col class=\"field-name\" />\n<col class=\"field-body\" />\n<tbody valign=\"top\">\n<tr class=\"field-odd field\"><th class=\"field-name\">参数:</th><td class=\"field-body\"><strong>parsed</strong> – UNIT 解析结果</td>\n</tr>\n<tr class=\"field-even field\"><th class=\"field-name\">返回:</th><td class=\"field-body\">意图数组</td>\n</tr>\n</tbody>\n</table>\n</dd></dl>\n\n<dl class=\"function\">\n<dt id=\"robot.sdk.unit.getSay\">\n<code class=\"descclassname\">robot.sdk.unit.</code><code class=\"descname\">getSay</code><span class=\"sig-paren\">(</span><em>parsed</em>, <em>intent=''</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/sdk/unit.html#getSay\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.sdk.unit.getSay\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>提取 UNIT 的回复文本</p>\n<table class=\"docutils field-list\" frame=\"void\" rules=\"none\">\n<col class=\"field-name\" />\n<col class=\"field-body\" />\n<tbody valign=\"top\">\n<tr class=\"field-odd field\"><th class=\"field-name\">参数:</th><td class=\"field-body\"><ul class=\"first simple\">\n<li><strong>parsed</strong> – UNIT 解析结果</li>\n<li><strong>intent</strong> – 意图的名称</li>\n</ul>\n</td>\n</tr>\n<tr class=\"field-even field\"><th class=\"field-name\">返回:</th><td class=\"field-body\"><p class=\"first last\">UNIT 的回复文本</p>\n</td>\n</tr>\n</tbody>\n</table>\n</dd></dl>\n\n<dl class=\"function\">\n<dt id=\"robot.sdk.unit.getSlotWords\">\n<code class=\"descclassname\">robot.sdk.unit.</code><code class=\"descname\">getSlotWords</code><span class=\"sig-paren\">(</span><em>parsed</em>, <em>intent</em>, <em>name</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/sdk/unit.html#getSlotWords\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.sdk.unit.getSlotWords\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>找出命中某个词槽的内容</p>\n<table class=\"docutils field-list\" frame=\"void\" rules=\"none\">\n<col class=\"field-name\" />\n<col class=\"field-body\" />\n<tbody valign=\"top\">\n<tr class=\"field-odd field\"><th class=\"field-name\">参数:</th><td class=\"field-body\"><ul class=\"first simple\">\n<li><strong>parsed</strong> – UNIT 解析结果</li>\n<li><strong>intent</strong> – 意图的名称</li>\n<li><strong>name</strong> – 词槽名</li>\n</ul>\n</td>\n</tr>\n<tr class=\"field-even field\"><th class=\"field-name\">返回:</th><td class=\"field-body\"><p class=\"first last\">命中该词槽的值的列表。</p>\n</td>\n</tr>\n</tbody>\n</table>\n</dd></dl>\n\n<dl class=\"function\">\n<dt id=\"robot.sdk.unit.getSlots\">\n<code class=\"descclassname\">robot.sdk.unit.</code><code class=\"descname\">getSlots</code><span class=\"sig-paren\">(</span><em>parsed</em>, <em>intent=''</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/sdk/unit.html#getSlots\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.sdk.unit.getSlots\" title=\"永久链接至目标\">¶</a></dt>\n<dd><blockquote>\n<div><p>提取某个意图的所有词槽</p>\n<table class=\"docutils field-list\" frame=\"void\" rules=\"none\">\n<col class=\"field-name\" />\n<col class=\"field-body\" />\n<tbody valign=\"top\">\n<tr class=\"field-odd field\"><th class=\"field-name\">param parsed:</th><td class=\"field-body\">UNIT 解析结果</td>\n</tr>\n<tr class=\"field-even field\"><th class=\"field-name\">param intent:</th><td class=\"field-body\">意图的名称</td>\n</tr>\n<tr class=\"field-odd field\"><th class=\"field-name\">returns:</th><td class=\"field-body\">词槽列表。你可以通过 name 属性筛选词槽，</td>\n</tr>\n</tbody>\n</table>\n</div></blockquote>\n<p>再通过 normalized_word 属性取出相应的值</p>\n</dd></dl>\n\n<dl class=\"function\">\n<dt id=\"robot.sdk.unit.getUnit\">\n<code class=\"descclassname\">robot.sdk.unit.</code><code class=\"descname\">getUnit</code><span class=\"sig-paren\">(</span><em>query</em>, <em>service_id</em>, <em>api_key</em>, <em>secret_key</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/sdk/unit.html#getUnit\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.sdk.unit.getUnit\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>NLU 解析</p>\n<table class=\"docutils field-list\" frame=\"void\" rules=\"none\">\n<col class=\"field-name\" />\n<col class=\"field-body\" />\n<tbody valign=\"top\">\n<tr class=\"field-odd field\"><th class=\"field-name\">参数:</th><td class=\"field-body\"><ul class=\"first simple\">\n<li><strong>query</strong> – 用户的指令字符串</li>\n<li><strong>service_id</strong> – UNIT 的 service_id</li>\n<li><strong>api_key</strong> – UNIT apk_key</li>\n<li><strong>secret_key</strong> – UNIT secret_key</li>\n</ul>\n</td>\n</tr>\n<tr class=\"field-even field\"><th class=\"field-name\">返回:</th><td class=\"field-body\"><p class=\"first last\">UNIT 解析结果。如果解析失败，返回 None</p>\n</td>\n</tr>\n</tbody>\n</table>\n</dd></dl>\n\n<dl class=\"function\">\n<dt id=\"robot.sdk.unit.get_token\">\n<code class=\"descclassname\">robot.sdk.unit.</code><code class=\"descname\">get_token</code><span class=\"sig-paren\">(</span><em>api_key</em>, <em>secret_key</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/sdk/unit.html#get_token\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.sdk.unit.get_token\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"function\">\n<dt id=\"robot.sdk.unit.hasIntent\">\n<code class=\"descclassname\">robot.sdk.unit.</code><code class=\"descname\">hasIntent</code><span class=\"sig-paren\">(</span><em>parsed</em>, <em>intent</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/robot/sdk/unit.html#hasIntent\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#robot.sdk.unit.hasIntent\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>判断是否包含某个意图</p>\n<table class=\"docutils field-list\" frame=\"void\" rules=\"none\">\n<col class=\"field-name\" />\n<col class=\"field-body\" />\n<tbody valign=\"top\">\n<tr class=\"field-odd field\"><th class=\"field-name\">参数:</th><td class=\"field-body\"><ul class=\"first simple\">\n<li><strong>parsed</strong> – UNIT 解析结果</li>\n<li><strong>intent</strong> – 意图的名称</li>\n</ul>\n</td>\n</tr>\n<tr class=\"field-even field\"><th class=\"field-name\">返回:</th><td class=\"field-body\"><p class=\"first last\">True: 包含; False: 不包含</p>\n</td>\n</tr>\n</tbody>\n</table>\n</dd></dl>\n\n</div>\n<div class=\"section\" id=\"module-robot.sdk\">\n<span id=\"module-contents\"></span><h2>Module contents<a class=\"headerlink\" href=\"#module-robot.sdk\" title=\"永久链接至标题\">¶</a></h2>\n</div>\n</div>\n\n\n           </div>\n           \n          </div>\n          <footer>\n  \n\n  <hr/>\n\n  <div role=\"contentinfo\">\n    <p>\n        &copy; Copyright 2019, wzpan\n\n    </p>\n  </div>\n  Built with <a href=\"http://sphinx-doc.org/\">Sphinx</a> using a <a href=\"https://github.com/rtfd/sphinx_rtd_theme\">theme</a> provided by <a href=\"https://readthedocs.org\">Read the Docs</a>. \n\n</footer>\n\n        </div>\n      </div>\n\n    </section>\n\n  </div>\n  \n\n\n  <script type=\"text/javascript\">\n      jQuery(function () {\n          SphinxRtdTheme.Navigation.enable(true);\n      });\n  </script>\n\n  \n  \n    \n   \n\n</body>\n</html>"
  },
  {
    "path": "docs/search.html",
    "content": "\n\n<!DOCTYPE html>\n<!--[if IE 8]><html class=\"no-js lt-ie9\" lang=\"zh-CN\" > <![endif]-->\n<!--[if gt IE 8]><!--> <html class=\"no-js\" lang=\"zh-CN\" > <!--<![endif]-->\n<head>\n  <meta charset=\"utf-8\">\n  \n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  \n  <title>搜索 &mdash; wukong-robot 1.2.0 文档</title>\n  \n\n  \n  \n  \n  \n\n  \n  <script type=\"text/javascript\" src=\"_static/js/modernizr.min.js\"></script>\n  \n    \n      <script type=\"text/javascript\" id=\"documentation_options\" data-url_root=\"./\" src=\"_static/documentation_options.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/jquery.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/underscore.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/doctools.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/language_data.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/translations.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/searchtools.js\"></script>\n    \n    <script type=\"text/javascript\" src=\"_static/js/theme.js\"></script>\n\n    \n\n  \n  <link rel=\"stylesheet\" href=\"_static/css/theme.css\" type=\"text/css\" />\n  <link rel=\"stylesheet\" href=\"_static/pygments.css\" type=\"text/css\" />\n    <link rel=\"index\" title=\"索引\" href=\"genindex.html\" />\n    <link rel=\"search\" title=\"搜索\" href=\"#\" /> \n</head>\n\n<body class=\"wy-body-for-nav\">\n\n   \n  <div class=\"wy-grid-for-nav\">\n    \n    <nav data-toggle=\"wy-nav-shift\" class=\"wy-nav-side\">\n      <div class=\"wy-side-scroll\">\n        <div class=\"wy-side-nav-search\" >\n          \n\n          \n            <a href=\"index.html\" class=\"icon icon-home\"> wukong-robot\n          \n\n          \n          </a>\n\n          \n            \n            \n          \n\n          \n<div role=\"search\">\n  <form id=\"rtd-search-form\" class=\"wy-form\" action=\"#\" method=\"get\">\n    <input type=\"text\" name=\"q\" placeholder=\"Search docs\" />\n    <input type=\"hidden\" name=\"check_keywords\" value=\"yes\" />\n    <input type=\"hidden\" name=\"area\" value=\"default\" />\n  </form>\n</div>\n\n          \n        </div>\n\n        <div class=\"wy-menu wy-menu-vertical\" data-spy=\"affix\" role=\"navigation\" aria-label=\"main navigation\">\n          \n            \n            \n              \n            \n            \n              <!-- Local TOC -->\n              <div class=\"local-toc\"></div>\n            \n          \n        </div>\n      </div>\n    </nav>\n\n    <section data-toggle=\"wy-nav-shift\" class=\"wy-nav-content-wrap\">\n\n      \n      <nav class=\"wy-nav-top\" aria-label=\"top navigation\">\n        \n          <i data-toggle=\"wy-nav-top\" class=\"fa fa-bars\"></i>\n          <a href=\"index.html\">wukong-robot</a>\n        \n      </nav>\n\n\n      <div class=\"wy-nav-content\">\n        \n        <div class=\"rst-content\">\n        \n          \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<div role=\"navigation\" aria-label=\"breadcrumbs navigation\">\n\n  <ul class=\"wy-breadcrumbs\">\n    \n      <li><a href=\"index.html\">Docs</a> &raquo;</li>\n        \n      <li>搜索</li>\n    \n    \n      <li class=\"wy-breadcrumbs-aside\">\n        \n            \n        \n      </li>\n    \n  </ul>\n\n  \n  <hr/>\n</div>\n          <div role=\"main\" class=\"document\" itemscope=\"itemscope\" itemtype=\"http://schema.org/Article\">\n           <div itemprop=\"articleBody\">\n            \n  <noscript>\n  <div id=\"fallback\" class=\"admonition warning\">\n    <p class=\"last\">\n      Please activate JavaScript to enable the search\n      functionality.\n    </p>\n  </div>\n  </noscript>\n\n  \n  <div id=\"search-results\">\n  \n  </div>\n\n           </div>\n           \n          </div>\n          <footer>\n  \n\n  <hr/>\n\n  <div role=\"contentinfo\">\n    <p>\n        &copy; Copyright 2019, wzpan\n\n    </p>\n  </div>\n  Built with <a href=\"http://sphinx-doc.org/\">Sphinx</a> using a <a href=\"https://github.com/rtfd/sphinx_rtd_theme\">theme</a> provided by <a href=\"https://readthedocs.org\">Read the Docs</a>. \n\n</footer>\n\n        </div>\n      </div>\n\n    </section>\n\n  </div>\n  \n\n\n  <script type=\"text/javascript\">\n      jQuery(function () {\n          SphinxRtdTheme.Navigation.enable(true);\n      });\n  </script>\n\n  \n  \n    \n  \n  <script type=\"text/javascript\">\n    jQuery(function() { Search.loadIndex(\"searchindex.js\"); });\n  </script>\n  \n  <script type=\"text/javascript\" id=\"searchindexloader\"></script>\n   \n\n\n</body>\n</html>"
  },
  {
    "path": "docs/searchindex.js",
    "content": "Search.setIndex({docnames:[\"index\",\"modules\",\"plugins\",\"robot\",\"robot.drivers\",\"robot.sdk\",\"snowboy\",\"wukong\"],envversion:{\"sphinx.domains.c\":1,\"sphinx.domains.changeset\":1,\"sphinx.domains.cpp\":1,\"sphinx.domains.javascript\":1,\"sphinx.domains.math\":2,\"sphinx.domains.python\":1,\"sphinx.domains.rst\":1,\"sphinx.domains.std\":1,\"sphinx.ext.viewcode\":1,sphinx:55},filenames:[\"index.rst\",\"modules.rst\",\"plugins.rst\",\"robot.rst\",\"robot.drivers.rst\",\"robot.sdk.rst\",\"snowboy.rst\",\"wukong.rst\"],objects:{\"\":{plugins:[2,0,0,\"-\"],robot:[3,0,0,\"-\"],snowboy:[6,0,0,\"-\"],wukong:[7,0,0,\"-\"]},\"plugins.Camera\":{Plugin:[2,1,1,\"\"]},\"plugins.Camera.Plugin\":{SLUG:[2,2,1,\"\"],handle:[2,3,1,\"\"],isValid:[2,3,1,\"\"]},\"plugins.CleanCache\":{Plugin:[2,1,1,\"\"]},\"plugins.CleanCache.Plugin\":{SLUG:[2,2,1,\"\"],handle:[2,3,1,\"\"],isValid:[2,3,1,\"\"]},\"plugins.Echo\":{Plugin:[2,1,1,\"\"]},\"plugins.Echo.Plugin\":{handle:[2,3,1,\"\"],isValid:[2,3,1,\"\"]},\"plugins.Email\":{Plugin:[2,1,1,\"\"]},\"plugins.Email.Plugin\":{SLUG:[2,2,1,\"\"],fetchUnreadEmails:[2,3,1,\"\"],getDate:[2,3,1,\"\"],getMostRecentDate:[2,3,1,\"\"],getSender:[2,3,1,\"\"],getSubject:[2,3,1,\"\"],handle:[2,3,1,\"\"],isNewEmail:[2,3,1,\"\"],isSelfEmail:[2,3,1,\"\"],isValid:[2,3,1,\"\"]},\"plugins.Geek\":{Plugin:[2,1,1,\"\"]},\"plugins.Geek.Plugin\":{IS_IMMERSIVE:[2,2,1,\"\"],handle:[2,3,1,\"\"],isValid:[2,3,1,\"\"],isValidImmersive:[2,3,1,\"\"],onAsk:[2,3,1,\"\"],restore:[2,3,1,\"\"]},\"plugins.LocalPlayer\":{Plugin:[2,1,1,\"\"]},\"plugins.LocalPlayer.Plugin\":{IS_IMMERSIVE:[2,2,1,\"\"],get_song_list:[2,3,1,\"\"],handle:[2,3,1,\"\"],init_music_player:[2,3,1,\"\"],isValid:[2,3,1,\"\"],isValidImmersive:[2,3,1,\"\"],pause:[2,3,1,\"\"],restore:[2,3,1,\"\"]},\"plugins.Poem\":{Plugin:[2,1,1,\"\"]},\"plugins.Poem.Plugin\":{SLUG:[2,2,1,\"\"],handle:[2,3,1,\"\"],isValid:[2,3,1,\"\"]},\"robot.AI\":{AbstractRobot:[3,1,1,\"\"],Emotibot:[3,1,1,\"\"],TulingRobot:[3,1,1,\"\"],get_robot_by_slug:[3,5,1,\"\"],get_robots:[3,5,1,\"\"]},\"robot.AI.AbstractRobot\":{chat:[3,3,1,\"\"],get_instance:[3,4,1,\"\"]},\"robot.AI.Emotibot\":{SLUG:[3,2,1,\"\"],chat:[3,3,1,\"\"],get_config:[3,4,1,\"\"]},\"robot.AI.TulingRobot\":{SLUG:[3,2,1,\"\"],chat:[3,3,1,\"\"],get_config:[3,4,1,\"\"]},\"robot.ASR\":{AbstractASR:[3,1,1,\"\"],AliASR:[3,1,1,\"\"],BaiduASR:[3,1,1,\"\"],TencentASR:[3,1,1,\"\"],XunfeiASR:[3,1,1,\"\"],get_engine_by_slug:[3,5,1,\"\"],get_engines:[3,5,1,\"\"]},\"robot.ASR.AbstractASR\":{get_config:[3,4,1,\"\"],get_instance:[3,4,1,\"\"],transcribe:[3,3,1,\"\"]},\"robot.ASR.AliASR\":{SLUG:[3,2,1,\"\"],get_config:[3,4,1,\"\"],transcribe:[3,3,1,\"\"]},\"robot.ASR.BaiduASR\":{SLUG:[3,2,1,\"\"],get_config:[3,4,1,\"\"],transcribe:[3,3,1,\"\"]},\"robot.ASR.TencentASR\":{SLUG:[3,2,1,\"\"],get_config:[3,4,1,\"\"],transcribe:[3,3,1,\"\"]},\"robot.ASR.XunfeiASR\":{SLUG:[3,2,1,\"\"],get_config:[3,4,1,\"\"],transcribe:[3,3,1,\"\"]},\"robot.Brain\":{Brain:[3,1,1,\"\"]},\"robot.Brain.Brain\":{isImmersive:[3,3,1,\"\"],pause:[3,3,1,\"\"],printPlugins:[3,3,1,\"\"],query:[3,3,1,\"\"],restore:[3,3,1,\"\"],say:[3,3,1,\"\"],understand:[3,3,1,\"\"]},\"robot.ConfigMonitor\":{ConfigMonitor:[3,1,1,\"\"]},\"robot.ConfigMonitor.ConfigMonitor\":{on_modified:[3,3,1,\"\"]},\"robot.Conversation\":{Conversation:[3,1,1,\"\"]},\"robot.Conversation.Conversation\":{activeListen:[3,3,1,\"\"],appendHistory:[3,3,1,\"\"],checkRestore:[3,3,1,\"\"],converse:[3,3,1,\"\"],doConverse:[3,3,1,\"\"],doParse:[3,3,1,\"\"],doResponse:[3,3,1,\"\"],getHistory:[3,3,1,\"\"],getImmersiveMode:[3,3,1,\"\"],interrupt:[3,3,1,\"\"],pardon:[3,3,1,\"\"],play:[3,3,1,\"\"],reload:[3,3,1,\"\"],say:[3,3,1,\"\"],setImmersiveMode:[3,3,1,\"\"]},\"robot.NLU\":{AbstractNLU:[3,1,1,\"\"],UnitNLU:[3,1,1,\"\"],get_engine_by_slug:[3,5,1,\"\"],get_engines:[3,5,1,\"\"]},\"robot.NLU.AbstractNLU\":{getIntent:[3,3,1,\"\"],getSay:[3,3,1,\"\"],getSlotWords:[3,3,1,\"\"],getSlots:[3,3,1,\"\"],get_config:[3,4,1,\"\"],get_instance:[3,4,1,\"\"],hasIntent:[3,3,1,\"\"],parse:[3,3,1,\"\"]},\"robot.NLU.UnitNLU\":{SLUG:[3,2,1,\"\"],getIntent:[3,3,1,\"\"],getSay:[3,3,1,\"\"],getSlotWords:[3,3,1,\"\"],getSlots:[3,3,1,\"\"],get_config:[3,4,1,\"\"],hasIntent:[3,3,1,\"\"],parse:[3,3,1,\"\"]},\"robot.Player\":{AbstractPlayer:[3,1,1,\"\"],MusicPlayer:[3,1,1,\"\"],SoxPlayer:[3,1,1,\"\"],getPlayerByFileName:[3,5,1,\"\"],no_alsa_error:[3,5,1,\"\"],play:[3,5,1,\"\"],py_error_handler:[3,5,1,\"\"]},\"robot.Player.AbstractPlayer\":{is_playing:[3,3,1,\"\"],play:[3,3,1,\"\"],play_block:[3,3,1,\"\"],stop:[3,3,1,\"\"]},\"robot.Player.MusicPlayer\":{SLUG:[3,2,1,\"\"],is_pausing:[3,3,1,\"\"],is_playing:[3,3,1,\"\"],next:[3,3,1,\"\"],pause:[3,3,1,\"\"],play:[3,3,1,\"\"],prev:[3,3,1,\"\"],resume:[3,3,1,\"\"],stop:[3,3,1,\"\"],turnDown:[3,3,1,\"\"],turnUp:[3,3,1,\"\"],update_playlist:[3,3,1,\"\"]},\"robot.Player.SoxPlayer\":{SLUG:[3,2,1,\"\"],appendOnCompleted:[3,3,1,\"\"],doPlay:[3,3,1,\"\"],is_playing:[3,3,1,\"\"],play:[3,3,1,\"\"],play_block:[3,3,1,\"\"],stop:[3,3,1,\"\"]},\"robot.TTS\":{AbstractTTS:[3,1,1,\"\"],AliTTS:[3,1,1,\"\"],BaiduTTS:[3,1,1,\"\"],TencentTTS:[3,1,1,\"\"],XunfeiTTS:[3,1,1,\"\"],get_engine_by_slug:[3,5,1,\"\"],get_engines:[3,5,1,\"\"]},\"robot.TTS.AbstractTTS\":{get_config:[3,4,1,\"\"],get_instance:[3,4,1,\"\"],get_speech:[3,3,1,\"\"]},\"robot.TTS.AliTTS\":{SLUG:[3,2,1,\"\"],get_config:[3,4,1,\"\"],get_speech:[3,3,1,\"\"]},\"robot.TTS.BaiduTTS\":{SLUG:[3,2,1,\"\"],get_config:[3,4,1,\"\"],get_speech:[3,3,1,\"\"]},\"robot.TTS.TencentTTS\":{SLUG:[3,2,1,\"\"],get_config:[3,4,1,\"\"],get_speech:[3,3,1,\"\"]},\"robot.TTS.XunfeiTTS\":{SLUG:[3,2,1,\"\"],getBody:[3,3,1,\"\"],getHeader:[3,3,1,\"\"],get_config:[3,4,1,\"\"],get_speech:[3,3,1,\"\"]},\"robot.Updater\":{Updater:[3,1,1,\"\"],fetch:[3,5,1,\"\"]},\"robot.Updater.Updater\":{fetch:[3,3,1,\"\"],update:[3,3,1,\"\"]},\"robot.config\":{doInit:[3,5,1,\"\"],dump:[3,5,1,\"\"],get:[3,5,1,\"\"],getConfig:[3,5,1,\"\"],getText:[3,5,1,\"\"],get_path:[3,5,1,\"\"],has:[3,5,1,\"\"],has_path:[3,5,1,\"\"],init:[3,5,1,\"\"],reload:[3,5,1,\"\"]},\"robot.constants\":{getConfigData:[3,5,1,\"\"],getConfigPath:[3,5,1,\"\"],getData:[3,5,1,\"\"],getDefaultConfigPath:[3,5,1,\"\"],getHotwordModel:[3,5,1,\"\"],newConfig:[3,5,1,\"\"]},\"robot.logging\":{getLogger:[3,5,1,\"\"],readLog:[3,5,1,\"\"],tail:[3,5,1,\"\"]},\"robot.plugin_loader\":{get_plugins:[3,5,1,\"\"],init_plugins:[3,5,1,\"\"]},\"robot.sdk\":{AbstractPlugin:[5,0,0,\"-\"],AliSpeech:[5,0,0,\"-\"],RASRsdk:[5,0,0,\"-\"],TencentSpeech:[5,0,0,\"-\"],XunfeiSpeech:[5,0,0,\"-\"],unit:[5,0,0,\"-\"]},\"robot.sdk.AbstractPlugin\":{AbstractPlugin:[5,1,1,\"\"]},\"robot.sdk.AbstractPlugin.AbstractPlugin\":{IS_IMMERSIVE:[5,2,1,\"\"],SLUG:[5,2,1,\"\"],activeListen:[5,3,1,\"\"],clearImmersive:[5,3,1,\"\"],handle:[5,3,1,\"\"],isValid:[5,3,1,\"\"],isValidImmersive:[5,3,1,\"\"],pause:[5,3,1,\"\"],play:[5,3,1,\"\"],restore:[5,3,1,\"\"],say:[5,3,1,\"\"]},\"robot.sdk.AliSpeech\":{asr:[5,5,1,\"\"],process:[5,5,1,\"\"],processGETRequest:[5,5,1,\"\"],processPOSTRequest:[5,5,1,\"\"],tts:[5,5,1,\"\"]},\"robot.sdk.RASRsdk\":{formatSignString:[5,5,1,\"\"],randstr:[5,5,1,\"\"],sendVoice:[5,5,1,\"\"],sign:[5,5,1,\"\"]},\"robot.sdk.TencentSpeech\":{tencentSpeech:[5,1,1,\"\"]},\"robot.sdk.TencentSpeech.tencentSpeech\":{ASR:[5,3,1,\"\"],PrimaryLanguage:[5,2,1,\"\"],Region:[5,2,1,\"\"],SECRET_ID:[5,2,1,\"\"],SECRET_KEY:[5,2,1,\"\"],SourceType:[5,2,1,\"\"],TTS:[5,3,1,\"\"],Text:[5,2,1,\"\"],URL:[5,2,1,\"\"],VoiceFormat:[5,2,1,\"\"],VoiceType:[5,2,1,\"\"],encode_sign:[5,3,1,\"\"],formatSignString:[5,3,1,\"\"],oneSentenceRecognition:[5,3,1,\"\"],primarylanguage:[5,2,1,\"\"],region:[5,2,1,\"\"],secret_id:[5,2,1,\"\"],secret_key:[5,2,1,\"\"],source_type:[5,2,1,\"\"],text:[5,2,1,\"\"],textToSpeech:[5,3,1,\"\"],url:[5,2,1,\"\"],voiceformat:[5,2,1,\"\"],voicetype:[5,2,1,\"\"]},\"robot.sdk.XunfeiSpeech\":{Ws_Param:[5,1,1,\"\"],on_close:[5,5,1,\"\"],on_error:[5,5,1,\"\"],on_message:[5,5,1,\"\"],on_open:[5,5,1,\"\"],transcribe:[5,5,1,\"\"]},\"robot.sdk.XunfeiSpeech.Ws_Param\":{create_url:[5,3,1,\"\"]},\"robot.sdk.unit\":{getIntent:[5,5,1,\"\"],getSay:[5,5,1,\"\"],getSlotWords:[5,5,1,\"\"],getSlots:[5,5,1,\"\"],getUnit:[5,5,1,\"\"],get_token:[5,5,1,\"\"],hasIntent:[5,5,1,\"\"]},\"robot.statistic\":{ReportThread:[3,1,1,\"\"],getUUID:[3,5,1,\"\"],report:[3,5,1,\"\"]},\"robot.statistic.ReportThread\":{run:[3,3,1,\"\"]},\"robot.utils\":{check_and_delete:[3,5,1,\"\"],clean:[3,5,1,\"\"],convert_mp3_to_wav:[3,5,1,\"\"],convert_wav_to_mp3:[3,5,1,\"\"],emailUser:[3,5,1,\"\"],getCache:[3,5,1,\"\"],getTimezone:[3,5,1,\"\"],get_do_not_bother_off_hotword:[3,5,1,\"\"],get_do_not_bother_on_hotword:[3,5,1,\"\"],get_file_content:[3,5,1,\"\"],get_pcm_from_wav:[3,5,1,\"\"],is_proper_time:[3,5,1,\"\"],lruCache:[3,5,1,\"\"],saveCache:[3,5,1,\"\"],sendEmail:[3,5,1,\"\"],write_temp_file:[3,5,1,\"\"]},\"snowboy.snowboydecoder\":{ActiveListener:[6,1,1,\"\"],HotwordDetector:[6,1,1,\"\"],RingBuffer:[6,1,1,\"\"],no_alsa_error:[6,5,1,\"\"],play_audio_file:[6,5,1,\"\"],py_error_handler:[6,5,1,\"\"]},\"snowboy.snowboydecoder.ActiveListener\":{listen:[6,3,1,\"\"],saveMessage:[6,3,1,\"\"]},\"snowboy.snowboydecoder.HotwordDetector\":{saveMessage:[6,3,1,\"\"],start:[6,3,1,\"\"],terminate:[6,3,1,\"\"]},\"snowboy.snowboydecoder.RingBuffer\":{extend:[6,3,1,\"\"],get:[6,3,1,\"\"]},\"snowboy.snowboydetect\":{SnowboyDetect:[6,1,1,\"\"],SnowboyVad:[6,1,1,\"\"]},\"snowboy.snowboydetect.SnowboyDetect\":{ApplyFrontend:[6,3,1,\"\"],BitsPerSample:[6,3,1,\"\"],GetSensitivity:[6,3,1,\"\"],NumChannels:[6,3,1,\"\"],NumHotwords:[6,3,1,\"\"],Reset:[6,3,1,\"\"],RunDetection:[6,3,1,\"\"],SampleRate:[6,3,1,\"\"],SetAudioGain:[6,3,1,\"\"],SetHighSensitivity:[6,3,1,\"\"],SetSensitivity:[6,3,1,\"\"],UpdateModel:[6,3,1,\"\"]},\"snowboy.snowboydetect.SnowboyVad\":{ApplyFrontend:[6,3,1,\"\"],BitsPerSample:[6,3,1,\"\"],NumChannels:[6,3,1,\"\"],Reset:[6,3,1,\"\"],RunVad:[6,3,1,\"\"],SampleRate:[6,3,1,\"\"],SetAudioGain:[6,3,1,\"\"]},\"wukong.Wukong\":{dev:[7,3,1,\"\"],fetch:[7,3,1,\"\"],init:[7,3,1,\"\"],initDetector:[7,3,1,\"\"],md5:[7,3,1,\"\"],profiling:[7,3,1,\"\"],restart:[7,3,1,\"\"],run:[7,3,1,\"\"],update:[7,3,1,\"\"]},plugins:{Camera:[2,0,0,\"-\"],CleanCache:[2,0,0,\"-\"],Echo:[2,0,0,\"-\"],Email:[2,0,0,\"-\"],Geek:[2,0,0,\"-\"],LocalPlayer:[2,0,0,\"-\"],Poem:[2,0,0,\"-\"]},robot:{AI:[3,0,0,\"-\"],ASR:[3,0,0,\"-\"],Brain:[3,0,0,\"-\"],ConfigMonitor:[3,0,0,\"-\"],Conversation:[3,0,0,\"-\"],NLU:[3,0,0,\"-\"],Player:[3,0,0,\"-\"],TTS:[3,0,0,\"-\"],Updater:[3,0,0,\"-\"],config:[3,0,0,\"-\"],constants:[3,0,0,\"-\"],drivers:[4,0,0,\"-\"],logging:[3,0,0,\"-\"],plugin_loader:[3,0,0,\"-\"],sdk:[5,0,0,\"-\"],statistic:[3,0,0,\"-\"],utils:[3,0,0,\"-\"]},snowboy:{snowboydecoder:[6,0,0,\"-\"],snowboydetect:[6,0,0,\"-\"]},wukong:{Wukong:[7,1,1,\"\"]}},objnames:{\"0\":[\"py\",\"module\",\"Python \\u6a21\\u5757\"],\"1\":[\"py\",\"class\",\"Python \\u7c7b\"],\"2\":[\"py\",\"attribute\",\"Python \\u5c5e\\u6027\"],\"3\":[\"py\",\"method\",\"Python \\u65b9\\u6cd5\"],\"4\":[\"py\",\"classmethod\",\"Python \\u7c7b\\u65b9\\u6cd5\"],\"5\":[\"py\",\"function\",\"Python \\u51fd\\u6570\"]},objtypes:{\"0\":\"py:module\",\"1\":\"py:class\",\"2\":\"py:attribute\",\"3\":\"py:method\",\"4\":\"py:classmethod\",\"5\":\"py:function\"},terms:{\"03\":6,\"03d\":[],\"10\":3,\"100\":[3,6],\"1024\":[],\"11186623\":3,\"15\":6,\"150\":[],\"1536\":3,\"1537\":3,\"1637\":3,\"17365\":3,\"1737\":3,\"1837\":3,\"1936\":3,\"200\":3,\"2001\":[],\"2016\":[],\"2017\":[],\"224\":[],\"24\":3,\"282\":[],\"300\":[],\"31\":[],\"32\":[],\"400\":3,\"4096\":6,\"441\":3,\"51240\":3,\"585d4eccb50d306c401d7df138bb02e7\":3,\"67ce5275q2rgst\":3,\"8000000\":[],\"84435\":3,\"88\":3,\"9670645\":3,\"97\":3,\"9c\":3,\"9f\":3,\"break\":6,\"byte\":[],\"case\":[],\"class\":[2,3,5,6,7],\"default\":[3,6],\"do\":[],\"float\":6,\"for\":[3,6],\"function\":[3,6],\"if\":[2,3,6],\"import\":[],\"in\":[2,3,6],\"int\":[],\"long\":6,\"new\":2,\"public\":[],\"return\":[2,3,5,6],\"static\":3,\"switch\":[],\"true\":[2,3,5,6],\"while\":[],\"with\":[3,6],__init__:[],__name__:[],_handler:[],a1:3,a2c4g:3,a8:3,abc:[],about:[],abov:[],abstractasr:3,abstractnlu:3,abstractplay:3,abstractplugin:[1,2,3],abstractrobot:3,abstractsoundplay:[],abstracttt:3,accept:[],access:[],accumul:[],acquir:[],acquisit:[],act:[],activ:[3,6],activelisten:[3,5,6],actual:[],adapt:[],add:6,added:[],addhandl:[],adding:[],addit:[],addlevelnam:[],address:[],after:6,again:6,ai:1,aka:[],algorithm:6,ali:3,aliasr:3,alispeech:[1,3],alitt:3,aliyun:3,all:[2,3],allow:[],alreadi:[],also:6,alter:[],am:[],an:[2,3,6],and:[3,6],ani:[2,3],ap:3,apa102:[],apa102_pi:[],api:[3,5],api_kei:[3,5],api_secret:5,apikei:5,apisecret:5,apk_kei:[3,5],append:[],appendhistori:3,appendoncomplet:3,appid:[3,5],appkei:[3,5],appli:6,applic:[],apply_frontend:6,applyfrontend:6,appropri:[],arbitrari:[],are:[],area:[],arg:[3,6],argument:[2,3],around:[],arrai:[],as:[2,3],asctim:[],asr:[1,5],asr_api_kei:3,asr_api_secret:3,assign:[],associ:[],at:[],attach_list:3,attribut:[],audio:6,audio_gain:6,audio_recorder_callback:6,audiocont:5,audiofil:5,aue:3,avail:3,avoid:[],awai:[],b0:3,bad:[],baidu:3,baidu_yuyin:3,baiduasr:3,baidutt:3,base:[],basic:[],basic_format:[],basicconfig:[],bb:[],be:[2,3,6],becaus:[],been:6,befor:2,begin:6,behaviour:[],behind:[],being:6,below:[],benefit:[],best:2,bigger:6,bit:[],bitspersampl:6,blue:[],bodi:3,both:[],brain:1,brief:[],bright:[],bright_perc:[],buffer:6,bufferingformatt:[],bus:[],but:[],by:[2,3,6],cach:[3,5],call:[3,6],callabl:3,callback:[3,6],caller:[],callhandl:[],camera:1,can:6,captur:[],capturewarn:[],care:[],carri:[],cater:[],certain:[],chang:[],channel:[],chat:3,check:[2,6],check_and_delet:3,checkrestor:3,circular:[],classmethod:3,clean:3,cleancach:1,cleanup:[],clear:6,clear_strip:[],clearimmers:5,clever:[],clock:[],clock_end_fram:[],clock_start_fram:[],clockendfram:[],clockstartfram:[],close:[],closer:[],cloud:3,cn:3,code:[],color:[],colour:[],com:3,combin:[],combine_color:[],comment:[],common:6,commun:[],comp:[],comput:[],con:[2,3,5],concaten:[],condition:[],config:1,config_dict:5,config_fil:3,configmonitor:1,configstr:3,configur:[],connect:[],consol:[],constant:1,construct:[],constructor:3,contain:[],content:1,contextu:[],conveni:[],convers:1,convert:[],convert_mp3_to_wav:3,convert_wav_to_mp3:3,copi:[],copyright:[],correct:[],correspond:6,could:[],coupl:[],creat:[],create_url:5,createlock:[],creation:[],critic:[],csv:[],current:3,custom:[],cutlength:5,cycl:[],data:[3,6],date:2,datefmt:[],debug:[],decod:6,decoder_model:6,deem:[],def:[],default_msec_format:[],default_time_format:[],defin:[],delai:[],deleg:[],delet:[3,5],depend:[],depth:[],descend:[],describ:[],desir:2,destin:[],detect:6,detected_callback:6,detector:6,determin:[],dev:[3,7],dev_pid:3,develop:[],devic:[],dict:[],dictionari:[],ding:6,direct:[],directori:3,dirmodifiedev:3,disabl:[],disast:[],disk:[],dispatch:[],doconvers:3,document:[3,6],document_detail:3,doe:[],doing:[],doinit:3,done:[],dopars:3,doplai:3,dorespons:3,dotstar:[],down:[],driver:[],dummi:[],dump:3,dump_arrai:[],dure:[],e5:3,e8:3,each:[],easier:[],echo:1,effect:[],ei:[],either:[],els:[],email:[1,3],emailus:3,emiss:[],emit:[],emotibot:3,empti:6,enabl:[],encod:[],encode_sign:5,encount:[],end:6,engin:3,engine_model_typ:5,enginetyp:[],enough:[],ensur:[],entir:[],epoch:[],err:[3,6],error:5,erzberg:[],essenti:[],etc:[],even:[],event:3,everi:6,everyth:[],exactli:[],exampl:[],exc_info:[],except:[],exist:6,explain:[],express:[],extend:6,extens:[],extern:[],extra:[],fact:[],factor:6,factori:[],fals:[2,3,5,6],fatal:[],fed:[],fetch:[2,3,7],fetchunreademail:2,few:[],field:[],file:[3,6],filehandl:[],filemod:[],filemodifiedev:3,filenam:[3,6],filepath:[3,5],filesystemeventhandl:3,filter:[],find:[],findcal:[],finish:[],first:[],flush:[],fmt:[3,6],fn:[],fname:[3,6],follow:[],footer:[],format:5,formatexcept:[],formatfoot:[],formathead:[],formatmessag:[],formatsignstr:5,formatstack:[],formatt:[],formattim:[],forward:[],found:[],fp:3,fpath:5,frame:[],from:[2,3,6],frontend:6,full:[],fulli:[],func:[],funcnam:[],geek:1,gener:3,get:[3,6],get_config:3,get_do_not_bother_off_hotword:3,get_do_not_bother_on_hotword:3,get_engin:3,get_engine_by_slug:3,get_file_cont:3,get_inst:3,get_nam:[],get_path:3,get_pcm_from_wav:3,get_plugin:3,get_robot:3,get_robot_by_slug:3,get_song_list:2,get_speech:3,get_token:5,getbodi:3,getcach:3,getchild:[],getconfig:3,getconfigdata:3,getconfigpath:3,getdat:2,getdata:3,getdefaultconfigpath:3,geteffectivelevel:[],gethead:3,gethistori:3,gethotwordmodel:3,getimmersivemod:3,getint:[3,5],getlevelnam:[],getlogg:3,getloggerclass:[],getlogrecordfactori:[],getmessag:[],getmostrecentd:2,getplayerbyfilenam:3,getsai:[3,5],getsend:2,getsensit:6,getslot:[3,5],getslotword:[3,5],getsubject:2,gettext:3,gettimezon:3,getunit:5,getuuid:3,ghi:[],github:[],given:[],global:[],global_bright:[],glow:[],gmt:[],gmtime:[],gnu:[],gnumer:[],goe:[],green:[],guangzhou:3,guess:2,handl:[2,5],handleerror:[],handler:[],has:[3,6],has_path:3,hashandl:[],hasint:[3,5],have:[],hdlr:[],header:[],heard:6,help:3,helper:[],hierarchi:[],high_sensitivity_str:6,hold:6,home:[],hotworddetector:6,houston:[],how:6,howev:[],html:3,http:3,human:[],id:[],identifi:[],ignor:[],imagin:[],immedi:6,immers:[],immersivemod:[],implement:3,inbox:2,includ:[],incompat:[],indic:6,individu:[],info:[],inform:[],init:[3,7],init_music_play:2,init_plugin:3,initdetector:7,initi:[],input:[2,3,6],insert:[],instanc:[],instanti:[],instead:[],integ:[],intend:[],intent:[3,5],interact:[],interest:[],interfac:[],intern:[],interpret:[],interrupt:3,interrupt_check:6,into:[],invert:[],invok:3,ioerror:3,ip:3,is:[2,3,6],is_immers:[2,5],is_paus:3,is_plai:3,is_proper_tim:3,isenabledfor:[],isimmers:3,isnewemail:2,iso8601:[],isselfemail:2,issu:[],isvalid:[2,5],isvalidimmers:[2,5],it:6,item:[3,6],iter:[],its:[],itself:[],java:[],just:[],keep:[],kei:3,keyword:[3,6],klass:[],know:[],knowledg:[],kwarg:3,lambda:6,lan:3,lang:[],languag:3,last:[],least:[],led:[],led_num:[],led_start:[],length:6,level:[],levelnam:[],levelno:[],librari:[],like:[],limit:[2,6],line:[3,6],linefmt:[],lineno:[],list:[2,6],listen:6,liter:[],ll:[],lno:[],load:[],local:[],localplay:1,localtim:[],locat:3,lock:[],log:1,logger:3,loggeradapt:[],logrecord:[],look:[],lookup:[],loop:6,lot:[],lrucach:3,made:[],mai:3,main:6,major:[],make:[],makelogrecord:[],makerecord:[],manag:[],manipul:[],map:[],mark:[2,6],markread:2,martin:[],match:6,max_bright:[],max_speed_hz:[],maximum:6,md5:7,mean:[],mention:[],merg:[],messag:[5,6],method:3,mic:[],microphon:6,might:[],millisecond:[],mode:3,model:6,model_str:6,modif:3,modifi:3,modul:1,more:[3,6],most:2,mostli:[],mp3:3,mp3_path:3,msec:[],msg:[2,3],much:6,multipl:6,multipli:6,musicplay:3,must:6,my:[],mysteri:[],name:[3,5,6],namespac:[],natur:[],necessari:[],need:6,neg:[],nest:[],newconfig:3,newlin:[],next:3,nlu:[1,2,5],no:[2,3],no_alsa_error:[3,6],non:[],none:[2,3,5,6],nonzero:[],normal:[],normalized_word:[3,5],not:[],note:[],noth:[],notimplementederror:[],now:[],nullhandl:[],num_l:[],number:6,numchannel:6,numer:[],numhotword:6,numl:[],object:[2,3,5,6,7],occur:[],of:[2,3,6],off:[],omit:[],on:3,on_clos:5,on_error:5,on_messag:5,on_modifi:3,on_open:5,onask:2,oncomplet:[3,5],one:[],onesentencerecognit:5,onli:[],online_tt:3,onsai:3,onto:[],open:[],oper:[],operand:[],opposit:[],optim:[],option:[],or:[3,6],order:[],organ:[],origin:[],otherwis:[],out:[],output:[],over:[],overrid:3,overridden:[],overview:[],own:[],packag:1,panweizh:[3,6],param:[3,5],paramet:[],pardon:3,parent:3,pars:[2,3,5],part:[],partial:[],particular:[],pass:[3,6],password:[3,7],path:[2,6],pathnam:[],paus:[2,3,5],pcm:3,peopl:[],pep:[],per:3,perform:[],period:[],person:[],pertin:[],phrase:[3,6],pi:[],pixel:[],pixels_n:[],place:[],placehold:[],plai:[3,5,6],platform:3,play_audio_fil:6,play_block:3,player:1,playlist:3,plugin:[1,3],plugin_load:1,poem:1,point:[],portaudio:6,portion:[],posit:[],possibl:[],power:[],pre:[],predefin:[],prepar:[],preparatori:[],present:[],prev:3,primarylanguag:5,print_except:[],print_stack:[],printplugin:3,problem:[],process:[5,6],processgetrequest:5,processpostrequest:5,produc:[],profil:[3,7],project:[3,6],propag:[],protocol:[],provid:[2,6],purpos:[],py_error_handl:[3,6],python:[],qg4han8b2bgvftcbbgqhrmzi:3,queri:[2,3,5],rais:3,raiseexcept:[],randstr:5,rasrsdk:[1,3],rather:[],raw:[],reach:[],read:2,readi:[],readlog:3,real:[],realli:[],receiv:[],recent:2,record:6,recordeddata:6,recording_timeout:6,red:[],redirect:[],region:[3,5],rel:[],relat:[],relativecr:[],releas:[],relev:[],reload:3,rememb:[],remov:[],removehandl:[],replac:[],report:3,reportthread:3,repres:3,represent:[],request:5,requir:[],res:6,res_typ:5,reserv:[],reset:6,resourc:6,resource_filenam:6,respect:3,respond:[],respons:[],rest:[],restart:7,restor:[2,3,5],result:[],result_text_format:5,resum:3,retriev:6,rgb:[],rgb_color:[],right:[],ring:6,ringbuff:6,robot:[2,6],root:[],rootlogg:[],rotat:[],row:[],run:[3,7],rundetect:6,runvad:6,sai:[3,5],sajip:[],same:[],sampler:[5,6],save:6,savecach:3,savemessag:6,script:[],sdk:[1,2,3],search:[],second:6,secret:3,secret_id:5,secret_kei:[3,5],secretid:[3,5],see:[],seen:[],self:6,send:[],sendemail:3,sender:[2,3],sendvoic:5,sensit:6,sensitivity_str:6,senstiv:6,sent:2,separ:[],sequenti:3,serial:[],servic:3,service_id:[3,5],set:[],set_nam:[],set_pixel:[],set_pixel_rgb:[],setaudiogain:6,setformatt:[],sethighsensit:6,setimmersivemod:3,setlevel:[],setloggerclass:[],setlogrecordfactori:[],setsensit:6,sever:[],shift:[],shot:[],should:[],show:[],shown:[],side:[],sign:5,signatur:[],signific:[],signstr:5,silenc:6,silent:[3,5],silent_count_threshold:6,simpl:6,simpli:[],sinc:2,sinfo:[],singl:6,size:6,sleep_tim:6,slug:[2,3,5],smtp:3,smtp_port:3,smtp_server:3,snowboi:1,snowboydecod:1,snowboydetect:1,snowboyvad:6,so:[],socket:[],someth:[],sound:6,sourc:[],source_typ:5,sourcetyp:5,soxplay:3,speak:[],speaker:3,special:[],specif:[],specifi:6,speech:3,spi:[],spm:3,spoken:6,src:[3,5],stack:[],stack_info:[],standard:3,start:6,startup:[],statist:1,stderr:[],stdout:[],step:[],still:[],stop:[3,6],store:6,str:6,stream:6,streamhandl:[],strftime:[],string:6,strip:[],stripe:[],structur:[],stub:[],style:[],sub:[],subclass:3,subject:3,submodul:1,subpackag:1,such:[],suffix:3,suit:[],suitabl:[],superclass:[],suppli:[],support:3,sure:[],sync:[],sys:[],system:[],tail:3,take:[],taken:3,target:[2,3],tell:[],templat:[],template_nam:5,ten:[],tencent:[3,5],tencentasr:3,tencentspeech:[1,3],tencenttt:3,termin:6,text:[2,3,5],texttospeech:5,textual:[],than:[],that:6,the:[2,3,6],thei:[],their:[],then:6,there:[],therefor:[],thereto:[],thi:[2,3,6],think:[],thorni:[],those:[],thread:3,threadnam:[],through:[],thrown:[],tidi:[],time:6,timestamp:6,tinu:[],titl:2,tm_hour:[],tm_isdst:[],tm_mdai:[],tm_min:[],tm_mon:[],tm_sec:[],tm_wdai:[],tm_ydai:[],tm_year:[],to:[2,3,6],todo:[],togeth:[],toggl:[],token:[3,5],top:[],traceback:[],trail:[],transcrib:[3,5],treat:[],trigger:6,tts:[1,5],tts_api_kei:3,tule:3,tuling_kei:3,tulingrobot:3,tupl:[],turn:[],turndown:3,turnup:3,two:[],type:[],typic:3,ultim:[],underli:[],understand:3,uniqu:[],unit:[1,3],unitnlu:3,unpickl:[],unread:2,unspecifi:[],until:[],up:[],updat:[1,7],update_playlist:3,updatemodel:6,upper:[],url:5,use:[],used:6,useful:[],user:[2,3,6],uses:[],usestim:[],using:[],usual:[],util:1,uuid:3,vad:6,valu:6,valueerror:3,veri:[],version:[],vinai:[],voic:[3,5,6],voice_format:5,voice_nam:3,voiceformat:5,voicetyp:[3,5],volum:[3,5,6],wait:[3,5,6],wakeup:[],want:[],warn:[],was:6,watchdog:3,wav:[3,6],wav_path:3,wave:6,wave_fil:5,wavplay:[],we:[],weather:[],well:[],wether:2,what:[],whatev:[],wheel:[],wheel_po:[],when:3,whenev:[],where:6,wherea:[],whether:[2,6],which:6,whose:2,will:[2,6],wish:[],wrap:[],write:[],write_temp_fil:3,written:[],ws:5,ws_param:5,wukong:[3,6],www:3,xfer:[],xfyun:3,xiaoyan:3,xiaoyun:3,xls:[],xml:3,xunfei:3,xunfeiasr:3,xunfeispeech:[1,3],xunfeitt:3,xxx:[],yell:[],yes:[],yet:[],yield:[],yml:3,you:3,your:[],yuyin:3,zero:[],zh:3},titles:[\"Welcome to wukong-robot\\u2019s documentation!\",\"wukong-robot\",\"plugins package\",\"robot package\",\"robot.drivers package\",\"robot.sdk package\",\"snowboy package\",\"wukong module\"],titleterms:{abstractplugin:5,ai:3,alispeech:5,and:0,apa102:4,asr:3,brain:3,camera:2,cleancach:2,config:3,configmonitor:3,constant:3,content:[2,3,4,5,6],convers:3,document:0,driver:4,echo:2,email:2,geek:2,indic:0,localplay:2,log:3,modul:[2,3,4,5,6,7],nlu:3,packag:[2,3,4,5,6],pixel:4,player:3,plugin:2,plugin_load:3,poem:2,rasrsdk:5,robot:[0,1,3,4,5],sdk:5,snowboi:6,snowboydecod:6,snowboydetect:6,statist:3,submodul:[2,3,4,5,6],subpackag:3,tabl:0,tencentspeech:5,to:0,tts:3,unit:5,updat:3,util:3,welcom:0,wukong:[0,1,7],xunfeispeech:5}})"
  },
  {
    "path": "docs/snowboy.html",
    "content": "\n\n<!DOCTYPE html>\n<!--[if IE 8]><html class=\"no-js lt-ie9\" lang=\"zh-CN\" > <![endif]-->\n<!--[if gt IE 8]><!--> <html class=\"no-js\" lang=\"zh-CN\" > <!--<![endif]-->\n<head>\n  <meta charset=\"utf-8\">\n  \n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  \n  <title>snowboy package &mdash; wukong-robot 1.2.0 文档</title>\n  \n\n  \n  \n  \n  \n\n  \n  <script type=\"text/javascript\" src=\"_static/js/modernizr.min.js\"></script>\n  \n    \n      <script type=\"text/javascript\" id=\"documentation_options\" data-url_root=\"./\" src=\"_static/documentation_options.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/jquery.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/underscore.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/doctools.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/language_data.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/translations.js\"></script>\n    \n    <script type=\"text/javascript\" src=\"_static/js/theme.js\"></script>\n\n    \n\n  \n  <link rel=\"stylesheet\" href=\"_static/css/theme.css\" type=\"text/css\" />\n  <link rel=\"stylesheet\" href=\"_static/pygments.css\" type=\"text/css\" />\n    <link rel=\"index\" title=\"索引\" href=\"genindex.html\" />\n    <link rel=\"search\" title=\"搜索\" href=\"search.html\" /> \n</head>\n\n<body class=\"wy-body-for-nav\">\n\n   \n  <div class=\"wy-grid-for-nav\">\n    \n    <nav data-toggle=\"wy-nav-shift\" class=\"wy-nav-side\">\n      <div class=\"wy-side-scroll\">\n        <div class=\"wy-side-nav-search\" >\n          \n\n          \n            <a href=\"index.html\" class=\"icon icon-home\"> wukong-robot\n          \n\n          \n          </a>\n\n          \n            \n            \n          \n\n          \n<div role=\"search\">\n  <form id=\"rtd-search-form\" class=\"wy-form\" action=\"search.html\" method=\"get\">\n    <input type=\"text\" name=\"q\" placeholder=\"Search docs\" />\n    <input type=\"hidden\" name=\"check_keywords\" value=\"yes\" />\n    <input type=\"hidden\" name=\"area\" value=\"default\" />\n  </form>\n</div>\n\n          \n        </div>\n\n        <div class=\"wy-menu wy-menu-vertical\" data-spy=\"affix\" role=\"navigation\" aria-label=\"main navigation\">\n          \n            \n            \n              \n            \n            \n              <!-- Local TOC -->\n              <div class=\"local-toc\"><ul>\n<li><a class=\"reference internal\" href=\"#\">snowboy package</a><ul>\n<li><a class=\"reference internal\" href=\"#submodules\">Submodules</a></li>\n<li><a class=\"reference internal\" href=\"#module-snowboy.snowboydecoder\">snowboy.snowboydecoder module</a></li>\n<li><a class=\"reference internal\" href=\"#module-snowboy.snowboydetect\">snowboy.snowboydetect module</a></li>\n<li><a class=\"reference internal\" href=\"#module-snowboy\">Module contents</a></li>\n</ul>\n</li>\n</ul>\n</div>\n            \n          \n        </div>\n      </div>\n    </nav>\n\n    <section data-toggle=\"wy-nav-shift\" class=\"wy-nav-content-wrap\">\n\n      \n      <nav class=\"wy-nav-top\" aria-label=\"top navigation\">\n        \n          <i data-toggle=\"wy-nav-top\" class=\"fa fa-bars\"></i>\n          <a href=\"index.html\">wukong-robot</a>\n        \n      </nav>\n\n\n      <div class=\"wy-nav-content\">\n        \n        <div class=\"rst-content\">\n        \n          \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<div role=\"navigation\" aria-label=\"breadcrumbs navigation\">\n\n  <ul class=\"wy-breadcrumbs\">\n    \n      <li><a href=\"index.html\">Docs</a> &raquo;</li>\n        \n      <li>snowboy package</li>\n    \n    \n      <li class=\"wy-breadcrumbs-aside\">\n        \n            \n            <a href=\"_sources/snowboy.rst.txt\" rel=\"nofollow\"> View page source</a>\n          \n        \n      </li>\n    \n  </ul>\n\n  \n  <hr/>\n</div>\n          <div role=\"main\" class=\"document\" itemscope=\"itemscope\" itemtype=\"http://schema.org/Article\">\n           <div itemprop=\"articleBody\">\n            \n  <div class=\"section\" id=\"snowboy-package\">\n<h1>snowboy package<a class=\"headerlink\" href=\"#snowboy-package\" title=\"永久链接至标题\">¶</a></h1>\n<div class=\"section\" id=\"submodules\">\n<h2>Submodules<a class=\"headerlink\" href=\"#submodules\" title=\"永久链接至标题\">¶</a></h2>\n</div>\n<div class=\"section\" id=\"module-snowboy.snowboydecoder\">\n<span id=\"snowboy-snowboydecoder-module\"></span><h2>snowboy.snowboydecoder module<a class=\"headerlink\" href=\"#module-snowboy.snowboydecoder\" title=\"永久链接至标题\">¶</a></h2>\n<dl class=\"class\">\n<dt id=\"snowboy.snowboydecoder.ActiveListener\">\n<em class=\"property\">class </em><code class=\"descclassname\">snowboy.snowboydecoder.</code><code class=\"descname\">ActiveListener</code><span class=\"sig-paren\">(</span><em>decoder_model</em>, <em>resource='/Users/panweizhou/Documents/projects/wukong-robot/snowboy/resources/common.res'</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/snowboy/snowboydecoder.html#ActiveListener\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#snowboy.snowboydecoder.ActiveListener\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>基类：<code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">object</span></code></p>\n<p>Active Listening with VAD</p>\n<dl class=\"method\">\n<dt id=\"snowboy.snowboydecoder.ActiveListener.listen\">\n<code class=\"descname\">listen</code><span class=\"sig-paren\">(</span><em>interrupt_check=&lt;function ActiveListener.&lt;lambda&gt;&gt;</em>, <em>sleep_time=0.03</em>, <em>silent_count_threshold=15</em>, <em>recording_timeout=100</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/snowboy/snowboydecoder.html#ActiveListener.listen\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#snowboy.snowboydecoder.ActiveListener.listen\" title=\"永久链接至目标\">¶</a></dt>\n<dd><table class=\"docutils field-list\" frame=\"void\" rules=\"none\">\n<col class=\"field-name\" />\n<col class=\"field-body\" />\n<tbody valign=\"top\">\n<tr class=\"field-odd field\"><th class=\"field-name\">参数:</th><td class=\"field-body\"><ul class=\"first simple\">\n<li><strong>interrupt_check</strong> – a function that returns True if the main loop\nneeds to stop.</li>\n<li><strong>silent_count_threshold</strong> – indicates how long silence must be heard\nto mark the end of a phrase that is\nbeing recorded.</li>\n<li><strong>sleep_time</strong> (<em>float</em>) – how much time in second every loop waits.</li>\n<li><strong>recording_timeout</strong> – limits the maximum length of a recording.</li>\n</ul>\n</td>\n</tr>\n<tr class=\"field-even field\"><th class=\"field-name\">返回:</th><td class=\"field-body\"><p class=\"first last\">recorded file path</p>\n</td>\n</tr>\n</tbody>\n</table>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"snowboy.snowboydecoder.ActiveListener.saveMessage\">\n<code class=\"descname\">saveMessage</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/snowboy/snowboydecoder.html#ActiveListener.saveMessage\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#snowboy.snowboydecoder.ActiveListener.saveMessage\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Save the message stored in self.recordedData to a timestamped file.</p>\n</dd></dl>\n\n</dd></dl>\n\n<dl class=\"class\">\n<dt id=\"snowboy.snowboydecoder.HotwordDetector\">\n<em class=\"property\">class </em><code class=\"descclassname\">snowboy.snowboydecoder.</code><code class=\"descname\">HotwordDetector</code><span class=\"sig-paren\">(</span><em>decoder_model</em>, <em>resource='/Users/panweizhou/Documents/projects/wukong-robot/snowboy/resources/common.res'</em>, <em>sensitivity=[]</em>, <em>audio_gain=1</em>, <em>apply_frontend=False</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/snowboy/snowboydecoder.html#HotwordDetector\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#snowboy.snowboydecoder.HotwordDetector\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>基类：<code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">object</span></code></p>\n<p>Snowboy decoder to detect whether a keyword specified by <cite>decoder_model</cite>\nexists in a microphone input stream.</p>\n<table class=\"docutils field-list\" frame=\"void\" rules=\"none\">\n<col class=\"field-name\" />\n<col class=\"field-body\" />\n<tbody valign=\"top\">\n<tr class=\"field-odd field\"><th class=\"field-name\">参数:</th><td class=\"field-body\"><ul class=\"first last simple\">\n<li><strong>decoder_model</strong> – decoder model file path, a string or a list of strings</li>\n<li><strong>resource</strong> – resource file path.</li>\n<li><strong>sensitivity</strong> – decoder sensitivity, a float of a list of floats.\nThe bigger the value, the more senstive the\ndecoder. If an empty list is provided, then the\ndefault sensitivity in the model will be used.</li>\n<li><strong>audio_gain</strong> – multiply input volume by this factor.</li>\n<li><strong>apply_frontend</strong> – applies the frontend processing algorithm if True.</li>\n</ul>\n</td>\n</tr>\n</tbody>\n</table>\n<dl class=\"method\">\n<dt id=\"snowboy.snowboydecoder.HotwordDetector.saveMessage\">\n<code class=\"descname\">saveMessage</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/snowboy/snowboydecoder.html#HotwordDetector.saveMessage\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#snowboy.snowboydecoder.HotwordDetector.saveMessage\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Save the message stored in self.recordedData to a timestamped file.</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"snowboy.snowboydecoder.HotwordDetector.start\">\n<code class=\"descname\">start</code><span class=\"sig-paren\">(</span><em>detected_callback=&lt;function play_audio_file&gt;</em>, <em>interrupt_check=&lt;function HotwordDetector.&lt;lambda&gt;&gt;</em>, <em>sleep_time=0.03</em>, <em>audio_recorder_callback=None</em>, <em>silent_count_threshold=15</em>, <em>recording_timeout=100</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/snowboy/snowboydecoder.html#HotwordDetector.start\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#snowboy.snowboydecoder.HotwordDetector.start\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Start the voice detector. For every <cite>sleep_time</cite> second it checks the\naudio buffer for triggering keywords. If detected, then call\ncorresponding function in <cite>detected_callback</cite>, which can be a single\nfunction (single model) or a list of callback functions (multiple\nmodels). Every loop it also calls <cite>interrupt_check</cite> – if it returns\nTrue, then breaks from the loop and return.</p>\n<table class=\"docutils field-list\" frame=\"void\" rules=\"none\">\n<col class=\"field-name\" />\n<col class=\"field-body\" />\n<tbody valign=\"top\">\n<tr class=\"field-odd field\"><th class=\"field-name\">参数:</th><td class=\"field-body\"><ul class=\"first simple\">\n<li><strong>detected_callback</strong> – a function or list of functions. The number of\nitems must match the number of models in\n<cite>decoder_model</cite>.</li>\n<li><strong>interrupt_check</strong> – a function that returns True if the main loop\nneeds to stop.</li>\n<li><strong>sleep_time</strong> (<em>float</em>) – how much time in second every loop waits.</li>\n<li><strong>audio_recorder_callback</strong> – if specified, this will be called after\na keyword has been spoken and after the\nphrase immediately after the keyword has\nbeen recorded. The function will be\npassed the name of the file where the\nphrase was recorded.</li>\n<li><strong>silent_count_threshold</strong> – indicates how long silence must be heard\nto mark the end of a phrase that is\nbeing recorded.</li>\n<li><strong>recording_timeout</strong> – limits the maximum length of a recording.</li>\n</ul>\n</td>\n</tr>\n<tr class=\"field-even field\"><th class=\"field-name\">返回:</th><td class=\"field-body\"><p class=\"first last\">None</p>\n</td>\n</tr>\n</tbody>\n</table>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"snowboy.snowboydecoder.HotwordDetector.terminate\">\n<code class=\"descname\">terminate</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/snowboy/snowboydecoder.html#HotwordDetector.terminate\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#snowboy.snowboydecoder.HotwordDetector.terminate\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Terminate audio stream. Users can call start() again to detect.\n:return: None</p>\n</dd></dl>\n\n</dd></dl>\n\n<dl class=\"class\">\n<dt id=\"snowboy.snowboydecoder.RingBuffer\">\n<em class=\"property\">class </em><code class=\"descclassname\">snowboy.snowboydecoder.</code><code class=\"descname\">RingBuffer</code><span class=\"sig-paren\">(</span><em>size=4096</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/snowboy/snowboydecoder.html#RingBuffer\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#snowboy.snowboydecoder.RingBuffer\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>基类：<code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">object</span></code></p>\n<p>Ring buffer to hold audio from PortAudio</p>\n<dl class=\"method\">\n<dt id=\"snowboy.snowboydecoder.RingBuffer.extend\">\n<code class=\"descname\">extend</code><span class=\"sig-paren\">(</span><em>data</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/snowboy/snowboydecoder.html#RingBuffer.extend\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#snowboy.snowboydecoder.RingBuffer.extend\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Adds data to the end of buffer</p>\n</dd></dl>\n\n<dl class=\"method\">\n<dt id=\"snowboy.snowboydecoder.RingBuffer.get\">\n<code class=\"descname\">get</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/snowboy/snowboydecoder.html#RingBuffer.get\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#snowboy.snowboydecoder.RingBuffer.get\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Retrieves data from the beginning of buffer and clears it</p>\n</dd></dl>\n\n</dd></dl>\n\n<dl class=\"function\">\n<dt id=\"snowboy.snowboydecoder.no_alsa_error\">\n<code class=\"descclassname\">snowboy.snowboydecoder.</code><code class=\"descname\">no_alsa_error</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/snowboy/snowboydecoder.html#no_alsa_error\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#snowboy.snowboydecoder.no_alsa_error\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"function\">\n<dt id=\"snowboy.snowboydecoder.play_audio_file\">\n<code class=\"descclassname\">snowboy.snowboydecoder.</code><code class=\"descname\">play_audio_file</code><span class=\"sig-paren\">(</span><em>fname='/Users/panweizhou/Documents/projects/wukong-robot/snowboy/resources/ding.wav'</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/snowboy/snowboydecoder.html#play_audio_file\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#snowboy.snowboydecoder.play_audio_file\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>Simple callback function to play a wave file. By default it plays\na Ding sound.</p>\n<table class=\"docutils field-list\" frame=\"void\" rules=\"none\">\n<col class=\"field-name\" />\n<col class=\"field-body\" />\n<tbody valign=\"top\">\n<tr class=\"field-odd field\"><th class=\"field-name\">参数:</th><td class=\"field-body\"><strong>fname</strong> (<em>str</em>) – wave file name</td>\n</tr>\n<tr class=\"field-even field\"><th class=\"field-name\">返回:</th><td class=\"field-body\">None</td>\n</tr>\n</tbody>\n</table>\n</dd></dl>\n\n<dl class=\"function\">\n<dt id=\"snowboy.snowboydecoder.py_error_handler\">\n<code class=\"descclassname\">snowboy.snowboydecoder.</code><code class=\"descname\">py_error_handler</code><span class=\"sig-paren\">(</span><em>filename</em>, <em>line</em>, <em>function</em>, <em>err</em>, <em>fmt</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/snowboy/snowboydecoder.html#py_error_handler\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#snowboy.snowboydecoder.py_error_handler\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n</div>\n<div class=\"section\" id=\"module-snowboy.snowboydetect\">\n<span id=\"snowboy-snowboydetect-module\"></span><h2>snowboy.snowboydetect module<a class=\"headerlink\" href=\"#module-snowboy.snowboydetect\" title=\"永久链接至标题\">¶</a></h2>\n<dl class=\"class\">\n<dt id=\"snowboy.snowboydetect.SnowboyDetect\">\n<em class=\"property\">class </em><code class=\"descclassname\">snowboy.snowboydetect.</code><code class=\"descname\">SnowboyDetect</code><span class=\"sig-paren\">(</span><em>resource_filename</em>, <em>model_str</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/snowboy/snowboydetect.html#SnowboyDetect\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#snowboy.snowboydetect.SnowboyDetect\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>基类：<code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">object</span></code></p>\n<dl class=\"method\">\n<dt id=\"snowboy.snowboydetect.SnowboyDetect.ApplyFrontend\">\n<code class=\"descname\">ApplyFrontend</code><span class=\"sig-paren\">(</span><em>apply_frontend</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/snowboy/snowboydetect.html#SnowboyDetect.ApplyFrontend\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#snowboy.snowboydetect.SnowboyDetect.ApplyFrontend\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"snowboy.snowboydetect.SnowboyDetect.BitsPerSample\">\n<code class=\"descname\">BitsPerSample</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/snowboy/snowboydetect.html#SnowboyDetect.BitsPerSample\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#snowboy.snowboydetect.SnowboyDetect.BitsPerSample\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"snowboy.snowboydetect.SnowboyDetect.GetSensitivity\">\n<code class=\"descname\">GetSensitivity</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/snowboy/snowboydetect.html#SnowboyDetect.GetSensitivity\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#snowboy.snowboydetect.SnowboyDetect.GetSensitivity\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"snowboy.snowboydetect.SnowboyDetect.NumChannels\">\n<code class=\"descname\">NumChannels</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/snowboy/snowboydetect.html#SnowboyDetect.NumChannels\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#snowboy.snowboydetect.SnowboyDetect.NumChannels\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"snowboy.snowboydetect.SnowboyDetect.NumHotwords\">\n<code class=\"descname\">NumHotwords</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/snowboy/snowboydetect.html#SnowboyDetect.NumHotwords\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#snowboy.snowboydetect.SnowboyDetect.NumHotwords\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"snowboy.snowboydetect.SnowboyDetect.Reset\">\n<code class=\"descname\">Reset</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/snowboy/snowboydetect.html#SnowboyDetect.Reset\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#snowboy.snowboydetect.SnowboyDetect.Reset\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"snowboy.snowboydetect.SnowboyDetect.RunDetection\">\n<code class=\"descname\">RunDetection</code><span class=\"sig-paren\">(</span><em>*args</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/snowboy/snowboydetect.html#SnowboyDetect.RunDetection\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#snowboy.snowboydetect.SnowboyDetect.RunDetection\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"snowboy.snowboydetect.SnowboyDetect.SampleRate\">\n<code class=\"descname\">SampleRate</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/snowboy/snowboydetect.html#SnowboyDetect.SampleRate\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#snowboy.snowboydetect.SnowboyDetect.SampleRate\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"snowboy.snowboydetect.SnowboyDetect.SetAudioGain\">\n<code class=\"descname\">SetAudioGain</code><span class=\"sig-paren\">(</span><em>audio_gain</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/snowboy/snowboydetect.html#SnowboyDetect.SetAudioGain\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#snowboy.snowboydetect.SnowboyDetect.SetAudioGain\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"snowboy.snowboydetect.SnowboyDetect.SetHighSensitivity\">\n<code class=\"descname\">SetHighSensitivity</code><span class=\"sig-paren\">(</span><em>high_sensitivity_str</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/snowboy/snowboydetect.html#SnowboyDetect.SetHighSensitivity\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#snowboy.snowboydetect.SnowboyDetect.SetHighSensitivity\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"snowboy.snowboydetect.SnowboyDetect.SetSensitivity\">\n<code class=\"descname\">SetSensitivity</code><span class=\"sig-paren\">(</span><em>sensitivity_str</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/snowboy/snowboydetect.html#SnowboyDetect.SetSensitivity\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#snowboy.snowboydetect.SnowboyDetect.SetSensitivity\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"snowboy.snowboydetect.SnowboyDetect.UpdateModel\">\n<code class=\"descname\">UpdateModel</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/snowboy/snowboydetect.html#SnowboyDetect.UpdateModel\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#snowboy.snowboydetect.SnowboyDetect.UpdateModel\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n</dd></dl>\n\n<dl class=\"class\">\n<dt id=\"snowboy.snowboydetect.SnowboyVad\">\n<em class=\"property\">class </em><code class=\"descclassname\">snowboy.snowboydetect.</code><code class=\"descname\">SnowboyVad</code><span class=\"sig-paren\">(</span><em>resource_filename</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/snowboy/snowboydetect.html#SnowboyVad\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#snowboy.snowboydetect.SnowboyVad\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>基类：<code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">object</span></code></p>\n<dl class=\"method\">\n<dt id=\"snowboy.snowboydetect.SnowboyVad.ApplyFrontend\">\n<code class=\"descname\">ApplyFrontend</code><span class=\"sig-paren\">(</span><em>apply_frontend</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/snowboy/snowboydetect.html#SnowboyVad.ApplyFrontend\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#snowboy.snowboydetect.SnowboyVad.ApplyFrontend\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"snowboy.snowboydetect.SnowboyVad.BitsPerSample\">\n<code class=\"descname\">BitsPerSample</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/snowboy/snowboydetect.html#SnowboyVad.BitsPerSample\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#snowboy.snowboydetect.SnowboyVad.BitsPerSample\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"snowboy.snowboydetect.SnowboyVad.NumChannels\">\n<code class=\"descname\">NumChannels</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/snowboy/snowboydetect.html#SnowboyVad.NumChannels\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#snowboy.snowboydetect.SnowboyVad.NumChannels\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"snowboy.snowboydetect.SnowboyVad.Reset\">\n<code class=\"descname\">Reset</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/snowboy/snowboydetect.html#SnowboyVad.Reset\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#snowboy.snowboydetect.SnowboyVad.Reset\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"snowboy.snowboydetect.SnowboyVad.RunVad\">\n<code class=\"descname\">RunVad</code><span class=\"sig-paren\">(</span><em>*args</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/snowboy/snowboydetect.html#SnowboyVad.RunVad\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#snowboy.snowboydetect.SnowboyVad.RunVad\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"snowboy.snowboydetect.SnowboyVad.SampleRate\">\n<code class=\"descname\">SampleRate</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/snowboy/snowboydetect.html#SnowboyVad.SampleRate\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#snowboy.snowboydetect.SnowboyVad.SampleRate\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"snowboy.snowboydetect.SnowboyVad.SetAudioGain\">\n<code class=\"descname\">SetAudioGain</code><span class=\"sig-paren\">(</span><em>audio_gain</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/snowboy/snowboydetect.html#SnowboyVad.SetAudioGain\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#snowboy.snowboydetect.SnowboyVad.SetAudioGain\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n</dd></dl>\n\n</div>\n<div class=\"section\" id=\"module-snowboy\">\n<span id=\"module-contents\"></span><h2>Module contents<a class=\"headerlink\" href=\"#module-snowboy\" title=\"永久链接至标题\">¶</a></h2>\n</div>\n</div>\n\n\n           </div>\n           \n          </div>\n          <footer>\n  \n\n  <hr/>\n\n  <div role=\"contentinfo\">\n    <p>\n        &copy; Copyright 2019, wzpan\n\n    </p>\n  </div>\n  Built with <a href=\"http://sphinx-doc.org/\">Sphinx</a> using a <a href=\"https://github.com/rtfd/sphinx_rtd_theme\">theme</a> provided by <a href=\"https://readthedocs.org\">Read the Docs</a>. \n\n</footer>\n\n        </div>\n      </div>\n\n    </section>\n\n  </div>\n  \n\n\n  <script type=\"text/javascript\">\n      jQuery(function () {\n          SphinxRtdTheme.Navigation.enable(true);\n      });\n  </script>\n\n  \n  \n    \n   \n\n</body>\n</html>"
  },
  {
    "path": "docs/statistic.html",
    "content": "\n\n<!DOCTYPE html>\n<!--[if IE 8]><html class=\"no-js lt-ie9\" lang=\"zh-CN\" > <![endif]-->\n<!--[if gt IE 8]><!--> <html class=\"no-js\" lang=\"zh-CN\" > <!--<![endif]-->\n<head>\n  <meta charset=\"utf-8\">\n  \n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  \n  <title>statistic module &mdash; wukong-robot 1.2.0 文档</title>\n  \n\n  \n  \n  \n  \n\n  \n  <script type=\"text/javascript\" src=\"_static/js/modernizr.min.js\"></script>\n  \n    \n      <script type=\"text/javascript\" id=\"documentation_options\" data-url_root=\"./\" src=\"_static/documentation_options.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/jquery.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/underscore.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/doctools.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/language_data.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/translations.js\"></script>\n    \n    <script type=\"text/javascript\" src=\"_static/js/theme.js\"></script>\n\n    \n\n  \n  <link rel=\"stylesheet\" href=\"_static/css/theme.css\" type=\"text/css\" />\n  <link rel=\"stylesheet\" href=\"_static/pygments.css\" type=\"text/css\" />\n    <link rel=\"index\" title=\"索引\" href=\"genindex.html\" />\n    <link rel=\"search\" title=\"搜索\" href=\"search.html\" /> \n</head>\n\n<body class=\"wy-body-for-nav\">\n\n   \n  <div class=\"wy-grid-for-nav\">\n    \n    <nav data-toggle=\"wy-nav-shift\" class=\"wy-nav-side\">\n      <div class=\"wy-side-scroll\">\n        <div class=\"wy-side-nav-search\" >\n          \n\n          \n            <a href=\"index.html\" class=\"icon icon-home\"> wukong-robot\n          \n\n          \n          </a>\n\n          \n            \n            \n          \n\n          \n<div role=\"search\">\n  <form id=\"rtd-search-form\" class=\"wy-form\" action=\"search.html\" method=\"get\">\n    <input type=\"text\" name=\"q\" placeholder=\"Search docs\" />\n    <input type=\"hidden\" name=\"check_keywords\" value=\"yes\" />\n    <input type=\"hidden\" name=\"area\" value=\"default\" />\n  </form>\n</div>\n\n          \n        </div>\n\n        <div class=\"wy-menu wy-menu-vertical\" data-spy=\"affix\" role=\"navigation\" aria-label=\"main navigation\">\n          \n            \n            \n              \n            \n            \n              <!-- Local TOC -->\n              <div class=\"local-toc\"><ul>\n<li><a class=\"reference internal\" href=\"#\">statistic module</a></li>\n</ul>\n</div>\n            \n          \n        </div>\n      </div>\n    </nav>\n\n    <section data-toggle=\"wy-nav-shift\" class=\"wy-nav-content-wrap\">\n\n      \n      <nav class=\"wy-nav-top\" aria-label=\"top navigation\">\n        \n          <i data-toggle=\"wy-nav-top\" class=\"fa fa-bars\"></i>\n          <a href=\"index.html\">wukong-robot</a>\n        \n      </nav>\n\n\n      <div class=\"wy-nav-content\">\n        \n        <div class=\"rst-content\">\n        \n          \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<div role=\"navigation\" aria-label=\"breadcrumbs navigation\">\n\n  <ul class=\"wy-breadcrumbs\">\n    \n      <li><a href=\"index.html\">Docs</a> &raquo;</li>\n        \n      <li>statistic module</li>\n    \n    \n      <li class=\"wy-breadcrumbs-aside\">\n        \n            \n            <a href=\"_sources/statistic.rst.txt\" rel=\"nofollow\"> View page source</a>\n          \n        \n      </li>\n    \n  </ul>\n\n  \n  <hr/>\n</div>\n          <div role=\"main\" class=\"document\" itemscope=\"itemscope\" itemtype=\"http://schema.org/Article\">\n           <div itemprop=\"articleBody\">\n            \n  <div class=\"section\" id=\"statistic-module\">\n<h1>statistic module<a class=\"headerlink\" href=\"#statistic-module\" title=\"永久链接至标题\">¶</a></h1>\n</div>\n\n\n           </div>\n           \n          </div>\n          <footer>\n  \n\n  <hr/>\n\n  <div role=\"contentinfo\">\n    <p>\n        &copy; Copyright 2019, wzpan\n\n    </p>\n  </div>\n  Built with <a href=\"http://sphinx-doc.org/\">Sphinx</a> using a <a href=\"https://github.com/rtfd/sphinx_rtd_theme\">theme</a> provided by <a href=\"https://readthedocs.org\">Read the Docs</a>. \n\n</footer>\n\n        </div>\n      </div>\n\n    </section>\n\n  </div>\n  \n\n\n  <script type=\"text/javascript\">\n      jQuery(function () {\n          SphinxRtdTheme.Navigation.enable(true);\n      });\n  </script>\n\n  \n  \n    \n   \n\n</body>\n</html>"
  },
  {
    "path": "docs/utils.html",
    "content": "\n\n<!DOCTYPE html>\n<!--[if IE 8]><html class=\"no-js lt-ie9\" lang=\"zh-CN\" > <![endif]-->\n<!--[if gt IE 8]><!--> <html class=\"no-js\" lang=\"zh-CN\" > <!--<![endif]-->\n<head>\n  <meta charset=\"utf-8\">\n  \n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  \n  <title>utils module &mdash; wukong-robot 1.2.0 文档</title>\n  \n\n  \n  \n  \n  \n\n  \n  <script type=\"text/javascript\" src=\"_static/js/modernizr.min.js\"></script>\n  \n    \n      <script type=\"text/javascript\" id=\"documentation_options\" data-url_root=\"./\" src=\"_static/documentation_options.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/jquery.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/underscore.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/doctools.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/language_data.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/translations.js\"></script>\n    \n    <script type=\"text/javascript\" src=\"_static/js/theme.js\"></script>\n\n    \n\n  \n  <link rel=\"stylesheet\" href=\"_static/css/theme.css\" type=\"text/css\" />\n  <link rel=\"stylesheet\" href=\"_static/pygments.css\" type=\"text/css\" />\n    <link rel=\"index\" title=\"索引\" href=\"genindex.html\" />\n    <link rel=\"search\" title=\"搜索\" href=\"search.html\" /> \n</head>\n\n<body class=\"wy-body-for-nav\">\n\n   \n  <div class=\"wy-grid-for-nav\">\n    \n    <nav data-toggle=\"wy-nav-shift\" class=\"wy-nav-side\">\n      <div class=\"wy-side-scroll\">\n        <div class=\"wy-side-nav-search\" >\n          \n\n          \n            <a href=\"index.html\" class=\"icon icon-home\"> wukong-robot\n          \n\n          \n          </a>\n\n          \n            \n            \n          \n\n          \n<div role=\"search\">\n  <form id=\"rtd-search-form\" class=\"wy-form\" action=\"search.html\" method=\"get\">\n    <input type=\"text\" name=\"q\" placeholder=\"Search docs\" />\n    <input type=\"hidden\" name=\"check_keywords\" value=\"yes\" />\n    <input type=\"hidden\" name=\"area\" value=\"default\" />\n  </form>\n</div>\n\n          \n        </div>\n\n        <div class=\"wy-menu wy-menu-vertical\" data-spy=\"affix\" role=\"navigation\" aria-label=\"main navigation\">\n          \n            \n            \n              \n            \n            \n              <!-- Local TOC -->\n              <div class=\"local-toc\"><ul>\n<li><a class=\"reference internal\" href=\"#\">utils module</a></li>\n</ul>\n</div>\n            \n          \n        </div>\n      </div>\n    </nav>\n\n    <section data-toggle=\"wy-nav-shift\" class=\"wy-nav-content-wrap\">\n\n      \n      <nav class=\"wy-nav-top\" aria-label=\"top navigation\">\n        \n          <i data-toggle=\"wy-nav-top\" class=\"fa fa-bars\"></i>\n          <a href=\"index.html\">wukong-robot</a>\n        \n      </nav>\n\n\n      <div class=\"wy-nav-content\">\n        \n        <div class=\"rst-content\">\n        \n          \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<div role=\"navigation\" aria-label=\"breadcrumbs navigation\">\n\n  <ul class=\"wy-breadcrumbs\">\n    \n      <li><a href=\"index.html\">Docs</a> &raquo;</li>\n        \n      <li>utils module</li>\n    \n    \n      <li class=\"wy-breadcrumbs-aside\">\n        \n            \n            <a href=\"_sources/utils.rst.txt\" rel=\"nofollow\"> View page source</a>\n          \n        \n      </li>\n    \n  </ul>\n\n  \n  <hr/>\n</div>\n          <div role=\"main\" class=\"document\" itemscope=\"itemscope\" itemtype=\"http://schema.org/Article\">\n           <div itemprop=\"articleBody\">\n            \n  <div class=\"section\" id=\"utils-module\">\n<h1>utils module<a class=\"headerlink\" href=\"#utils-module\" title=\"永久链接至标题\">¶</a></h1>\n</div>\n\n\n           </div>\n           \n          </div>\n          <footer>\n  \n\n  <hr/>\n\n  <div role=\"contentinfo\">\n    <p>\n        &copy; Copyright 2019, wzpan\n\n    </p>\n  </div>\n  Built with <a href=\"http://sphinx-doc.org/\">Sphinx</a> using a <a href=\"https://github.com/rtfd/sphinx_rtd_theme\">theme</a> provided by <a href=\"https://readthedocs.org\">Read the Docs</a>. \n\n</footer>\n\n        </div>\n      </div>\n\n    </section>\n\n  </div>\n  \n\n\n  <script type=\"text/javascript\">\n      jQuery(function () {\n          SphinxRtdTheme.Navigation.enable(true);\n      });\n  </script>\n\n  \n  \n    \n   \n\n</body>\n</html>"
  },
  {
    "path": "docs/wukong.html",
    "content": "\n\n<!DOCTYPE html>\n<!--[if IE 8]><html class=\"no-js lt-ie9\" lang=\"zh-CN\" > <![endif]-->\n<!--[if gt IE 8]><!--> <html class=\"no-js\" lang=\"zh-CN\" > <!--<![endif]-->\n<head>\n  <meta charset=\"utf-8\">\n  \n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  \n  <title>wukong module &mdash; wukong-robot 1.2.0 文档</title>\n  \n\n  \n  \n  \n  \n\n  \n  <script type=\"text/javascript\" src=\"_static/js/modernizr.min.js\"></script>\n  \n    \n      <script type=\"text/javascript\" id=\"documentation_options\" data-url_root=\"./\" src=\"_static/documentation_options.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/jquery.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/underscore.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/doctools.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/language_data.js\"></script>\n        <script type=\"text/javascript\" src=\"_static/translations.js\"></script>\n    \n    <script type=\"text/javascript\" src=\"_static/js/theme.js\"></script>\n\n    \n\n  \n  <link rel=\"stylesheet\" href=\"_static/css/theme.css\" type=\"text/css\" />\n  <link rel=\"stylesheet\" href=\"_static/pygments.css\" type=\"text/css\" />\n    <link rel=\"index\" title=\"索引\" href=\"genindex.html\" />\n    <link rel=\"search\" title=\"搜索\" href=\"search.html\" /> \n</head>\n\n<body class=\"wy-body-for-nav\">\n\n   \n  <div class=\"wy-grid-for-nav\">\n    \n    <nav data-toggle=\"wy-nav-shift\" class=\"wy-nav-side\">\n      <div class=\"wy-side-scroll\">\n        <div class=\"wy-side-nav-search\" >\n          \n\n          \n            <a href=\"index.html\" class=\"icon icon-home\"> wukong-robot\n          \n\n          \n          </a>\n\n          \n            \n            \n          \n\n          \n<div role=\"search\">\n  <form id=\"rtd-search-form\" class=\"wy-form\" action=\"search.html\" method=\"get\">\n    <input type=\"text\" name=\"q\" placeholder=\"Search docs\" />\n    <input type=\"hidden\" name=\"check_keywords\" value=\"yes\" />\n    <input type=\"hidden\" name=\"area\" value=\"default\" />\n  </form>\n</div>\n\n          \n        </div>\n\n        <div class=\"wy-menu wy-menu-vertical\" data-spy=\"affix\" role=\"navigation\" aria-label=\"main navigation\">\n          \n            \n            \n              \n            \n            \n              <!-- Local TOC -->\n              <div class=\"local-toc\"><ul>\n<li><a class=\"reference internal\" href=\"#\">wukong module</a></li>\n</ul>\n</div>\n            \n          \n        </div>\n      </div>\n    </nav>\n\n    <section data-toggle=\"wy-nav-shift\" class=\"wy-nav-content-wrap\">\n\n      \n      <nav class=\"wy-nav-top\" aria-label=\"top navigation\">\n        \n          <i data-toggle=\"wy-nav-top\" class=\"fa fa-bars\"></i>\n          <a href=\"index.html\">wukong-robot</a>\n        \n      </nav>\n\n\n      <div class=\"wy-nav-content\">\n        \n        <div class=\"rst-content\">\n        \n          \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<div role=\"navigation\" aria-label=\"breadcrumbs navigation\">\n\n  <ul class=\"wy-breadcrumbs\">\n    \n      <li><a href=\"index.html\">Docs</a> &raquo;</li>\n        \n      <li>wukong module</li>\n    \n    \n      <li class=\"wy-breadcrumbs-aside\">\n        \n            \n            <a href=\"_sources/wukong.rst.txt\" rel=\"nofollow\"> View page source</a>\n          \n        \n      </li>\n    \n  </ul>\n\n  \n  <hr/>\n</div>\n          <div role=\"main\" class=\"document\" itemscope=\"itemscope\" itemtype=\"http://schema.org/Article\">\n           <div itemprop=\"articleBody\">\n            \n  <div class=\"section\" id=\"module-wukong\">\n<span id=\"wukong-module\"></span><h1>wukong module<a class=\"headerlink\" href=\"#module-wukong\" title=\"永久链接至标题\">¶</a></h1>\n<dl class=\"class\">\n<dt id=\"wukong.Wukong\">\n<em class=\"property\">class </em><code class=\"descclassname\">wukong.</code><code class=\"descname\">Wukong</code><a class=\"reference internal\" href=\"_modules/wukong.html#Wukong\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#wukong.Wukong\" title=\"永久链接至目标\">¶</a></dt>\n<dd><p>基类：<code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">object</span></code></p>\n<dl class=\"method\">\n<dt id=\"wukong.Wukong.dev\">\n<code class=\"descname\">dev</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/wukong.html#Wukong.dev\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#wukong.Wukong.dev\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"wukong.Wukong.fetch\">\n<code class=\"descname\">fetch</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/wukong.html#Wukong.fetch\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#wukong.Wukong.fetch\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"wukong.Wukong.init\">\n<code class=\"descname\">init</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/wukong.html#Wukong.init\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#wukong.Wukong.init\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"wukong.Wukong.initDetector\">\n<code class=\"descname\">initDetector</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/wukong.html#Wukong.initDetector\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#wukong.Wukong.initDetector\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"wukong.Wukong.md5\">\n<code class=\"descname\">md5</code><span class=\"sig-paren\">(</span><em>password</em><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/wukong.html#Wukong.md5\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#wukong.Wukong.md5\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"wukong.Wukong.profiling\">\n<code class=\"descname\">profiling</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/wukong.html#Wukong.profiling\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#wukong.Wukong.profiling\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"wukong.Wukong.restart\">\n<code class=\"descname\">restart</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/wukong.html#Wukong.restart\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#wukong.Wukong.restart\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"wukong.Wukong.run\">\n<code class=\"descname\">run</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/wukong.html#Wukong.run\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#wukong.Wukong.run\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n<dl class=\"method\">\n<dt id=\"wukong.Wukong.update\">\n<code class=\"descname\">update</code><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"reference internal\" href=\"_modules/wukong.html#Wukong.update\"><span class=\"viewcode-link\">[源代码]</span></a><a class=\"headerlink\" href=\"#wukong.Wukong.update\" title=\"永久链接至目标\">¶</a></dt>\n<dd></dd></dl>\n\n</dd></dl>\n\n</div>\n\n\n           </div>\n           \n          </div>\n          <footer>\n  \n\n  <hr/>\n\n  <div role=\"contentinfo\">\n    <p>\n        &copy; Copyright 2019, wzpan\n\n    </p>\n  </div>\n  Built with <a href=\"http://sphinx-doc.org/\">Sphinx</a> using a <a href=\"https://github.com/rtfd/sphinx_rtd_theme\">theme</a> provided by <a href=\"https://readthedocs.org\">Read the Docs</a>. \n\n</footer>\n\n        </div>\n      </div>\n\n    </section>\n\n  </div>\n  \n\n\n  <script type=\"text/javascript\">\n      jQuery(function () {\n          SphinxRtdTheme.Navigation.enable(true);\n      });\n  </script>\n\n  \n  \n    \n   \n\n</body>\n</html>"
  },
  {
    "path": "plugins/Camera.py",
    "content": "# -*- coding: utf-8 -*-\n\nimport os\nimport subprocess\nimport time\nfrom robot import config, constants, logging\nfrom robot.sdk.AbstractPlugin import AbstractPlugin\n\nlogger = logging.getLogger(__name__)\n\n\nclass Plugin(AbstractPlugin):\n\n    SLUG = \"camera\"\n\n    def handle(self, text, parsed):\n        quality = config.get(\"/camera/quality\", 100)\n        count_down = config.get(\"/camera/count_down\", 3)\n        dest_path = config.get(\"/camera/dest_path\", os.path.expanduser(\"~/pictures\"))\n        device = config.get(\"/camera/device\", \"/dev/video0\")\n        vertical_flip = config.get(\"/camera/vetical_flip\", False)\n        horizontal_flip = config.get(\"/camera/horizontal_flip\", False)\n        sound = config.get(\"/camera/sound\", True)\n        camera_type = config.get(\"/camera/type\", 0)\n        if config.has(\"/camera/usb_camera\") and config.get(\"/camera/usb_camera\"):\n            camera_type = 0\n        if any(word in text for word in [\"安静\", \"偷偷\", \"悄悄\"]):\n            sound = False\n        try:\n            if not os.path.exists(dest_path):\n                os.makedirs(dest_path)\n        except Exception:\n            self.say(\"抱歉，照片目录创建失败\", cache=True)\n            return\n        dest_file = os.path.join(dest_path, \"%s.jpg\" % time.time()).replace(\".\", \"\", 1)\n        if camera_type == 0:\n            # usb camera\n            logger.info(\"usb camera\")\n            command = [\"fswebcam\", \"--no-banner\", \"-r\", \"1024x765\", \"-q\", \"-d\", device]\n            if vertical_flip:\n                command.extend([\"-s\", \"v\"])\n            if horizontal_flip:\n                command.extend([\"-s\", \"h\"])\n            command.append(dest_file)\n        elif camera_type == 1:\n            # Raspberry Pi 5MP\n            logger.info(\"Raspberry Pi 5MP camera\")\n            command = [\"raspistill\", \"-o\", dest_file, \"-q\", str(quality)]\n            if count_down > 0 and sound:\n                command.extend([\"-t\", str(count_down * 1000)])\n            if vertical_flip:\n                command.append(\"-vf\")\n            if horizontal_flip:\n                command.append(\"-hf\")\n        else:\n            # notebook camera\n            logger.info(\"notebook camera\")\n            command = [\"imagesnap\", dest_file]\n            if count_down > 0 and sound:\n                command.extend([\"-w\", str(count_down)])\n        if sound and count_down > 0:\n            self.say(\"收到，%d秒后启动拍照\" % (count_down), cache=True)\n            if camera_type == 0:\n                time.sleep(count_down)\n\n        try:\n            subprocess.run(command, shell=False, check=True)\n            if sound:\n                self.play(constants.getData(\"camera.wav\"))\n                photo_url = \"http://{}:{}/photo/{}\".format(\n                    config.get(\"/server/host\"),\n                    config.get(\"/server/port\"),\n                    os.path.basename(dest_file),\n                )\n                self.say(\"拍照成功\", cache=True)\n                self.say(photo_url)\n        except subprocess.CalledProcessError as e:\n            logger.error(e, stack_info=True)\n            if sound:\n                self.say(\"拍照失败，请检查相机是否连接正确\", cache=True)\n\n    def isValid(self, text, parsed):\n        return any(word in text for word in [\"拍照\", \"拍张照\"]) and not any(\n            word in text for word in [\"拍照成功\", \"拍照失败\", \"后启动拍照\"]\n        )\n"
  },
  {
    "path": "plugins/CleanCache.py",
    "content": "# -*- coding: utf-8 -*-\n\nimport os\nfrom robot import constants, utils\nfrom robot.sdk.AbstractPlugin import AbstractPlugin\n\n\nclass Plugin(AbstractPlugin):\n\n    SLUG = \"cleancache\"\n\n    def handle(self, text, parsed):\n        temp = constants.TEMP_PATH\n        for f in os.listdir(temp):\n            if f != \"DIR\":\n                utils.check_and_delete(os.path.join(temp, f))\n        self.say(\"缓存目录已清空\", cache=True)\n\n    def isValid(self, text, parsed):\n        return any(word in text.lower() for word in [\"清除缓存\", \"清空缓存\", \"清缓存\"])\n"
  },
  {
    "path": "plugins/Echo.py",
    "content": "# -*- coding: utf-8 -*-\n# author: wzpan\n# 回声\n\nimport logging\nfrom robot.sdk.AbstractPlugin import AbstractPlugin\n\nlogger = logging.getLogger(__name__)\n\n\nclass Plugin(AbstractPlugin):\n    def handle(self, text, parsed):\n        text = text.lower().replace(\"echo\", \"\").replace(\"传话\", \"\")\n        self.say(text, cache=False)\n\n    def isValid(self, text, parsed):\n        return any(word in text.lower() for word in [\"echo\", \"传话\"])\n"
  },
  {
    "path": "plugins/Email.py",
    "content": "# -*- coding: utf-8 -*-\nimport imaplib\nimport email\nimport time\nimport datetime\nfrom robot import logging\nfrom dateutil import parser\nfrom robot import config\nfrom robot.sdk.AbstractPlugin import AbstractPlugin\n\n\nclass Plugin(AbstractPlugin):\n\n    SLUG = \"email\"\n\n    def getSender(self, msg):\n        \"\"\"\n        Returns the best-guess sender of an email.\n\n        Arguments:\n        msg -- the email whose sender is desired\n\n        Returns:\n        Sender of the sender.\n        \"\"\"\n        fromstr = str(msg[\"From\"])\n        ls = fromstr.split(\" \")\n        if len(ls) == 2:\n            fromname = email.header.decode_header(str(ls[0]).strip('\"'))\n            sender = fromname[0][0]\n        elif len(ls) > 2:\n            fromname = email.header.decode_header(\n                str(fromstr[: fromstr.find(\"<\")]).strip('\"')\n            )\n            sender = fromname[0][0]\n        else:\n            sender = msg[\"From\"]\n        if isinstance(sender, bytes):\n            try:\n                return sender.decode(\"utf-8\")\n            except UnicodeDecodeError:\n                return sender.decode(\"gbk\")\n        else:\n            return sender\n\n    def isSelfEmail(self, msg):\n        \"\"\"Whether the email is sent by the user\"\"\"\n        fromstr = str(msg[\"From\"])\n        addr = (fromstr[fromstr.find(\"<\") + 1 : fromstr.find(\">\")]).strip('\"')\n        address = config.get()[self.SLUG][\"address\"].strip()\n        return addr == address\n\n    def getSubject(self, msg):\n        \"\"\"\n        Returns the title of an email\n\n        Arguments:\n        msg -- the email\n\n        Returns:\n        Title of the email.\n        \"\"\"\n        subject = email.header.decode_header(msg[\"subject\"])\n        if isinstance(subject[0][0], bytes):\n            try:\n                sub = subject[0][0].decode(\"utf-8\")\n            except UnicodeDecodeError:\n                sub = subject[0][0].decode(\"gbk\")\n        else:\n            sub = subject[0][0]\n        to_read = False\n        if sub.strip() == \"\":\n            return \"\"\n        to_read = config.get(\"/email/read_email_title\", True)\n        if to_read:\n            return \"邮件标题为 %s\" % sub\n        return \"\"\n\n    def isNewEmail(msg):\n        \"\"\"Wether an email is a new email\"\"\"\n        date = str(msg[\"Date\"])\n        dtext = date.split(\",\")[1].split(\"+\")[0].strip()\n        dtime = time.strptime(dtext, \"%d %b %Y %H:%M:%S\")\n        current = time.localtime()\n        dt = datetime.datetime(*dtime[:6])\n        cr = datetime.datetime(*current[:6])\n        return (cr - dt).days == 0\n\n    def getDate(self, email):\n        return parser.parse(email.get(\"date\"))\n\n    def getMostRecentDate(self, emails):\n        \"\"\"\n        Returns the most recent date of any email in the list provided.\n\n        Arguments:\n        emails -- a list of emails to check\n\n        Returns:\n        Date of the most recent email.\n        \"\"\"\n        dates = [self.getDate(e) for e in emails]\n        dates.sort(reverse=True)\n        if dates:\n            return dates[0]\n        return None\n\n    def fetchUnreadEmails(self, since=None, markRead=False, limit=None):\n        \"\"\"\n        Fetches a list of unread email objects from a user's email inbox.\n\n        Arguments:\n        since -- if provided, no emails before this date will be returned\n        markRead -- if True, marks all returned emails as read in target inbox\n\n        Returns:\n        A list of unread email objects.\n        \"\"\"\n        logger = logging.getLogger(__name__)\n        profile = config.get()\n        conn = imaplib.IMAP4(\n            profile[self.SLUG][\"imap_server\"], profile[self.SLUG][\"imap_port\"]\n        )\n        conn.debug = 0\n\n        msgs = []\n        try:\n            conn.login(profile[self.SLUG][\"address\"], profile[self.SLUG][\"password\"])\n            conn.select(readonly=(not markRead))\n            (retcode, messages) = conn.search(None, \"(UNSEEN)\")\n        except Exception:\n            logger.warning(\"抱歉，您的邮箱账户验证失败了，请检查下配置\")\n            return None\n\n        if retcode == \"OK\" and messages != [b\"\"]:\n            numUnread = len(messages[0].split(b\" \"))\n            if limit and numUnread > limit:\n                return numUnread\n\n            for num in messages[0].split(b\" \"):\n                # parse email RFC822 format\n                ret, data = conn.fetch(num, \"(RFC822)\")\n                if data is None:\n                    continue\n                msg = email.message_from_string(data[0][1].decode(\"utf-8\"))\n\n                if not since or self.getDate(msg) > since:\n                    msgs.append(msg)\n\n        conn.close()\n        conn.logout()\n\n        return msgs\n\n    def handle(self, text, parsed):\n        msgs = self.fetchUnreadEmails(limit=5)\n\n        if msgs is None:\n            self.say(\"抱歉，您的邮箱账户验证失败了\", cache=True)\n            return\n\n        if isinstance(msgs, int):\n            response = \"您有 %d 封未读邮件\" % msgs\n            self.say(response, cache=True)\n            return\n\n        senders = [str(self.getSender(e)) for e in msgs]\n\n        if not senders:\n            self.say(\"您没有未读邮件，真棒！\", cache=True)\n        elif len(senders) == 1:\n            self.say(f\"您有来自 {senders[0]} 的未读邮件。{self.getSubject(msgs[0])}\")\n        else:\n            response = \"您有 %d 封未读邮件\" % len(senders)\n            unique_senders = list(set(senders))\n            if len(unique_senders) > 1:\n                unique_senders[-1] = \", \" + unique_senders[-1]\n                response += \"。这些邮件的发件人包括：\"\n                response += \" 和 \".join(senders)\n            else:\n                response += \"，邮件都来自 \" + unique_senders[0]\n            self.say(response)\n\n    def isValid(self, text, parsed):\n        return any(word in text for word in [\"邮箱\", \"邮件\"])\n"
  },
  {
    "path": "plugins/Geek.py",
    "content": "# -*- coding: utf-8 -*-\nfrom robot import config, logging\nfrom robot.sdk.AbstractPlugin import AbstractPlugin\n\nlogger = logging.getLogger(__name__)\n\n\nclass Plugin(AbstractPlugin):\n\n    IS_IMMERSIVE = True  # 这是个沉浸式技能\n    SLUG = \"geek\"\n\n    def __init__(self, con):\n        super(Plugin, self).__init__(con)\n        self.silent_count = 0\n\n    def handle(self, text, parsed):\n        if any(word in text for word in [\"开启\", \"激活\", \"开始\", \"进入\", \"打开\"]):\n            self.silent_count = 0\n            self.say(\n                \"进入极客模式\",\n                cache=True,\n                onCompleted=lambda: self.onAsk(self.activeListen(silent=True)),\n            )\n        else:\n            self.say(\"退出极客模式\", cache=True)\n            self.clearImmersive()\n\n    def onAsk(self, input):\n        if input:\n            logger.debug(f\"input: {input}\")\n            self.silent_count = 0\n            self.con.doResponse(input)\n        else:\n            self.silent_count += 1\n            if self.silent_count >= config.get(\"/geek/max_silent_count\", 20):\n                self.say(\"退出极客模式\", cache=True)\n                self.clearImmersive()\n            else:\n                self.onAsk(self.activeListen(silent=True))\n\n    def restore(self):\n        self.onAsk(self.activeListen(silent=True))\n\n    def isValidImmersive(self, text, parsed):\n        return (\n            \"模式\" in text\n            and any(word in text for word in [\"即刻\", \"即可\", \"极客\", \"即客\", \"集团\", \"集客\"])\n            and any(word in text for word in [\"退出\", \"结束\", \"停止\"])\n        )\n\n    def isValid(self, text, parsed):\n        return (\n            \"模式\" in text\n            and any(word in text for word in [\"即刻\", \"即可\", \"即客\", \"集团\", \"极客\", \"集客\"])\n            and any(word in text for word in [\"开启\", \"激活\", \"开始\", \"进入\", \"打开\"])\n        )\n"
  },
  {
    "path": "plugins/Gossip.py",
    "content": "# -*- coding: utf-8 -*-\n# author: wzpan\n# 闲聊一下\n\nimport logging\nfrom robot.sdk.AbstractPlugin import AbstractPlugin\n\nlogger = logging.getLogger(__name__)\n\nENTRY_WORDS = [\"进入\", \"打开\", \"激活\", \"开启\", \"一下\"]\nCLOSE_WORDS = [\"退出\", \"结束\", \"停止\"]\n\n\nclass Plugin(AbstractPlugin):\n\n    IS_IMMERSIVE = True\n\n    def handle(self, text, parsed):\n\n        if \"闲聊一下\" in text or \"进入闲聊\" in text:\n            # 进入闲聊模式\n            self.say(\"好的，已进入闲聊模式\", cache=True)\n        else:\n            self.clearImmersive()  # 去掉沉浸式\n            self.say(\"结束闲聊\", cache=True)\n\n    def isValidImmersive(self, text, parsed):\n        return \"闲聊\" in text and any(word in text for word in CLOSE_WORDS)\n\n    def isValid(self, text, parsed):\n        return \"闲聊\" in text and any(word in text for word in ENTRY_WORDS)\n"
  },
  {
    "path": "plugins/LocalPlayer.py",
    "content": "# -*- coding: utf-8 -*-\nimport os\nimport platform\n\nfrom robot import config, logging\nfrom robot.Player import MusicPlayer\nfrom robot.sdk.AbstractPlugin import AbstractPlugin\n\nlogger = logging.getLogger(__name__)\n\n\nclass Plugin(AbstractPlugin):\n\n    IS_IMMERSIVE = True  # 这是个沉浸式技能\n\n    def __init__(self, con):\n        super(Plugin, self).__init__(con)\n        self.player = None\n        self.song_list = None\n\n    def get_song_list(self, path):\n        if not os.path.exists(path) or not os.path.isdir(path):\n            return []\n        song_list = list(\n            filter(lambda d: d.endswith(\".mp3\") or d.endswith(\"wav\"), os.listdir(path))\n        )\n        return [os.path.join(path, song) for song in song_list]\n\n    def init_music_player(self):\n        self.song_list = self.get_song_list(config.get(\"/LocalPlayer/path\"))\n        if self.song_list == None:\n            logger.error(f\"{self.SLUG} 插件配置有误\", stack_info=True)\n        logger.info(f\"本地音乐列表：{self.song_list}\")\n        return MusicPlayer(self.song_list, self)\n\n    def handle(self, text, parsed):\n        if not self.player:\n            self.player = self.init_music_player()\n        if len(self.song_list) == 0:\n            self.clearImmersive()  # 去掉沉浸式\n            self.say(\"本地音乐目录并没有音乐文件，播放失败\")\n            return\n        if self.nlu.hasIntent(parsed, \"MUSICRANK\"):\n            self.player.play()\n        elif self.nlu.hasIntent(parsed, \"CHANGE_TO_NEXT\"):\n            self.player.next()\n        elif self.nlu.hasIntent(parsed, \"CHANGE_TO_LAST\"):\n            self.player.prev()\n        elif self.nlu.hasIntent(parsed, \"CHANGE_VOL\"):\n            slots = self.nlu.getSlots(parsed, \"CHANGE_VOL\")\n            for slot in slots:\n                if slot[\"name\"] == \"user_d\":\n                    word = self.nlu.getSlotWords(parsed, \"CHANGE_VOL\", \"user_d\")[0]\n                    if word == \"--HIGHER--\":\n                        self.player.turnUp()\n                    else:\n                        self.player.turnDown()\n                    return\n                elif slot[\"name\"] == \"user_vd\":\n                    word = self.nlu.getSlotWords(parsed, \"CHANGE_VOL\", \"user_vd\")[0]\n                    if word == \"--LOUDER--\":\n                        self.player.turnUp()\n                    else:\n                        self.player.turnDown()\n\n        elif self.nlu.hasIntent(parsed, \"CONTINUE\"):\n            logger.info(\"继续播放\")\n            self.player.resume()\n        elif self.nlu.hasIntent(parsed, \"CLOSE_MUSIC\") or self.nlu.hasIntent(\n            parsed, \"PAUSE\"\n        ):\n            logger.info(\"停止播放\")\n            self.player.stop()\n            self.clearImmersive()  # 去掉沉浸式\n        else:\n            self.say(\"没听懂你的意思呢，要停止播放，请说停止播放\")\n            self.player.resume()\n\n    def pause(self):\n        if self.player:\n            system = platform.system()\n            # BigSur 以上 Mac 系统的 pkill 无法正常暂停音频，\n            # 因此改成直接停止播放，不再支持沉浸模式\n            if system == \"Darwin\" and float(platform.mac_ver()[0][:5]) >= 10.16:\n                logger.warning(\"注意：Mac BigSur 以上系统无法正常暂停音频，将停止播放，不支持恢复播放\")\n                self.player.stop()\n                return\n            self.player.pause()\n\n    def restore(self):\n        if self.player and self.player.is_pausing():\n            self.player.resume()\n\n    def isValidImmersive(self, text, parsed):\n        return any(\n            self.nlu.hasIntent(parsed, intent)\n            for intent in [\n                \"CHANGE_TO_LAST\",\n                \"CHANGE_TO_NEXT\",\n                \"CHANGE_VOL\",\n                \"CLOSE_MUSIC\",\n                \"PAUSE\",\n                \"CONTINUE\",\n            ]\n        )\n\n    def isValid(self, text, parsed):\n        return \"本地音乐\" in text\n"
  },
  {
    "path": "plugins/Poem.py",
    "content": "# -*- coding: utf-8 -*-\n# author: wzpan\n# 写诗\n\nimport logging\nfrom robot.sdk.AbstractPlugin import AbstractPlugin\n\nINTENT = \"BUILT_POEM\"\n\nlogger = logging.getLogger(__name__)\n\n\nclass Plugin(AbstractPlugin):\n\n    SLUG = \"poem\"\n\n    def handle(self, text, parsed):\n        try:\n            responds = self.nlu.getSay(parsed, INTENT)\n            self.say(responds, cache=True)\n        except Exception as e:\n            logger.error(e, stack_info=True)\n            self.say(\"抱歉，写诗插件出问题了，请稍后再试\", cache=True)\n\n    def isValid(self, text, parsed):\n        return self.nlu.hasIntent(parsed, INTENT) and \"写\" in text and \"诗\" in text\n"
  },
  {
    "path": "plugins/Reminder.py",
    "content": "# -*- coding: utf-8 -*-\n# author: wzpan\n# 闹钟\n\nimport logging\nimport os\nimport pickle\nimport time\n\nfrom robot import config, constants, utils\nfrom robot.sdk.AbstractPlugin import AbstractPlugin\n\nlogger = logging.getLogger(__name__)\n\nLOCAL_REMINDER = os.path.join(constants.TEMP_PATH, \"reminder.pkl\")\n\n\nclass Plugin(AbstractPlugin):\n    def __init__(self, con):\n        super(Plugin, self).__init__(con)\n\n    def _dump_reminders(self):\n        logger.info(\"写入日程提醒信息\")\n        with open(LOCAL_REMINDER, \"wb\") as f:\n            pickle.dump(self.con.scheduler.get_jobs(), f)\n\n    def alarm(self, remind_time, content, job_id):\n        self.con.player.stop()  # 停止所有音频\n        content = utils.stripPunctuation(content)\n        self.say(\n            f\"现在是{time.strftime('%H:%M:%S', time.localtime(time.time()))}，该{content}了。\"\n            * int(config.get(\"/reminder/repeat\", 3))\n        )\n        # 非周期性提醒，提醒完即删除\n        if \"repeat\" not in remind_time:\n            self.con.scheduler.del_job_by_id(job_id)\n            self._dump_reminders()\n\n    def list_reminder(self, parsed):\n        \"\"\"\n        列举所有的日程\n        \"\"\"\n        logger.info(\"list_reminder\")\n        _jobs = self.con.scheduler.get_jobs()\n        if len(_jobs) == 0:\n            self.say(f\"您当前没有提醒。\", cache=True)\n        elif len(_jobs) > 1:\n            self.say(f\"您当前有{len(_jobs)}个提醒。\", cache=True)\n            index = 0\n            for job in _jobs:\n                self.say(f\"第{index+1}个提醒内容是{job.describe}\")\n                logger.info(f\"index: {index}, job.job_id: {job.job_id}\")\n                index += 1\n        elif len(_jobs) == 1:\n            self.say(f\"您当前有1个提醒。\", cache=True)\n            self.say(f\"提醒内容是{_jobs[0].describe}\")\n\n    def add_reminder(self, parsed):\n        logger.info(\"add_reminder\")\n        remind_times = self.nlu.getSlotWords(parsed, \"SET_REMIND\", \"user_remind_time\")\n        original_times = self.nlu.getSlotOriginalWords(\n            parsed, \"SET_REMIND\", \"user_remind_time\"\n        )\n        contents = self.nlu.getSlotWords(parsed, \"SET_REMIND\", \"user_wild_content\")\n        if len(remind_times) < 0 or \"|\" not in remind_times[0]:\n            self.say(\"添加提醒失败。请说明需要我提醒的时间\", cache=True)\n            return\n        if len(contents) < 0:\n            self.say(\"添加提醒失败。请说明需要我提醒做什么\", cache=True)\n            return\n        remind_time, original_time, content = (\n            remind_times[0],\n            original_times[0],\n            contents[0],\n        )\n        job_id = utils.getTimemStap()\n        job = self.con.scheduler.add_job(\n            remind_time,\n            original_time,\n            content,\n            lambda: self.alarm(remind_time, content, job_id),\n            job_id=job_id,\n        )\n        if job:\n            self._dump_reminders()\n            logger.info(f\"added reminder: {job.describe}, job_id: {job_id}\")\n            self.say(f\"好的，已为您添加提醒：{job.describe}\")\n        else:\n            self.say(\"抱歉，添加提醒失败了\")\n\n    def _assure(self):\n        pick = self.activeListen()\n        if \"不\" in pick:\n            self.say(\"好的。取消删除\", cache=True)\n            return False\n        elif any(yes in pick for yes in (\"是\", \"要\", \"删除\")):\n            return True\n        else:\n            self.say(\"取消删除\", cache=True)\n            return False\n\n    def _ask_which(self):\n        self.say(f\"要删除哪一个提醒呢\", cache=True)\n        pick = self.activeListen()\n        parsed = self.parse(pick)\n        if self.nlu.hasIntent(parsed, \"HASS_INDEX\"):\n            _jobs = self.con.scheduler.get_jobs()\n            index = int(\n                float(\n                    self.nlu.getSlotWords(parsed, \"HASS_INDEX\", \"user_index\")[0].split(\n                        \"|\"\n                    )[0]\n                )\n            )\n            logger.info(f\"用户选择了第{index}个\")\n            if index < 0 or index > len(_jobs):\n                self.say(\"没有找到符合条件的提醒，删除失败\", cache=True)\n                return -1\n            job = _jobs[index - 1]\n            return job.job_id\n        else:\n            self.say(\"没有找到符合条件的提醒，删除失败\", cache=True)\n            return \"\"\n\n    def del_reminder(self, parsed):\n        logger.info(\"del_reminder\")\n        self.list_reminder(parsed)\n        _jobs = self.con.scheduler.get_jobs()\n        if len(_jobs) == 1:\n            self.say(\"要删除这个提醒吗\", cache=True)\n            if self._assure():\n                try:\n                    self.con.scheduler.del_job_by_id(_jobs[0].job_id)\n                    self._dump_reminders()\n                    self.say(\"好的，已删除该提醒\")\n                except Exception as e:\n                    logger.error(f\"删除失败: {e}\")\n                    self.say(\"删除提醒失败\")\n        elif len(_jobs) > 1:\n            job_id = self._ask_which()\n            if job_id:\n                try:\n                    self.con.scheduler.del_job_by_id(job_id)\n                    self._dump_reminders()\n                    self.say(\"好的，已删除该提醒\")\n                except Exception as e:\n                    logger.error(f\"删除失败: {e}\")\n                    self.say(\"删除提醒失败\")\n\n    def handle(self, text, parsed):\n        logger.info(\"Reminder handle\")\n        if self.nlu.hasIntent(parsed, \"CHECK_REMIND\"):\n            # 查询当前设置的提醒\n            self.list_reminder(parsed)\n        elif self.nlu.hasIntent(parsed, \"DELETE_REMIND\"):\n            # 删除指定的提醒\n            self.del_reminder(parsed)\n        elif self.nlu.hasIntent(parsed, \"SET_REMIND\"):\n            # 设置提醒\n            self.add_reminder(parsed)\n\n    def isValid(self, text, parsed):\n        return any(\n            self.nlu.hasIntent(parsed, intent)\n            for intent in [\"CHECK_REMIND\", \"DELETE_REMIND\", \"SET_REMIND\"]\n        )\n"
  },
  {
    "path": "plugins/Volume.py",
    "content": "# -*- coding: utf-8 -*-\nfrom robot.Player import MusicPlayer\nfrom robot import logging\nfrom robot.sdk.AbstractPlugin import AbstractPlugin\n\nlogger = logging.getLogger(__name__)\n\n\nclass Plugin(AbstractPlugin):\n    def __init__(self, con):\n        super(Plugin, self).__init__(con)\n        self.player = None\n\n    def handle(self, text, parsed):\n        if not self.player:\n            self.player = MusicPlayer([], self)\n        if self.nlu.hasIntent(parsed, \"CHANGE_VOL\"):\n            slots = self.nlu.getSlots(parsed, \"CHANGE_VOL\")\n            for slot in slots:\n                if slot[\"name\"] == \"user_d\":\n                    word = self.nlu.getSlotWords(parsed, \"CHANGE_VOL\", \"user_d\")[0]\n                    if word == \"--HIGHER--\":\n                        self.player.turnUp()\n                        self.say(\"好的\", cache=True)\n                    else:\n                        self.player.turnDown()\n                        self.say(\"好的\", cache=True)\n                    return\n                elif slot[\"name\"] == \"user_vd\":\n                    word = self.nlu.getSlotWords(parsed, \"CHANGE_VOL\", \"user_vd\")[0]\n                    if word == \"--LOUDER--\":\n                        self.player.turnUp()\n                        self.say(\"好的\", cache=True)\n                    else:\n                        self.player.turnDown()\n                        self.say(\"好的\", cache=True)\n\n    def isValid(self, text, parsed):\n        return self.nlu.hasIntent(parsed, \"CHANGE_VOL\")\n"
  },
  {
    "path": "plugins/__init__.py",
    "content": ""
  },
  {
    "path": "requirements.txt",
    "content": "pyyaml>=4.2b1\nrequests==2.31.0\nbaidu-aip==2.0.0.1\npydub==0.23.1\npython-dateutil==2.7.5\nwatchdog==0.9.0\npytz==2018.9\nfire==0.1.3\ntornado==6.3.3\nmarkdown==3.0.1\nsemver==2.8.1\nwebsocket==0.2.1\nwebsocket-client\npypinyin\njieba\npvporcupine\npvrecorder==1.1.1\nopenai\napscheduler\nasyncio\nedge-tts\nnest_asyncio\nfunasr_onnx\n"
  },
  {
    "path": "robot/AI.py",
    "content": "# -*- coding: utf-8 -*-\nimport os\nimport json\nimport random\nimport requests\n\nfrom uuid import getnode as get_mac\nfrom abc import ABCMeta, abstractmethod\nfrom robot import logging, config, utils\nfrom robot.sdk import unit\n\nlogger = logging.getLogger(__name__)\n\n\nclass AbstractRobot(object):\n\n    __metaclass__ = ABCMeta\n\n    @classmethod\n    def get_instance(cls):\n        profile = cls.get_config()\n        instance = cls(**profile)\n        return instance\n\n    def __init__(self, **kwargs):\n        pass\n\n    @abstractmethod\n    def chat(self, texts, parsed):\n        pass\n\n    @abstractmethod\n    def stream_chat(self, texts):\n        pass\n\n\nclass TulingRobot(AbstractRobot):\n\n    SLUG = \"tuling\"\n\n    def __init__(self, tuling_key):\n        \"\"\"\n        图灵机器人\n        \"\"\"\n        super(self.__class__, self).__init__()\n        self.tuling_key = tuling_key\n\n    @classmethod\n    def get_config(cls):\n        return config.get(\"tuling\", {})\n\n    def chat(self, texts, parsed=None):\n        \"\"\"\n        使用图灵机器人聊天\n\n        Arguments:\n        texts -- user input, typically speech, to be parsed by a module\n        \"\"\"\n        msg = \"\".join(texts)\n        msg = utils.stripPunctuation(msg)\n        try:\n            url = \"http://openapi.turingapi.com/openapi/api/v2\"\n            userid = str(get_mac())[:32]\n            body = {\n                \"perception\": {\"inputText\": {\"text\": msg}},\n                \"userInfo\": {\"apiKey\": self.tuling_key, \"userId\": userid},\n            }\n            r = requests.post(url, json=body)\n            respond = json.loads(r.text)\n            result = \"\"\n            if \"results\" in respond:\n                for res in respond[\"results\"]:\n                    result += \"\\n\".join(res[\"values\"].values())\n            else:\n                result = \"图灵机器人服务异常，请联系作者\"\n            logger.info(f\"{self.SLUG} 回答：{result}\")\n            return result\n        except Exception:\n            logger.critical(\n                \"Tuling robot failed to response for %r\", msg, exc_info=True\n            )\n            return \"抱歉, 图灵机器人服务回答失败\"\n\n\nclass UnitRobot(AbstractRobot):\n\n    SLUG = \"unit\"\n\n    def __init__(self):\n        \"\"\"\n        百度UNIT机器人\n        \"\"\"\n        super(self.__class__, self).__init__()\n\n    @classmethod\n    def get_config(cls):\n        return {}\n\n    def chat(self, texts, parsed):\n        \"\"\"\n        使用百度UNIT机器人聊天\n\n        Arguments:\n        texts -- user input, typically speech, to be parsed by a module\n        \"\"\"\n        msg = \"\".join(texts)\n        msg = utils.stripPunctuation(msg)\n        try:\n            result = unit.getSay(parsed)\n            logger.info(\"{} 回答：{}\".format(self.SLUG, result))\n            return result\n        except Exception:\n            logger.critical(\"UNIT robot failed to response for %r\", msg, exc_info=True)\n            return \"抱歉, 百度UNIT服务回答失败\"\n\n\nclass BingRobot(AbstractRobot):\n\n    SLUG = \"bing\"\n\n    def __init__(self, prefix, proxy, mode):\n        \"\"\"\n        bing\n        \"\"\"\n        super(self.__class__, self).__init__()\n        self.prefix = prefix\n        self.proxy = proxy\n        self.mode = mode\n\n    @classmethod\n    def get_config(cls):\n        return config.get(\"bing\", {})\n\n    def chat(self, texts, parsed):\n        \"\"\"\n\n        Arguments:\n        texts -- user input, typically speech, to be parsed by a module\n        \"\"\"\n        msg = \"\".join(texts)\n        msg = utils.stripPunctuation(msg)\n        try:\n            import asyncio, json\n            from EdgeGPT.EdgeGPT import Chatbot, ConversationStyle\n\n            async def query_bing():\n                # Passing cookies is \"optional\"\n                bot = await Chatbot.create(proxy=self.proxy) \n                m2s = {\n                    \"creative\": ConversationStyle.creative,\n                    \"balanced\": ConversationStyle.balanced,\n                    \"precise\": ConversationStyle.precise\n                }\n                response = await bot.ask(prompt=self.prefix + \"\\n\" + msg,\n                                         conversation_style=m2s[self.mode],\n                                         simplify_response=True)\n                #print(json.dumps(response, indent=2)) # Returns\n                return response[\"text\"]\n                await bot.close()\n\n            result = asyncio.run(query_bing())\n\n            logger.info(\"{} 回答：{}\".format(self.SLUG, result))\n            return result\n        except Exception:\n            logger.critical(\"bing robot failed to response for %r\", msg, exc_info=True)\n            return \"抱歉, bing回答失败\"\n\n\nclass AnyQRobot(AbstractRobot):\n\n    SLUG = \"anyq\"\n\n    def __init__(self, host, port, solr_port, threshold, secondary):\n        \"\"\"\n        AnyQ机器人\n        \"\"\"\n        super(self.__class__, self).__init__()\n        self.host = host\n        self.threshold = threshold\n        self.port = port\n        self.secondary = secondary\n\n    @classmethod\n    def get_config(cls):\n        # Try to get anyq config from config\n        return config.get(\"anyq\", {})\n\n    def chat(self, texts, parsed):\n        \"\"\"\n        使用AnyQ机器人聊天\n\n        Arguments:\n        texts -- user input, typically speech, to be parsed by a module\n        \"\"\"\n        msg = \"\".join(texts)\n        msg = utils.stripPunctuation(msg)\n        try:\n            url = f\"http://{self.host}:{self.port}/anyq?question={msg}\"\n            r = requests.get(url)\n            respond = json.loads(r.text)\n            logger.info(f\"anyq response: {respond}\")\n            if len(respond) > 0:\n                # 有命中，进一步判断 confidence 是否达到要求\n                confidence = respond[0][\"confidence\"]\n                if confidence >= self.threshold:\n                    # 命中该问题，返回回答\n                    answer = respond[0][\"answer\"]\n                    if utils.validjson(answer):\n                        answer = random.choice(json.loads(answer))\n                    logger.info(f\"{self.SLUG} 回答：{answer}\")\n                    return answer\n            # 没有命中，走兜底\n            if self.secondary != \"null\" and self.secondary:\n                try:\n                    ai = get_robot_by_slug(self.secondary)\n                    return ai.chat(texts, parsed)\n                except Exception:\n                    logger.critical(\n                        f\"Secondary robot {self.secondary} failed to response for {msg}\"\n                    )\n                    return get_unknown_response()\n            else:\n                return get_unknown_response()\n        except Exception:\n            logger.critical(\"AnyQ robot failed to response for %r\", msg, exc_info=True)\n            return \"抱歉, AnyQ回答失败\"\n\nclass OPENAIRobot(AbstractRobot):\n\n    SLUG = \"openai\"\n\n    def __init__(\n        self,\n        openai_api_key,\n        model,\n        provider,\n        api_version,\n        temperature,\n        max_tokens,\n        top_p,\n        frequency_penalty,\n        presence_penalty,\n        stop_ai,\n        prefix=\"\",\n        proxy=\"\",\n        api_base=\"\",\n    ):\n        \"\"\"\n        OpenAI机器人\n        \"\"\"\n        super(self.__class__, self).__init__()\n        self.openai = None\n        try:\n            import openai\n\n            self.openai = openai\n            if not openai_api_key:\n                openai_api_key = os.getenv(\"OPENAI_API_KEY\")\n            self.openai.api_key = openai_api_key\n            if proxy:\n                logger.info(f\"{self.SLUG} 使用代理：{proxy}\")\n                self.openai.proxy = proxy\n            else:\n                self.openai.proxy = None\n\n        except Exception:\n            logger.critical(\"OpenAI 初始化失败，请升级 Python 版本至 > 3.6\")\n        self.model = model\n        self.prefix = prefix\n        self.provider = provider\n        self.api_version = api_version\n        self.temperature = temperature\n        self.max_tokens = max_tokens\n        self.top_p = top_p\n        self.frequency_penalty = frequency_penalty\n        self.presence_penalty = presence_penalty\n        self.stop_ai = stop_ai\n        self.api_base = api_base if api_base else \"https://api.openai.com/v1/chat\"\n        self.context = []\n\n    @classmethod\n    def get_config(cls):\n        # Try to get anyq config from config\n        return config.get(\"openai\", {})\n\n    def stream_chat(self, texts):\n        \"\"\"\n        从ChatGPT API获取回复\n        :return: 回复\n        \"\"\"\n\n        msg = \"\".join(texts)\n        msg = utils.stripPunctuation(msg)\n        msg = self.prefix + msg  # 增加一段前缀\n        logger.info(\"msg: \" + msg)\n        self.context.append({\"role\": \"user\", \"content\": msg})\n\n        header = {\n            \"Content-Type\": \"application/json\",\n            # \"Authorization\": \"Bearer \" + self.openai.api_key\n        }\n        if self.provider == 'openai':\n            header['Authorization'] = \"Bearer \" + self.openai.api_key\n        elif self.provider == 'azure':\n            header['api-key'] = self.openai.api_key\n        else:\n            raise ValueError(\"Please check your config file, OpenAiRobot's provider should be openai or azure.\")\n\n        data = {\"model\": self.model, \"messages\": self.context, \"stream\": True}\n        logger.info(f\"使用模型：{self.model}，开始流式请求\")\n        url = self.api_base + \"/completions\"\n        if self.provider == 'azure':\n            url = f\"{self.api_base}/openai/deployments/{self.model}/chat/completions?api-version={self.api_version}\"\n        # 请求接收流式数据\n        try:\n            response = requests.request(\n                \"POST\",\n                url,\n                headers=header,\n                json=data,\n                stream=True,\n                proxies={\"https\": self.openai.proxy},\n            )\n\n            def generate():\n                stream_content = str()\n                one_message = {\"role\": \"assistant\", \"content\": stream_content}\n                self.context.append(one_message)\n                i = 0\n                for line in response.iter_lines():\n                    line_str = str(line, encoding=\"utf-8\")\n                    if line_str.startswith(\"data:\") and line_str[5:]:\n                        if line_str.startswith(\"data: [DONE]\"):\n                            break\n                        line_json = json.loads(line_str[5:])\n                        if \"choices\" in line_json:\n                            if len(line_json[\"choices\"]) > 0:\n                                choice = line_json[\"choices\"][0]\n                                if \"delta\" in choice:\n                                    delta = choice[\"delta\"]\n                                    if \"role\" in delta:\n                                        role = delta[\"role\"]\n                                    elif \"content\" in delta:\n                                        delta_content = delta[\"content\"]\n                                        i += 1\n                                        if i < 40:\n                                            logger.debug(delta_content, end=\"\")\n                                        elif i == 40:\n                                            logger.debug(\"......\")\n                                        one_message[\"content\"] = (\n                                            one_message[\"content\"] + delta_content\n                                        )\n                                        yield delta_content\n\n                    elif len(line_str.strip()) > 0:\n                        logger.debug(line_str)\n                        yield line_str\n\n        except Exception as e:\n            ee = e\n\n            def generate():\n                yield \"request error:\\n\" + str(ee)\n\n        return generate\n\n    def chat(self, texts, parsed):\n        \"\"\"\n        使用OpenAI机器人聊天\n\n        Arguments:\n        texts -- user input, typically speech, to be parsed by a module\n        \"\"\"\n        msg = \"\".join(texts)\n        msg = utils.stripPunctuation(msg)\n        msg = self.prefix + msg  # 增加一段前缀\n        logger.info(\"msg: \" + msg)\n        try:\n            respond = \"\"\n            self.context.append({\"role\": \"user\", \"content\": msg})\n            if self.provider == \"openai\":\n                response = self.openai.Completion.create(\n                    model=self.model,\n                    messages=self.context,\n                    temperature=self.temperature,\n                    max_tokens=self.max_tokens,\n                    top_p=self.top_p,\n                    frequency_penalty=self.frequency_penalty,\n                    presence_penalty=self.presence_penalty,\n                    stop=self.stop_ai,\n                    api_base=self.api_base\n                )\n            else:\n                from openai import AzureOpenAI\n                client = AzureOpenAI(\n                            azure_endpoint = self.api_base, \n                            api_key=self.openai_api_key,  \n                            api_version=self.api_version\n                            )\n                response = client.chat.completions.create(\n                    model=self.model,\n                    messages=self.context\n                )\n            message = response.choices[0].message\n            respond = message.content\n            self.context.append(message)\n            return respond\n        except self.openai.error.InvalidRequestError:\n            logger.warning(\"token超出长度限制，丢弃历史会话\")\n            self.context = []\n            return self.chat(texts, parsed)\n        except Exception:\n            logger.critical(\n                \"openai robot failed to response for %r\", msg, exc_info=True\n            )\n            return \"抱歉，OpenAI 回答失败\"\n\nclass WenxinRobot(AbstractRobot):\n    \n    SLUG = \"wenxin\"\n\n    def __init__(self, api_key, secret_key):\n        \"\"\"\n        Wenxin机器人\n        \"\"\"\n        super(self.__class__, self).__init__()\n        self.api_key = api_key\n        self.secret_key = secret_key\n        \n    @classmethod\n    def get_config(cls):\n        return config.get(\"wenxin\", {})\n\n    def chat(self, texts, _):\n        \"\"\"\n        使用Wenxin机器人聊天\n\n        Arguments:\n        texts -- user input, typically speech, to be parsed by a module\n        \"\"\"\n        msg = \"\".join(texts)\n        msg = utils.stripPunctuation(msg)\n        wenxinurl = f\"https://aip.baidubce.com/oauth/2.0/token?client_id={self.api_key}&\\\n                    client_secret={self.secret_key}&grant_type=client_credentials\"\n        try:\n            headers = {\n                \"Content-Type\": \"application/json\",\n                \"Accept\": \"application/json\",\n                }\n            payload = json.dumps({\n                \"question\": [\n                    {\n                        \"role\": \"user\",\n                        \"content\": msg,\n                    }\n                ]\n                })\n            response = requests.request(\"POST\", wenxinurl, headers=headers)\n            logger.info(f\"wenxin response: {response}\")\n            return response.text\n        \n        except Exception:\n            logger.critical(\"Wenxin robot failed to response for %r\", msg, exc_info=True)\n            return \"抱歉, Wenxin回答失败\"\n\nclass TongyiRobot(AbstractRobot):\n        '''\n        usage:\n        pip install dashscope\n        echo \"export DASHSCOPE_API_KEY=YOUR_KEY\" >> /.bashrc\n        '''\n        SLUG = \"tongyi\"\n    \n        def __init__(self, api_key):\n            \"\"\"\n            Tongyi机器人\n            \"\"\"\n            super(self.__class__, self).__init__()\n            self.api_key = api_key\n            \n        @classmethod\n        def get_config(cls):\n            return config.get(\"tongyi\", {})\n    \n        def chat(self, texts, _):\n            \"\"\"\n            使用Tongyi机器人聊天\n    \n            Arguments:\n            texts -- user input, typically speech, to be parsed by a module\n            \"\"\"\n            msg = \"\".join(texts)\n            msg = utils.stripPunctuation(msg)\n            msg = [{\"role\": \"user\", \"content\": msg}]\n            try:\n                response = dashscope.Generation.call(\n                    model='qwen1.5-72b-chat',\n                    messages=msg,\n                    result_format='message',  # set the result to be \"message\" format.\n                )\n                logger.info(f\"tongyi response: {response}\")\n                return response['output']['choices'][0]['message']['content']\n            \n            except Exception:\n                logger.critical(\"Tongyi robot failed to response for %r\", msg, exc_info=True)\n                return \"抱歉, Tongyi回答失败\"\n\nclass CozeRobot(AbstractRobot):\n    SLUG = \"coze\"\n\n    def __init__(self, botid, token, **kwargs):\n        super(self.__class__, self).__init__()\n        self.botid = botid\n        self.token = token\n        self.userid = str(get_mac())[:32]\n\n    @classmethod\n    def get_config(cls):\n        return config.get(\"coze\", {})\n\n    def chat(self, texts, parsed=None):\n        \"\"\"\n        使用coze聊天\n\n        Arguments:\n        texts -- user input, typically speech, to be parsed by a module\n        \"\"\"\n        msg = \"\".join(texts)\n        msg = utils.stripPunctuation(msg)\n        try:\n            url = \"https://api.coze.cn/open_api/v2/chat\"\n            \n            body = {\n                \"conversation_id\": \"123\",\n                \"bot_id\": self.botid,\n                \"user\": self.userid,\n                \"query\": msg,\n                \"stream\": False\n            }\n            headers = {\n                \"Authorization\": \"Bearer \" + self.token,\n                \"Content-Type\": \"application/json\",\n                \"Accept\": \"*/*\",\n                \"Host\": \"api.coze.cn\",\n                \"Connection\": \"keep-alive\"\n            }\n            r = requests.post(url, headers=headers, json=body)\n            respond = json.loads(r.text)\n            result = \"\"\n            logger.info(f\"{self.SLUG} 回答：{respond}\")\n            if \"messages\" in respond:\n                for m in respond[\"messages\"]:\n                    if m[\"type\"] == \"answer\":\n                        result = m[\"content\"].replace(\"\\n\", \"\").replace(\"\\r\", \"\")\n            else:\n                result = \"抱歉，扣子回答失败\"\n            if result == \"\":\n                result = \"抱歉，扣子回答失败\"\n            logger.info(f\"{self.SLUG} 回答：{result}\")\n            return result\n        except Exception:\n            logger.critical(\n                \"Tuling robot failed to response for %r\", msg, exc_info=True\n            )\n            return \"抱歉, 扣子回答失败\"\n\ndef get_unknown_response():\n    \"\"\"\n    不知道怎么回答的情况下的答复\n\n    :returns: 表示不知道的答复\n    \"\"\"\n    results = [\"抱歉，我不会这个呢\", \"我不会这个呢\", \"我还不会这个呢\", \"我还没学会这个呢\", \"对不起，你说的这个，我还不会\"]\n    return random.choice(results)\n\n\ndef get_robot_by_slug(slug):\n    \"\"\"\n    Returns:\n        A robot implementation available on the current platform\n    \"\"\"\n    if not slug or type(slug) is not str:\n        raise TypeError(\"Invalid slug '%s'\", slug)\n\n    selected_robots = list(\n        filter(\n            lambda robot: hasattr(robot, \"SLUG\") and robot.SLUG == slug, get_robots()\n        )\n    )\n    if len(selected_robots) == 0:\n        raise ValueError(\"No robot found for slug '%s'\" % slug)\n    else:\n        if len(selected_robots) > 1:\n            logger.warning(\n                \"WARNING: Multiple robots found for slug '%s'. \"\n                + \"This is most certainly a bug.\" % slug\n            )\n        robot = selected_robots[0]\n        logger.info(f\"使用 {robot.SLUG} 对话机器人\")\n        return robot.get_instance()\n\n\ndef get_robots():\n    def get_subclasses(cls):\n        subclasses = set()\n        for subclass in cls.__subclasses__():\n            subclasses.add(subclass)\n            subclasses.update(get_subclasses(subclass))\n        return subclasses\n\n    return [\n        robot\n        for robot in list(get_subclasses(AbstractRobot))\n        if hasattr(robot, \"SLUG\") and robot.SLUG\n    ]\n"
  },
  {
    "path": "robot/ASR.py",
    "content": "# -*- coding: utf-8 -*-\nimport json\nfrom aip import AipSpeech\nfrom .sdk import TencentSpeech, AliSpeech, XunfeiSpeech, BaiduSpeech, FunASREngine, VolcengineSpeech\nfrom . import utils, config\nfrom robot import logging\nfrom abc import ABCMeta, abstractmethod\nimport requests\n\nlogger = logging.getLogger(__name__)\n\n\nclass AbstractASR(object):\n    \"\"\"\n    Generic parent class for all ASR engines\n    \"\"\"\n\n    __metaclass__ = ABCMeta\n\n    @classmethod\n    def get_config(cls):\n        return {}\n\n    @classmethod\n    def get_instance(cls):\n        profile = cls.get_config()\n        instance = cls(**profile)\n        return instance\n\n    @abstractmethod\n    def transcribe(self, fp):\n        pass\n\n\nclass AzureASR(AbstractASR):\n    \"\"\"\n    微软的语音识别API\n    \"\"\"\n\n    SLUG = \"azure-asr\"\n\n    def __init__(self, secret_key, region, lang=\"zh-CN\", **args):\n        super(self.__class__, self).__init__()\n        self.post_url = \"https://<REGION_IDENTIFIER>.stt.speech.microsoft.com/speech/recognition/conversation/cognitiveservices/v1\".replace(\n            \"<REGION_IDENTIFIER>\", region\n        )\n\n        self.post_header = {\n            \"Ocp-Apim-Subscription-Key\": secret_key,\n            \"Content-Type\": \"audio/wav; codecs=audio/pcm; samplerate=16000\",\n            \"Accept\": \"application/json\",\n        }\n\n        self.post_param = {\"language\": lang, \"profanity\": \"raw\"}\n        self.sess = requests.session()\n\n    @classmethod\n    def get_config(cls):\n        # Try to get azure_yuyin config from config\n        return config.get(\"azure_yuyin\", {})\n\n    def transcribe(self, fp):\n        # 识别本地文件\n        pcm = utils.get_pcm_from_wav(fp)\n        ret = self.sess.post(\n            url=self.post_url,\n            data=pcm,\n            headers=self.post_header,\n            params=self.post_param,\n        )\n\n        if ret.status_code == 200:\n            res = ret.json()\n            logger.info(f\"{self.SLUG} 语音识别到了：{res['DisplayText']}\")\n            return \"\".join(res[\"DisplayText\"])\n        else:\n            logger.info(f\"{self.SLUG} 语音识别出错了: {res.text}\")\n            return \"\"\n\n\nclass BaiduASR(AbstractASR):\n    \"\"\"\n    百度的语音识别API.\n    dev_pid:\n        - 1936: 普通话远场\n        - 1536：普通话(支持简单的英文识别)\n        - 1537：普通话(纯中文识别)\n        - 1737：英语\n        - 1637：粤语\n        - 1837：四川话\n    要使用本模块, 首先到 yuyin.baidu.com 注册一个开发者账号,\n    之后创建一个新应用, 然后在应用管理的\"查看key\"中获得 API Key 和 Secret Key\n    填入 config.xml 中.\n    ...\n        baidu_yuyin:\n            appid: '9670645'\n            api_key: 'qg4haN8b2bGvFtCbBGqhrmZy'\n            secret_key: '585d4eccb50d306c401d7df138bb02e7'\n        ...\n    \"\"\"\n\n    SLUG = \"baidu-asr\"\n\n    def __init__(self, appid, api_key, secret_key, dev_pid=1936, **args):\n        super(self.__class__, self).__init__()\n        if dev_pid != 80001:\n            self.client = AipSpeech(appid, api_key, secret_key)\n        else:\n            self.client = BaiduSpeech.baiduSpeech(api_key, secret_key, dev_pid)\n        self.dev_pid = dev_pid\n\n    @classmethod\n    def get_config(cls):\n        # Try to get baidu_yuyin config from config\n        return config.get(\"baidu_yuyin\", {})\n\n    def transcribe(self, fp):\n        # 识别本地文件\n        pcm = utils.get_pcm_from_wav(fp)\n        res = self.client.asr(pcm, \"pcm\", 16000, {\"dev_pid\": self.dev_pid})\n        if res[\"err_no\"] == 0:\n            logger.info(f\"{self.SLUG} 语音识别到了：{res['result']}\")\n            return \"\".join(res[\"result\"])\n        else:\n            logger.info(f\"{self.SLUG} 语音识别出错了: {res['err_msg']}\")\n            if res[\"err_msg\"] == \"request pv too much\":\n                logger.info(\"       出现这个原因很可能是你的百度语音服务调用量超出限制，或未开通付费\")\n            return \"\"\n\n\nclass TencentASR(AbstractASR):\n    \"\"\"\n    腾讯的语音识别API.\n    \"\"\"\n\n    SLUG = \"tencent-asr\"\n\n    def __init__(self, appid, secretid, secret_key, region=\"ap-guangzhou\", **args):\n        super(self.__class__, self).__init__()\n        self.engine = TencentSpeech.tencentSpeech(secret_key, secretid)\n        self.region = region\n\n    @classmethod\n    def get_config(cls):\n        # Try to get tencent_yuyin config from config\n        return config.get(\"tencent_yuyin\", {})\n\n    def transcribe(self, fp):\n        mp3_path = utils.convert_wav_to_mp3(fp)\n        r = self.engine.ASR(mp3_path, \"mp3\", \"1\", self.region)\n        utils.check_and_delete(mp3_path)\n        res = json.loads(r)\n        if \"Response\" in res and \"Result\" in res[\"Response\"]:\n            logger.info(f\"{self.SLUG} 语音识别到了：{res['Response']['Result']}\")\n            return res[\"Response\"][\"Result\"]\n        else:\n            logger.critical(f\"{self.SLUG} 语音识别出错了: {res}\", stack_info=True)\n            return \"\"\n\n\nclass XunfeiASR(AbstractASR):\n    \"\"\"\n    科大讯飞的语音识别API.\n    外网ip查询：https://ip.51240.com/\n    \"\"\"\n\n    SLUG = \"xunfei-asr\"\n\n    def __init__(self, appid, api_key, api_secret, **args):\n        super(self.__class__, self).__init__()\n        self.appid = appid\n        self.api_key = api_key\n        self.api_secret = api_secret\n\n    @classmethod\n    def get_config(cls):\n        # Try to get xunfei_yuyin config from config\n        return config.get(\"xunfei_yuyin\", {})\n\n    def transcribe(self, fp):\n        return XunfeiSpeech.transcribe(fp, self.appid, self.api_key, self.api_secret)\n\n\nclass AliASR(AbstractASR):\n    \"\"\"\n    阿里的语音识别API.\n    \"\"\"\n\n    SLUG = \"ali-asr\"\n\n    def __init__(self, appKey, token, **args):\n        super(self.__class__, self).__init__()\n        self.appKey, self.token = appKey, token\n\n    @classmethod\n    def get_config(cls):\n        # Try to get ali_yuyin config from config\n        return config.get(\"ali_yuyin\", {})\n\n    def transcribe(self, fp):\n        result = AliSpeech.asr(self.appKey, self.token, fp)\n        if result:\n            logger.info(f\"{self.SLUG} 语音识别到了：{result}\")\n            return result\n        else:\n            logger.critical(f\"{self.SLUG} 语音识别出错了\", stack_info=True)\n            return \"\"\n\n\nclass WhisperASR(AbstractASR):\n    \"\"\"\n    OpenAI 的 whisper 语音识别API\n    \"\"\"\n\n    SLUG = \"openai\"\n\n    def __init__(self, openai_api_key, **args):\n        super(self.__class__, self).__init__()\n        try:\n            import openai\n\n            self.openai = openai\n            self.openai.api_key = openai_api_key\n            print(openai_api_key)\n        except Exception:\n            logger.critical(\"OpenAI 初始化失败，请升级 Python 版本至 > 3.6\")\n\n    @classmethod\n    def get_config(cls):\n        return config.get(\"openai\", {})\n\n    def transcribe(self, fp):\n        if self.openai:\n            try:\n                with open(fp, \"rb\") as f:\n                    result = self.openai.Audio.transcribe(\"whisper-1\", f)\n                    if result:\n                        logger.info(f\"{self.SLUG} 语音识别到了：{result.text}\")\n                        return result.text\n            except Exception:\n                logger.critical(f\"{self.SLUG} 语音识别出错了\", stack_info=True)\n                return \"\"\n        logger.critical(f\"{self.SLUG} 语音识别出错了\", stack_info=True)\n        return \"\"\n\nclass FunASR(AbstractASR):\n    \"\"\"\n    达摩院FunASR实时语音转写服务软件包\n    \"\"\"\n\n    SLUG = \"fun-asr\"\n\n    def __init__(self, inference_type, model_dir, **args):\n        super(self.__class__, self).__init__()\n        self.engine = FunASREngine.funASREngine(inference_type, model_dir)\n\n    @classmethod\n    def get_config(cls):\n        return config.get(\"fun_asr\", {})\n\n    def transcribe(self, fp):\n        result = self.engine(fp)\n        if result:\n            logger.info(f\"{self.SLUG} 语音识别到了：{result}\")\n            return result\n        else:\n            logger.critical(f\"{self.SLUG} 语音识别出错了\", stack_info=True)\n            return \"\"\n\nclass VolcengineASR(AbstractASR):\n    \"\"\"\n    VolcengineASR 实时语音转写服务软件包\n    \"\"\"\n\n    SLUG = \"volcengine-asr\"\n\n    def __init__(self, **kargs):\n        super(self.__class__, self).__init__()\n        self.volcengine_asr = VolcengineSpeech.VolcengineASR(**kargs)\n\n    @classmethod\n    def get_config(cls):\n        return config.get(\"volcengine-asr\", {})\n\n    def transcribe(self, fp):\n        result = self.volcengine_asr.execute(fp)\n        if result:\n            logger.info(f\"{self.SLUG} 语音识别到了：{result}\")\n            return result\n        else:\n            logger.critical(f\"{self.SLUG} 语音识别出错了\", stack_info=True)\n            return \"\"\n\ndef get_engine_by_slug(slug=None):\n    \"\"\"\n    Returns:\n        An ASR Engine implementation available on the current platform\n\n    Raises:\n        ValueError if no speaker implementation is supported on this platform\n    \"\"\"\n\n    if not slug or type(slug) is not str:\n        raise TypeError(\"无效的 ASR slug '%s'\", slug)\n\n    selected_engines = list(\n        filter(\n            lambda engine: hasattr(engine, \"SLUG\") and engine.SLUG == slug,\n            get_engines(),\n        )\n    )\n\n    if len(selected_engines) == 0:\n        raise ValueError(f\"错误：找不到名为 {slug} 的 ASR 引擎\")\n    else:\n        if len(selected_engines) > 1:\n            logger.warning(f\"注意: 有多个 ASR 名称与指定的引擎名 {slug} 匹配\")\n        engine = selected_engines[0]\n        logger.info(f\"使用 {engine.SLUG} ASR 引擎\")\n        return engine.get_instance()\n\n\ndef get_engines():\n    def get_subclasses(cls):\n        subclasses = set()\n        for subclass in cls.__subclasses__():\n            subclasses.add(subclass)\n            subclasses.update(get_subclasses(subclass))\n        return subclasses\n\n    return [\n        engine\n        for engine in list(get_subclasses(AbstractASR))\n        if hasattr(engine, \"SLUG\") and engine.SLUG\n    ]\n"
  },
  {
    "path": "robot/BCI.py",
    "content": "import importlib\nimport multiprocessing\nfrom robot import config, logging\nfrom datetime import datetime, timedelta\n\nlogger = logging.getLogger(__name__)\n\n\nclass MuseBCI(object):\n    def __init__(self, event):\n        self._wakeup_event = event\n        self.last_blink = datetime.now() - timedelta(days=1.5)\n        self.last_jaw = datetime.now() - timedelta(days=1.5)\n\n    def start(self):\n        osc_process = multiprocessing.Process(target=self._start_osc)\n        osc_process.start()\n\n    def blink_handler(self, unused_addr, args, blink):\n        if blink:\n            logger.info(\"blink detected\")\n            self.last_blink = datetime.now()\n            if (self.last_blink - self.last_jaw) <= timedelta(seconds=1):\n                self._wakeup_event.set()\n\n    def jaw_clench_handler(self, unused_addr, args, jaw):\n        if jaw:\n            logger.info(\"Jaw_Clench detected\")\n            self.last_jaw = datetime.now()\n            if (self.last_jaw - self.last_blink) <= timedelta(seconds=1):\n                self._wakeup_event.set()\n\n    def _start_osc(self):\n        if not importlib.util.find_spec(\"pythonosc\"):\n            logger.critical(\"错误：请先安装 python-osc ！\")\n            return\n\n        from pythonosc import dispatcher as dsp\n        from pythonosc import osc_server\n\n        dispatcher = dsp.Dispatcher()\n        dispatcher.map(\"/muse/elements/blink\", self.blink_handler, \"EEG\")\n        dispatcher.map(\"/muse/elements/jaw_clench\", self.jaw_clench_handler, \"EEG\")\n\n        try:\n            server = osc_server.ThreadingOSCUDPServer(\n                (\n                    config.get(\"/muse/ip\", \"127.0.0.1\"),\n                    int(config.get(\"/muse/port\", \"5001\")),\n                ),\n                dispatcher,\n            )\n            logger.info(f\"Muse serving on {server.server_address}\")\n            server.serve_forever()\n        except Exception as e:\n            logger.error(e, stack_info=True)\n"
  },
  {
    "path": "robot/Brain.py",
    "content": "# -*- coding: utf-8 -*-\nimport re\nimport traceback\n\nfrom robot import config\nfrom robot import logging\nfrom . import plugin_loader\n\nlogger = logging.getLogger(__name__)\n\n\nclass Brain(object):\n    def __init__(self, conversation):\n        \"\"\"\n        大脑模块，负责处理技能的匹配和响应\n\n        参数：\n        conversation -- 管理对话\n        \"\"\"\n        self.conversation = conversation\n        self.plugins = plugin_loader.get_plugins(self.conversation)\n        self.handling = False\n\n    def match(self, patterns, text):\n        for pattern in patterns:\n            if re.match(pattern, text):\n                return True\n        return False\n\n    def isValid(self, plugin, text, parsed):\n        patterns = config.get(f\"/{plugin.SLUG}/patterns\", [])\n        if len(patterns) > 0:\n            return plugin.isValid(text, parsed) or self.match(patterns, text)\n        else:\n            return plugin.isValid(text, parsed)\n\n    def isValidImmersive(self, plugin, text, parsed):\n        patterns = config.get(f\"/{plugin.SLUG}/patterns\", [])\n        if len(patterns) > 0:\n            return plugin.isValidImmersive(text, parsed) or self.match(patterns, text)\n        else:\n            return plugin.isValidImmersive(text, parsed)\n\n    def isImmersive(self, plugin, text, parsed):\n        return (\n            self.conversation.getImmersiveMode() == plugin.SLUG\n            and self.isValidImmersive(plugin, text, parsed)\n        )\n\n    def printPlugins(self):\n        plugin_list = []\n        for plugin in self.plugins:\n            plugin_list.append(plugin.SLUG)\n        logger.info(f\"已激活插件：{plugin_list}\")\n\n    def query(self, text, parsed):\n        \"\"\"\n        query 模块\n\n        Arguments:\n        text -- 原文本\n        parsed -- ULU解析出来的结果\n        \"\"\"\n\n        for plugin in self.plugins:\n            if not self.isValid(plugin, text, parsed) and not self.isImmersive(\n                plugin, text, parsed\n            ):\n                continue\n\n            logger.info(f\"'{text}' 命中技能 {plugin.SLUG}\")\n            self.conversation.matchPlugin = plugin.SLUG\n\n            if plugin.IS_IMMERSIVE:\n                self.conversation.setImmersiveMode(plugin.SLUG)\n\n            continueHandle = False\n            try:\n                self.handling = True\n                continueHandle = plugin.handle(text, parsed)\n                self.handling = False\n            except Exception as e:\n                logger.critical(f\"Failed to execute plugin: {e}\", stack_info=True)\n                traceback.print_exc()\n                reply = f\"抱歉，插件{plugin.SLUG}出故障了，晚点再试试吧\"\n                self.conversation.say(reply, plugin=plugin.SLUG)\n            else:\n                logger.debug(\n                    \"Handling of phrase '%s' by \" + \"plugin '%s' completed\",\n                    text,\n                    plugin.SLUG,\n                )\n            finally:\n                if not continueHandle:\n                    return True\n\n        logger.debug(f\"No plugin was able to handle phrase {text} \")\n        return False\n\n    def restore(self):\n        \"\"\"恢复某个技能的处理\"\"\"\n        if not self.conversation.immersiveMode:\n            return\n        for plugin in self.plugins:\n            if plugin.SLUG == self.conversation.immersiveMode and plugin.restore:\n                logger.warning(f\"{plugin.SLUG}: restore\")\n                plugin.restore()\n\n    def pause(self):\n        \"\"\"暂停某个技能的处理\"\"\"\n        if not self.conversation.immersiveMode:\n            return\n        for plugin in self.plugins:\n            if plugin.SLUG == self.conversation.immersiveMode and plugin.pause:\n                plugin.pause()\n\n    def understand(self, fp):\n        if self.conversation and self.conversation.asr:\n            return self.conversation.asr.transcribe(fp)\n        return None\n\n    def say(self, msg, cache=False):\n        if self.conversation and self.conversation.tts:\n            self.conversation.tts.say(msg, cache)\n"
  },
  {
    "path": "robot/ConfigMonitor.py",
    "content": "# -*- coding: utf-8 -*-\n\nimport os\nfrom robot import config, utils, logging\nfrom watchdog.events import FileSystemEventHandler\n\nlogger = logging.getLogger(__name__)\n\n\nclass ConfigMonitor(FileSystemEventHandler):\n    def __init__(self, conversation):\n        FileSystemEventHandler.__init__(self)\n        self._conversation = conversation\n\n    # 文件修改\n    def on_modified(self, event):\n        if event.is_directory:\n            return\n\n        filename = event.src_path\n        extension = os.path.splitext(filename)[-1].lower()\n        if extension in (\".yaml\", \".yml\"):\n            if utils.validyaml(filename):\n                logger.info(f\"检测到文件 {filename} 发生变更\")\n                config.reload()\n                self._conversation.reInit()\n"
  },
  {
    "path": "robot/Conversation.py",
    "content": "# -*- coding: utf-8 -*-\nimport time\nimport uuid\nimport cProfile\nimport pstats\nimport io\nimport re\nimport os\nimport threading\nimport traceback\n\nfrom concurrent.futures import ThreadPoolExecutor, as_completed\n\nfrom snowboy import snowboydecoder\n\nfrom robot.LifeCycleHandler import LifeCycleHandler\nfrom robot.Brain import Brain\nfrom robot.Scheduler import Scheduler\nfrom robot.sdk import History\nfrom robot import (\n    AI,\n    ASR,\n    config,\n    constants,\n    logging,\n    NLU,\n    Player,\n    statistic,\n    TTS,\n    utils,\n)\n\n\nlogger = logging.getLogger(__name__)\n\n\nclass Conversation(object):\n    def __init__(self, profiling=False):\n        self.brain, self.asr, self.ai, self.tts, self.nlu = None, None, None, None, None\n        self.reInit()\n        self.scheduler = Scheduler(self)\n        # 历史会话消息\n        self.history = History.History()\n        # 沉浸模式，处于这个模式下，被打断后将自动恢复这个技能\n        self.matchPlugin = None\n        self.immersiveMode = None\n        self.isRecording = False\n        self.profiling = profiling\n        self.onSay = None\n        self.onStream = None\n        self.hasPardon = False\n        self.player = Player.SoxPlayer()\n        self.lifeCycleHandler = LifeCycleHandler(self)\n        self.tts_count = 0\n        self.tts_index = 0\n        self.tts_lock = threading.Lock()\n        self.play_lock = threading.Lock()\n\n    def _lastCompleted(self, index, onCompleted):\n        # logger.debug(f\"{index}, {self.tts_index}, {self.tts_count}\")\n        if index >= self.tts_count - 1:\n            # logger.debug(f\"执行onCompleted\")\n            onCompleted and onCompleted()\n\n    def _ttsAction(self, msg, cache, index, onCompleted=None):\n        if msg:\n            voice = \"\"\n            if utils.getCache(msg):\n                logger.info(f\"第{index}段TTS命中缓存，播放缓存语音\")\n                voice = utils.getCache(msg)\n                while index != self.tts_index:\n                    # 阻塞直到轮到这个音频播放\n                    continue\n                with self.play_lock:\n                    self.player.play(\n                        voice,\n                        not cache,\n                        onCompleted=lambda: self._lastCompleted(index, onCompleted),\n                    )\n                    self.tts_index += 1\n                return voice\n            else:\n                try:\n                    voice = self.tts.get_speech(msg)\n                    logger.info(f\"第{index}段TTS合成成功。msg: {msg}\")\n                    while index != self.tts_index:\n                        # 阻塞直到轮到这个音频播放\n                        continue\n                    with self.play_lock:\n                        logger.info(f\"即将播放第{index}段TTS。msg: {msg}\")\n                        self.player.play(\n                            voice,\n                            not cache,\n                            onCompleted=lambda: self._lastCompleted(index, onCompleted),\n                        )\n                        self.tts_index += 1\n                    return voice\n                except Exception as e:\n                    logger.error(f\"语音合成失败：{e}\", stack_info=True)\n                    self.tts_index += 1\n                    traceback.print_exc()\n                    return None\n\n    def getHistory(self):\n        return self.history\n\n    def interrupt(self):\n        if self.player and self.player.is_playing():\n            self.player.stop()\n        if self.immersiveMode:\n            self.brain.pause()\n\n    def reInit(self):\n        \"\"\"重新初始化\"\"\"\n        try:\n            self.asr = ASR.get_engine_by_slug(config.get(\"asr_engine\", \"tencent-asr\"))\n            self.ai = AI.get_robot_by_slug(config.get(\"robot\", \"tuling\"))\n            self.tts = TTS.get_engine_by_slug(config.get(\"tts_engine\", \"baidu-tts\"))\n            self.nlu = NLU.get_engine_by_slug(config.get(\"nlu_engine\", \"unit\"))\n            self.player = Player.SoxPlayer()\n            self.brain = Brain(self)\n            self.brain.printPlugins()\n        except Exception as e:\n            logger.critical(f\"对话初始化失败：{e}\", stack_info=True)\n\n    def checkRestore(self):\n        if self.immersiveMode:\n            logger.info(\"处于沉浸模式，恢复技能\")\n            self.lifeCycleHandler.onRestore()\n            self.brain.restore()\n\n    def _InGossip(self, query):\n        return self.immersiveMode in [\"Gossip\"] and not \"闲聊\" in query\n\n    def doResponse(self, query, UUID=\"\", onSay=None, onStream=None):\n        \"\"\"\n        响应指令\n\n        :param query: 指令\n        :UUID: 指令的UUID\n        :onSay: 朗读时的回调\n        :onStream: 流式输出时的回调\n        \"\"\"\n        statistic.report(1)\n        self.interrupt()\n        self.appendHistory(0, query, UUID)\n\n        if onSay:\n            self.onSay = onSay\n\n        if onStream:\n            self.onStream = onStream\n\n        if query.strip() == \"\":\n            self.pardon()\n            return\n\n        lastImmersiveMode = self.immersiveMode\n\n        parsed = self.doParse(query)\n        if self._InGossip(query) or not self.brain.query(query, parsed):\n            # 进入闲聊\n            if self.nlu.hasIntent(parsed, \"PAUSE\") or \"闭嘴\" in query:\n                # 停止说话\n                self.player.stop()\n            else:\n                # 没命中技能，使用机器人回复\n                if self.ai.SLUG == \"openai\":\n                    stream = self.ai.stream_chat(query)\n                    self.stream_say(stream, True, onCompleted=self.checkRestore)\n                else:\n                    msg = self.ai.chat(query, parsed)\n                    self.say(msg, True, onCompleted=self.checkRestore)\n        else:\n            # 命中技能\n            if lastImmersiveMode and lastImmersiveMode != self.matchPlugin:\n                if self.player:\n                    if self.player.is_playing():\n                        logger.debug(\"等说完再checkRestore\")\n                        self.player.appendOnCompleted(lambda: self.checkRestore())\n                else:\n                    logger.debug(\"checkRestore\")\n                    self.checkRestore()\n\n    def doParse(self, query):\n        args = {\n            \"service_id\": config.get(\"/unit/service_id\", \"S13442\"),\n            \"api_key\": config.get(\"/unit/api_key\", \"w5v7gUV3iPGsGntcM84PtOOM\"),\n            \"secret_key\": config.get(\n                \"/unit/secret_key\", \"KffXwW6E1alcGplcabcNs63Li6GvvnfL\"\n            ),\n        }\n        return self.nlu.parse(query, **args)\n\n    def setImmersiveMode(self, slug):\n        self.immersiveMode = slug\n\n    def getImmersiveMode(self):\n        return self.immersiveMode\n\n    def converse(self, fp, callback=None):\n        \"\"\"核心对话逻辑\"\"\"\n        logger.info(\"结束录音\")\n        self.lifeCycleHandler.onThink()\n        self.isRecording = False\n        if self.profiling:\n            logger.info(\"性能调试已打开\")\n            pr = cProfile.Profile()\n            pr.enable()\n            self.doConverse(fp, callback)\n            pr.disable()\n            s = io.StringIO()\n            sortby = \"cumulative\"\n            ps = pstats.Stats(pr, stream=s).sort_stats(sortby)\n            ps.print_stats()\n            print(s.getvalue())\n        else:\n            self.doConverse(fp, callback)\n\n    def doConverse(self, fp, callback=None, onSay=None, onStream=None):\n        self.interrupt()\n        try:\n            query = self.asr.transcribe(fp)\n        except Exception as e:\n            logger.critical(f\"ASR识别失败：{e}\", stack_info=True)\n            traceback.print_exc()\n        utils.check_and_delete(fp)\n        try:\n            self.doResponse(query, callback, onSay, onStream)\n        except Exception as e:\n            logger.critical(f\"回复失败：{e}\", stack_info=True)\n            traceback.print_exc()\n        utils.clean()\n\n    def appendHistory(self, t, text, UUID=\"\", plugin=\"\"):\n        \"\"\"将会话历史加进历史记录\"\"\"\n        if t in (0, 1) and text:\n            if text.endswith(\",\") or text.endswith(\"，\"):\n                text = text[:-1]\n            if UUID == \"\" or UUID == None or UUID == \"null\":\n                UUID = str(uuid.uuid1())\n            # 将图片处理成HTML\n            pattern = r\"https?://.+\\.(?:png|jpg|jpeg|bmp|gif|JPG|PNG|JPEG|BMP|GIF)\"\n            url_pattern = r\"^https?://.+\"\n            imgs = re.findall(pattern, text)\n            for img in imgs:\n                text = text.replace(\n                    img,\n                    f'<a data-fancybox=\"images\" href=\"{img}\"><img src={img} class=\"img fancybox\"></img></a>',\n                )\n            urls = re.findall(url_pattern, text)\n            for url in urls:\n                text = text.replace(url, f'<a href={url} target=\"_blank\">{url}</a>')\n            self.lifeCycleHandler.onResponse(t, text)\n            self.history.add_message(\n                {\n                    \"type\": t,\n                    \"text\": text,\n                    \"time\": time.strftime(\n                        \"%Y-%m-%d %H:%M:%S\", time.localtime(time.time())\n                    ),\n                    \"uuid\": UUID,\n                    \"plugin\": plugin,\n                }\n            )\n\n    def _onCompleted(self, msg):\n        pass\n\n    def pardon(self):\n        if not self.hasPardon:\n            self.say(\"抱歉，刚刚没听清，能再说一遍吗？\", cache=True)\n            self.hasPardon = True\n        else:\n            self.say(\"没听清呢\")\n            self.hasPardon = False\n\n    def _tts_line(self, line, cache, index=0, onCompleted=None):\n        \"\"\"\n        对单行字符串进行 TTS 并返回合成后的音频\n        :param line: 字符串\n        :param cache: 是否缓存 TTS 结果\n        :param index: 合成序号\n        :param onCompleted: 播放完成的操作\n        \"\"\"\n        line = line.strip()\n        pattern = r\"http[s]?://.+\"\n        if re.match(pattern, line):\n            logger.info(\"内容包含URL，屏蔽后续内容\")\n            return None\n        line.replace(\"- \", \"\")\n        if line:\n            result = self._ttsAction(line, cache, index, onCompleted)\n            return result\n        return None\n\n    def _tts(self, lines, cache, onCompleted=None):\n        \"\"\"\n        对字符串进行 TTS 并返回合成后的音频\n        :param lines: 字符串列表\n        :param cache: 是否缓存 TTS 结果\n        \"\"\"\n        audios = []\n        pattern = r\"http[s]?://.+\"\n        logger.info(\"_tts\")\n        with self.tts_lock:\n            with ThreadPoolExecutor(max_workers=config.get(\"tts_parallel\", 5)) as pool:\n                all_task = []\n                index = 0\n                for line in lines:\n                    if re.match(pattern, line):\n                        logger.info(\"内容包含URL，屏蔽后续内容\")\n                        self.tts_count -= 1\n                        continue\n                    if line:\n                        task = pool.submit(\n                            self._ttsAction, line.strip(), cache, index, onCompleted\n                        )\n                        index += 1\n                        all_task.append(task)\n                    else:\n                        self.tts_count -= 1\n                for future in as_completed(all_task):\n                    audio = future.result()\n                    if audio:\n                        audios.append(audio)\n            return audios\n\n    def _after_play(self, msg, audios, plugin=\"\"):\n        cached_audios = [\n            f\"http://{config.get('/server/host')}:{config.get('/server/port')}/audio/{os.path.basename(voice)}\"\n            for voice in audios\n        ]\n        if self.onSay:\n            logger.info(f\"onSay: {msg}, {cached_audios}\")\n            self.onSay(msg, cached_audios, plugin=plugin)\n            self.onSay = None\n        utils.lruCache()  # 清理缓存\n\n    def stream_say(self, stream, cache=False, onCompleted=None):\n        \"\"\"\n        从流中逐字逐句生成语音\n        :param stream: 文字流，可迭代对象\n        :param cache: 是否缓存 TTS 结果\n        :param onCompleted: 声音播报完成后的回调\n        \"\"\"\n        lines = []\n        line = \"\"\n        resp_uuid = str(uuid.uuid1())\n        audios = []\n        if onCompleted is None:\n            onCompleted = lambda: self._onCompleted(msg)\n        self.tts_index = 0\n        self.tts_count = 0\n        index = 0\n        skip_tts = False\n        for data in stream():\n            if self.onStream:\n                self.onStream(data, resp_uuid)\n            line += data\n            if any(char in data for char in utils.getPunctuations()):\n                if \"```\" in line.strip():\n                    skip_tts = True\n                if not skip_tts:\n                    audio = self._tts_line(line.strip(), cache, index, onCompleted)\n                    if audio:\n                        self.tts_count += 1\n                        audios.append(audio)\n                        index += 1\n                else:\n                    logger.info(f\"{line} 属于代码段，跳过朗读\")\n                lines.append(line)\n                line = \"\"\n        if line.strip():\n            lines.append(line)\n        if skip_tts:\n            self._tts_line(\"内容包含代码，我就不念了\", True, index, onCompleted)\n        msg = \"\".join(lines)\n        self.appendHistory(1, msg, UUID=resp_uuid, plugin=\"\")\n        self._after_play(msg, audios, \"\")\n\n    def say(self, msg, cache=False, plugin=\"\", onCompleted=None, append_history=True):\n        \"\"\"\n        说一句话\n        :param msg: 内容\n        :param cache: 是否缓存这句话的音频\n        :param plugin: 来自哪个插件的消息（将带上插件的说明）\n        :param onCompleted: 完成的回调\n        :param append_history: 是否要追加到聊天记录\n        \"\"\"\n        if append_history:\n            self.appendHistory(1, msg, plugin=plugin)\n        msg = utils.stripPunctuation(msg).strip()\n\n        if not msg:\n            return\n\n        logger.info(f\"即将朗读语音：{msg}\")\n        lines = re.split(\"。|！|？|\\!|\\?|\\n\", msg)\n        if onCompleted is None:\n            onCompleted = lambda: self._onCompleted(msg)\n        self.tts_index = 0\n        self.tts_count = len(lines)\n        logger.debug(f\"tts_count: {self.tts_count}\")\n        audios = self._tts(lines, cache, onCompleted)\n        self._after_play(msg, audios, plugin)\n\n    def activeListen(self, silent=False):\n        \"\"\"\n        主动问一个问题(适用于多轮对话)\n        :param silent: 是否不触发唤醒表现（主要用于极客模式）\n        :param\n        \"\"\"\n        if self.immersiveMode:\n            self.player.stop()\n        elif self.player.is_playing():\n            self.player.join()  # 确保所有音频都播完\n        logger.info(\"进入主动聆听...\")\n        try:\n            if not silent:\n                self.lifeCycleHandler.onWakeup()\n            listener = snowboydecoder.ActiveListener(\n                [constants.getHotwordModel(config.get(\"hotword\", \"wukong.pmdl\"))]\n            )\n            voice = listener.listen(\n                silent_count_threshold=config.get(\"silent_threshold\", 15),\n                recording_timeout=config.get(\"recording_timeout\", 5) * 4,\n            )\n            if not silent:\n                self.lifeCycleHandler.onThink()\n            if voice:\n                query = self.asr.transcribe(voice)\n                utils.check_and_delete(voice)\n                return query\n            return \"\"\n        except Exception as e:\n            logger.error(f\"主动聆听失败：{e}\", stack_info=True)\n            traceback.print_exc()\n            return \"\"\n\n    def play(self, src, delete=False, onCompleted=None, volume=1):\n        \"\"\"播放一个音频\"\"\"\n        if self.player:\n            self.interrupt()\n        self.player = Player.SoxPlayer()\n        self.player.play(src, delete=delete, onCompleted=onCompleted)\n"
  },
  {
    "path": "robot/LifeCycleHandler.py",
    "content": "import logging\nimport multiprocessing\nimport os\nimport time\nimport pickle\nimport time\nimport _thread as thread\n\nfrom watchdog.observers import Observer\nfrom robot import config, constants, statistic, Player\nfrom robot.ConfigMonitor import ConfigMonitor\nfrom robot.sdk import LED\n\nlogger = logging.getLogger(__name__)\n\nLOCAL_REMINDER = os.path.join(constants.TEMP_PATH, \"reminder.pkl\")\n\n\ndef singleton(cls):\n    _instance = {}\n\n    def inner(conversation):\n        if cls not in _instance:\n            _instance[cls] = cls(conversation)\n        return _instance[cls]\n\n    return inner\n\n\n\"\"\"\n抽象出来的生命周期，\n方便在这里针对 wukong 的各个状态做定制\n\"\"\"\n\n\n@singleton\nclass LifeCycleHandler(object):\n    def __init__(self, conversation):\n        self._observer = Observer()\n        self._unihiker = None\n        self._wakeup = None\n        self._conversation = conversation\n\n    def onInit(self):\n        \"\"\"\n        wukong-robot 初始化\n        \"\"\"\n        config.init()\n        statistic.report(0)\n\n        # 初始化配置监听器\n        config_event_handler = ConfigMonitor(self._conversation)\n        self._observer.schedule(config_event_handler, constants.CONFIG_PATH, False)\n        self._observer.schedule(config_event_handler, constants.DATA_PATH, False)\n        self._observer.start()\n\n        # 加载历史提醒\n        self._read_reminders()\n\n        # 行空板\n        self._init_unihiker()\n        # LED 灯\n        self._init_LED()\n        # Muse 头环\n        self._init_muse()\n\n    def _read_reminders(self):\n        logger.info(\"重新加载提醒信息\")\n        if os.path.exists(LOCAL_REMINDER):\n            with open(LOCAL_REMINDER, \"rb\") as f:\n                jobs = pickle.load(f)\n                for job in jobs:\n                    if \"repeat\" in job.remind_time or int(time.time()) < int(\n                        job.job_id\n                    ):\n                        logger.info(f\"加入提醒: {job.describe}, job_id: {job.job_id}\")\n                        if not (self._conversation.scheduler.has_job(job.job_id)):\n                            self._conversation.scheduler.add_job(\n                                job.remind_time,\n                                job.original_time,\n                                job.content,\n                                lambda: self.alarm(\n                                    job.remind_time, job.content, job.job_id\n                                ),\n                                job_id=job.job_id,\n                            )\n\n    def _init_unihiker(self):\n        global unihiker\n        if config.get(\"/unihiker/enable\", False):\n            try:\n                from robot.sdk.Unihiker import Unihiker\n\n                self._unihiker = Unihiker()\n                thread.start_new_thread(self._unihiker_shake_event, ())\n            except ImportError:\n                logger.error(\"错误：请确保当前硬件环境为行空板\", stack_info=True)\n\n    def _init_LED(self):\n        if config.get(\"/LED/enable\", False) and config.get(\"/LED/type\") == \"aiy\":\n            thread.start_new_thread(self._aiy_button_event, ())\n\n    def _init_muse(self):\n        if config.get(\"/muse/enable\", False):\n            try:\n                from robot import BCI\n\n                self._wakeup = multiprocessing.Event()\n                bci = BCI.MuseBCI(self._wakeup)\n                bci.start()\n                thread.start_new_thread(self._muse_loop_event, ())\n            except ImportError:\n                logger.error(\"错误：请确保当前硬件搭配了Muse头环并安装了相关驱动\", stack_info=True)\n\n    def _unihiker_shake_event(self):\n        \"\"\"\n        行空板摇一摇的监听逻辑\n        \"\"\"\n        while True:\n            from pinpong.extension.unihiker import accelerometer\n\n            if accelerometer.get_strength() >= 1.5:\n                logger.info(\"行空板摇一摇触发唤醒\")\n                self._conversation.interrupt()\n                query = self._conversation.activeListen()\n                self._conversation.doResponse(query)\n            time.sleep(0.1)\n\n    def _aiy_button_event(self):\n        \"\"\"\n        Google AIY VoiceKit 的监听逻辑\n        \"\"\"\n        try:\n            from aiy.board import Board\n        except ImportError:\n            logger.error(\"错误：请确保当前硬件环境为Google AIY VoiceKit并正确安装了驱动\", stack_info=True)\n            return\n        with Board() as board:\n            while True:\n                board.button.wait_for_press()\n                logger.info(\"Google AIY Voicekit 触发唤醒\")\n                self._conversation.interrupt()\n                query = self._conversation.activeListen()\n                self._conversation.doResponse(query)\n\n    def _muse_loop_event(self):\n        \"\"\"\n        Muse 头环的监听逻辑\n        \"\"\"\n        while True:\n            self._wakeup.wait()\n            self._conversation.interrupt()\n            logger.info(\"Muse 头环触发唤醒\")\n            query = self._conversation.activeListen()\n            self._conversation.doResponse(query)\n            self._wakeup.clear()\n\n    def _beep_hi(self, onCompleted=None):\n        Player.play(constants.getData(\"beep_hi.wav\"), onCompleted)\n\n    def _beep_lo(self):\n        Player.play(constants.getData(\"beep_lo.wav\"))\n\n    def onWakeup(self, onCompleted=None):\n        \"\"\"\n        唤醒并进入录音的状态\n        \"\"\"\n        logger.info(\"onWakeup\")\n        self._beep_hi(onCompleted=onCompleted)\n        if config.get(\"/LED/enable\", False):\n            LED.wakeup()\n        self._unihiker and self._unihiker.record(1, \"我正在聆听...\")\n        self._unihiker and self._unihiker.wakeup()\n\n    def onThink(self):\n        \"\"\"\n        录音结束并进入思考的状态\n        \"\"\"\n        logger.info(\"onThink\")\n        self._beep_lo()\n        self._unihiker and self._unihiker.think()\n        self._unihiker and self._unihiker.record(1, \"我正在思考...\")\n        if config.get(\"/LED/enable\", False):\n            LED.think()\n\n    def onResponse(self, t=1, text=\"\"):\n        \"\"\"\n        思考完成并播放结果的状态\n        \"\"\"\n        if t == 1:\n            text = text[:60] + \"...\" if len(text) >= 60 else text\n        else:\n            text = text[:9] + \"...\" if len(text) >= 9 else text\n        self._unihiker and self._unihiker.record(t, text)\n        if config.get(\"/LED/enable\", False):\n            LED.off()\n\n    def onRestore(self):\n        \"\"\"\n        恢复沉浸式技能的状态\n        \"\"\"\n        logger.info(\"onRestore\")\n\n    def onKilled(self):\n        logger.info(\"onKill\")\n        self._observer.stop()\n"
  },
  {
    "path": "robot/NLU.py",
    "content": "# -*- coding: utf-8 -*-\nfrom .sdk import unit\nfrom robot import logging\nfrom abc import ABCMeta, abstractmethod\n\nlogger = logging.getLogger(__name__)\n\n\nclass AbstractNLU(object):\n    \"\"\"\n    Generic parent class for all NLU engines\n    \"\"\"\n\n    __metaclass__ = ABCMeta\n\n    @classmethod\n    def get_config(cls):\n        return {}\n\n    @classmethod\n    def get_instance(cls):\n        profile = cls.get_config()\n        instance = cls(**profile)\n        return instance\n\n    @abstractmethod\n    def parse(self, query, **args):\n        \"\"\"\n        进行 NLU 解析\n\n        :param query: 用户的指令字符串\n        :param **args: 可选的参数\n        \"\"\"\n        return None\n\n    @abstractmethod\n    def getIntent(self, parsed):\n        \"\"\"\n        提取意图\n\n        :param parsed: 解析结果\n        :returns: 意图数组\n        \"\"\"\n        return None\n\n    @abstractmethod\n    def hasIntent(self, parsed, intent):\n        \"\"\"\n        判断是否包含某个意图\n\n        :param parsed: 解析结果\n        :param intent: 意图的名称\n        :returns: True: 包含; False: 不包含\n        \"\"\"\n        return False\n\n    @abstractmethod\n    def getSlots(self, parsed, intent):\n        \"\"\"\n        提取某个意图的所有词槽\n\n        :param parsed: 解析结果\n        :param intent: 意图的名称\n        :returns: 词槽列表。你可以通过 name 属性筛选词槽，\n        再通过 normalized_word 属性取出相应的值\n        \"\"\"\n        return None\n\n    @abstractmethod\n    def getSlotWords(self, parsed, intent, name):\n        \"\"\"\n        找出命中某个词槽的内容\n\n        :param parsed: 解析结果\n        :param intent: 意图的名称\n        :param name: 词槽名\n        :returns: 命中该词槽的值的列表。\n        \"\"\"\n        return None\n\n    @abstractmethod\n    def getSay(self, parsed, intent):\n        \"\"\"\n        提取回复文本\n\n        :param parsed: 解析结果\n        :param intent: 意图的名称\n        :returns: 回复文本\n        \"\"\"\n        return \"\"\n\n\nclass UnitNLU(AbstractNLU):\n    \"\"\"\n    百度UNIT的NLU API.\n    \"\"\"\n\n    SLUG = \"unit\"\n\n    def __init__(self):\n        super(self.__class__, self).__init__()\n\n    @classmethod\n    def get_config(cls):\n        \"\"\"\n        百度UNIT的配置\n\n        无需配置，所以返回 {}\n        \"\"\"\n        return {}\n\n    def parse(self, query, **args):\n        \"\"\"\n        使用百度 UNIT 进行 NLU 解析\n\n        :param query: 用户的指令字符串\n        :param **args: UNIT 的相关参数\n            - service_id: UNIT 的 service_id\n            - api_key: UNIT apk_key\n            - secret_key: UNIT secret_key\n        :returns: UNIT 解析结果。如果解析失败，返回 None\n        \"\"\"\n        if (\n            \"service_id\" not in args\n            or \"api_key\" not in args\n            or \"secret_key\" not in args\n        ):\n            logger.critical(f\"{self.SLUG} NLU 失败：参数错误！\", stack_info=True)\n            return None\n        return unit.getUnit(\n            query, args[\"service_id\"], args[\"api_key\"], args[\"secret_key\"]\n        )\n\n    def getIntent(self, parsed):\n        \"\"\"\n        提取意图\n\n        :param parsed: 解析结果\n        :returns: 意图数组\n        \"\"\"\n        return unit.getIntent(parsed)\n\n    def hasIntent(self, parsed, intent):\n        \"\"\"\n        判断是否包含某个意图\n\n        :param parsed: UNIT 解析结果\n        :param intent: 意图的名称\n        :returns: True: 包含; False: 不包含\n        \"\"\"\n        return unit.hasIntent(parsed, intent)\n\n    def getSlots(self, parsed, intent):\n        \"\"\"\n        提取某个意图的所有词槽\n\n        :param parsed: UNIT 解析结果\n        :param intent: 意图的名称\n        :returns: 词槽列表。你可以通过 name 属性筛选词槽，\n        再通过 normalized_word 属性取出相应的值\n        \"\"\"\n        return unit.getSlots(parsed, intent)\n\n    def getSlotWords(self, parsed, intent, name):\n        \"\"\"\n        找出命中某个词槽的内容\n\n        :param parsed: UNIT 解析结果\n        :param intent: 意图的名称\n        :param name: 词槽名\n        :returns: 命中该词槽的值的列表。\n        \"\"\"\n        return unit.getSlotWords(parsed, intent, name)\n\n    def getSlotOriginalWords(self, parsed, intent, name):\n        \"\"\"\n        找出命中某个词槽的原始内容\n\n        :param parsed: UNIT 解析结果\n        :param intent: 意图的名称\n        :param name: 词槽名\n        :returns: 命中该词槽的值的列表。\n        \"\"\"\n        return unit.getSlotOriginalWords(parsed, intent, name)\n\n    def getSay(self, parsed, intent):\n        \"\"\"\n        提取 UNIT 的回复文本\n\n        :param parsed: UNIT 解析结果\n        :param intent: 意图的名称\n        :returns: UNIT 的回复文本\n        \"\"\"\n        return unit.getSay(parsed, intent)\n\n\ndef get_engine_by_slug(slug=None):\n    \"\"\"\n    Returns:\n        An NLU Engine implementation available on the current platform\n\n    Raises:\n        ValueError if no speaker implementation is supported on this platform\n    \"\"\"\n\n    if not slug or type(slug) is not str:\n        raise TypeError(\"无效的 NLU slug '%s'\", slug)\n\n    selected_engines = list(\n        filter(\n            lambda engine: hasattr(engine, \"SLUG\") and engine.SLUG == slug,\n            get_engines(),\n        )\n    )\n\n    if len(selected_engines) == 0:\n        raise ValueError(f\"错误：找不到名为 {slug} 的 NLU 引擎\")\n    else:\n        if len(selected_engines) > 1:\n            logger.warning(f\"注意: 有多个 NLU 名称与指定的引擎名 {slug} 匹配\")\n        engine = selected_engines[0]\n        logger.info(f\"使用 {engine.SLUG} NLU 引擎\")\n        return engine.get_instance()\n\n\ndef get_engines():\n    def get_subclasses(cls):\n        subclasses = set()\n        for subclass in cls.__subclasses__():\n            subclasses.add(subclass)\n            subclasses.update(get_subclasses(subclass))\n        return subclasses\n\n    return [\n        engine\n        for engine in list(get_subclasses(AbstractNLU))\n        if hasattr(engine, \"SLUG\") and engine.SLUG\n    ]\n"
  },
  {
    "path": "robot/Player.py",
    "content": "# -*- coding: utf-8 -*-\nimport asyncio\nimport subprocess\nimport os\nimport platform\nimport queue\nimport signal\nimport threading\n\nfrom robot import logging\nfrom ctypes import CFUNCTYPE, c_char_p, c_int, cdll\nfrom contextlib import contextmanager\n\nfrom . import utils\n\nlogger = logging.getLogger(__name__)\n\n\ndef py_error_handler(filename, line, function, err, fmt):\n    pass\n\n\nERROR_HANDLER_FUNC = CFUNCTYPE(None, c_char_p, c_int, c_char_p, c_int, c_char_p)\n\nc_error_handler = ERROR_HANDLER_FUNC(py_error_handler)\n\n\n@contextmanager\ndef no_alsa_error():\n    try:\n        asound = cdll.LoadLibrary(\"libasound.so\")\n        asound.snd_lib_error_set_handler(c_error_handler)\n        yield\n        asound.snd_lib_error_set_handler(None)\n    except:\n        yield\n        pass\n\n\ndef play(fname, onCompleted=None):\n    player = getPlayerByFileName(fname)\n    player.play(fname, onCompleted=onCompleted)\n\n\ndef getPlayerByFileName(fname):\n    foo, ext = os.path.splitext(fname)\n    if ext in [\".mp3\", \".wav\"]:\n        return SoxPlayer()\n\n\nclass AbstractPlayer(object):\n    def __init__(self, **kwargs):\n        super(AbstractPlayer, self).__init__()\n\n    def play(self):\n        pass\n\n    def play_block(self):\n        pass\n\n    def stop(self):\n        pass\n\n    def is_playing(self):\n        return False\n\n    def join(self):\n        pass\n\n\nclass SoxPlayer(AbstractPlayer):\n    SLUG = \"SoxPlayer\"\n\n    def __init__(self, **kwargs):\n        super(SoxPlayer, self).__init__(**kwargs)\n        self.playing = False\n        self.proc = None\n        self.delete = False\n        self.onCompleteds = []\n        # 创建一个锁用于保证同一时间只有一个音频在播放\n        self.play_lock = threading.Lock()\n        self.play_queue = queue.Queue()  # 播放队列\n        self.consumer_thread = threading.Thread(target=self.playLoop)\n        self.consumer_thread.start()\n        self.loop = asyncio.new_event_loop()  # 创建事件循环\n        self.thread_loop = threading.Thread(target=self.loop.run_forever)\n        self.thread_loop.start()\n\n    def executeOnCompleted(self, res, onCompleted):\n        # 全部播放完成，播放统一的 onCompleted()\n        res and onCompleted and onCompleted()\n        if self.play_queue.empty():\n            for onCompleted in self.onCompleteds:\n                onCompleted and onCompleted()\n\n    def playLoop(self):\n        while True:\n            (src, onCompleted) = self.play_queue.get()\n            if src:\n                with self.play_lock:\n                    logger.info(f\"开始播放音频：{src}\")\n                    self.src = src\n                    res = self.doPlay(src)\n                    self.play_queue.task_done()\n                    # 将 onCompleted() 方法的调用放到事件循环的线程中执行\n                    self.loop.call_soon_threadsafe(\n                        self.executeOnCompleted, res, onCompleted\n                    )\n\n    def doPlay(self, src):\n        system = platform.system()\n        if system == \"Darwin\":\n            cmd = [\"afplay\", str(src)]\n        else:\n            cmd = [\"play\", str(src)]\n        logger.debug(\"Executing %s\", \" \".join(cmd))\n        self.proc = subprocess.Popen(\n            cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL\n        )\n        self.playing = True\n        self.proc.wait()\n        self.playing = False\n        if self.delete:\n            utils.check_and_delete(src)\n        logger.info(f\"播放完成：{src}\")\n        return self.proc and self.proc.returncode == 0\n\n    def play(self, src, delete=False, onCompleted=None):\n        if src and (os.path.exists(src) or src.startswith(\"http\")):\n            self.delete = delete\n            self.play_queue.put((src, onCompleted))\n        else:\n            logger.critical(f\"path not exists: {src}\", stack_info=True)\n\n    def preappendCompleted(self, onCompleted):\n        onCompleted and self.onCompleteds.insert(0, onCompleted)\n\n    def appendOnCompleted(self, onCompleted):\n        onCompleted and self.onCompleteds.append(onCompleted)\n\n    def play_block(self):\n        self.run()\n\n    def stop(self):\n        if self.proc:\n            self.onCompleteds = []\n            self.proc.terminate()\n            self.proc.kill()\n            self.proc = None\n            self.playing = False\n            self._clear_queue()\n            if self.delete:\n                utils.check_and_delete(self.src)\n\n    def is_playing(self):\n        return self.playing or not self.play_queue.empty()\n\n    def join(self):\n        self.play_queue.join()\n\n    def _clear_queue(self):\n        with self.play_queue.mutex:\n            self.play_queue.queue.clear()\n\n\nclass MusicPlayer(SoxPlayer):\n    \"\"\"\n    给音乐播放器插件使用的，\n    在 SOXPlayer 的基础上增加了列表的支持，\n    并支持暂停和恢复播放\n    \"\"\"\n\n    SLUG = \"MusicPlayer\"\n\n    def __init__(self, playlist, plugin, **kwargs):\n        super(MusicPlayer, self).__init__(**kwargs)\n        self.playlist = playlist\n        self.plugin = plugin\n        self.idx = 0\n        self.pausing = False\n\n    def update_playlist(self, playlist):\n        super().stop()\n        self.playlist = playlist\n        self.idx = 0\n        self.play()\n\n    def play(self):\n        logger.debug(\"MusicPlayer play\")\n        path = self.playlist[self.idx]\n        super().stop()\n        super().play(path, False, self.next)\n\n    def next(self):\n        logger.debug(\"MusicPlayer next\")\n        super().stop()\n        self.idx = (self.idx + 1) % len(self.playlist)\n        self.play()\n\n    def prev(self):\n        logger.debug(\"MusicPlayer prev\")\n        super().stop()\n        self.idx = (self.idx - 1) % len(self.playlist)\n        self.play()\n\n    def pause(self):\n        logger.debug(\"MusicPlayer pause\")\n        self.pausing = True\n        if self.proc:\n            os.kill(self.proc.pid, signal.SIGSTOP)\n\n    def stop(self):\n        if self.proc:\n            logger.debug(f\"MusicPlayer stop {self.proc.pid}\")\n            self.onCompleteds = []\n            os.kill(self.proc.pid, signal.SIGSTOP)\n            self.proc.terminate()\n            self.proc.kill()\n            self.proc = None\n\n    def resume(self):\n        logger.debug(\"MusicPlayer resume\")\n        self.pausing = False\n        self.onCompleteds = [self.next]\n        if self.proc:\n            os.kill(self.proc.pid, signal.SIGCONT)\n\n    def is_playing(self):\n        return self.playing\n\n    def is_pausing(self):\n        return self.pausing\n\n    def turnUp(self):\n        system = platform.system()\n        if system == \"Darwin\":\n            res = subprocess.run(\n                [\"osascript\", \"-e\", \"output volume of (get volume settings)\"],\n                shell=False,\n                capture_output=True,\n                universal_newlines=True,\n            )\n            volume = int(res.stdout.strip())\n            volume += 20\n            if volume >= 100:\n                volume = 100\n                self.plugin.say(\"音量已经最大啦\")\n            subprocess.run([\"osascript\", \"-e\", f\"set volume output volume {volume}\"])\n        elif system == \"Linux\":\n            res = subprocess.run(\n                [\"amixer sget Master | grep 'Mono:' | awk -F'[][]' '{ print $2 }'\"],\n                shell=True,\n                capture_output=True,\n                universal_newlines=True,\n            )\n            if res.stdout != \"\" and res.stdout.strip().endswith(\"%\"):\n                volume = int(res.stdout.strip().replace(\"%\", \"\"))\n                volume += 20\n                if volume >= 100:\n                    volume = 100\n                    self.plugin.say(\"音量已经最大啦\")\n                subprocess.run([\"amixer\", \"set\", \"Master\", f\"{volume}%\"])\n            else:\n                subprocess.run([\"amixer\", \"set\", \"Master\", \"20%+\"])\n        else:\n            self.plugin.say(\"当前系统不支持调节音量\")\n        self.resume()\n\n    def turnDown(self):\n        system = platform.system()\n        if system == \"Darwin\":\n            res = subprocess.run(\n                [\"osascript\", \"-e\", \"output volume of (get volume settings)\"],\n                shell=False,\n                capture_output=True,\n                universal_newlines=True,\n            )\n            volume = int(res.stdout.strip())\n            volume -= 20\n            if volume <= 20:\n                volume = 20\n                self.plugin.say(\"音量已经很小啦\")\n            subprocess.run([\"osascript\", \"-e\", f\"set volume output volume {volume}\"])\n        elif system == \"Linux\":\n            res = subprocess.run(\n                [\"amixer sget Master | grep 'Mono:' | awk -F'[][]' '{ print $2 }'\"],\n                shell=True,\n                capture_output=True,\n                universal_newlines=True,\n            )\n            if res.stdout != \"\" and res.stdout.endswith(\"%\"):\n                volume = int(res.stdout.replace(\"%\", \"\").strip())\n                volume -= 20\n                if volume <= 20:\n                    volume = 20\n                    self.plugin.say(\"音量已经最小啦\")\n                subprocess.run([\"amixer\", \"set\", \"Master\", f\"{volume}%\"])\n            else:\n                subprocess.run([\"amixer\", \"set\", \"Master\", \"20%-\"])\n        else:\n            self.plugin.say(\"当前系统不支持调节音量\")\n        self.resume()\n"
  },
  {
    "path": "robot/Scheduler.py",
    "content": "# wukong-robot 的提醒机制\n# 基于 BackgroundScheduler 做二次封装\nimport datetime\n\nfrom apscheduler.schedulers.background import BackgroundScheduler\nfrom apscheduler.triggers.cron import CronTrigger\n\nfrom robot import logging, utils, constants\n\nlogger = logging.getLogger(__name__)\n\n\nclass Job(object):\n    \"\"\"\n    任务类\n    \"\"\"\n\n    def __init__(self, remind_time, original_time, content, describe, job_id):\n        self.remind_time = remind_time\n        self.original_time = original_time\n        self.content = utils.stripPunctuation(content)\n        self.describe = describe\n        self.job_id = job_id\n\n\nclass Scheduler(object):\n    \"\"\"\n    wukong-robot 的提醒器，\n    用于实现日程提醒功能\n    \"\"\"\n\n    def __init__(self, con):\n        self._jobs = []\n        self._sched = BackgroundScheduler()\n        self._sched.start()\n        self.con = con\n\n    def _get_datetime(self, norm_str):\n        date, time = norm_str.split(\"|\")\n        year, mon, day = date.split(\"-\")\n        hour, min, sec = time.split(\":\")\n        return datetime.datetime(\n            int(year), int(mon), int(day), int(hour), int(min), int(sec)\n        )\n\n    def _add_interval_job(self, alarm, job_id, norm_str):\n        interval, count = norm_str.split(\"-\")[1:]\n        interval_type = interval + \"s\"\n        self._sched.add_job(\n            alarm,\n            \"interval\",\n            **{interval_type: int(count)},\n            id=job_id,\n            misfire_grace_time=60,\n        )\n        return True\n\n    def _parse_cron_rule(self, rule_str):\n        # 解析规则字符串\n        rule_type, rule_time = rule_str.split(\"|\")\n        rule_time_parts = rule_time.split(\" \")\n        hour, minute, second = 0, 0, 0\n        if len(rule_time_parts) > 1:\n            hour, minute, second = map(int, rule_time_parts[1].split(\":\"))\n        else:\n            hour, minute, second = map(int, rule_time_parts[0].split(\":\"))\n\n        if rule_type.startswith(\"repeat-day\"):\n            # 每天执行\n            return CronTrigger(second=second, minute=minute, hour=hour)\n        elif rule_type.startswith(\"repeat-week\"):\n            # 每周执行\n            day_of_week = rule_time_parts[0].split(\"-\")[1]\n            return CronTrigger(\n                second=second, minute=minute, hour=hour, day_of_week=day_of_week\n            )\n        elif rule_type.startswith(\"repeat-month\"):\n            # 每月执行\n            day_of_month = rule_time_parts[0].split(\"-\")[1]\n            return CronTrigger(\n                second=second, minute=minute, hour=hour, day=day_of_month\n            )\n        elif rule_type.startswith(\"repeat-year\"):\n            # 每年执行\n            month, day = rule_time_parts[0].split(\"-\")\n            return CronTrigger(\n                second=second, minute=minute, hour=hour, day=day, month=month\n            )\n        else:\n            return None\n\n    def _add_cron_job(self, alarm, job_id, norm_str):\n        # 解析规则字符串\n        cron_trigger = self._parse_cron_rule(norm_str)\n        if cron_trigger:\n            self._sched.add_job(alarm, trigger=cron_trigger, misfire_grace_time=60)\n            return True\n        return False\n\n    def get_jobs(self):\n        \"\"\"\n        检查当前有多少提醒\n\n        \"\"\"\n        return self._jobs\n\n    def set_jobs(self, jobs):\n        self._jobs = jobs\n\n    def add_job(self, remind_time, original_time, content, onAlarm, job_id=None):\n        \"\"\"\n        添加提醒\n\n        :param remind_time: 提醒时间\n        :param content: 提醒事项\n        :param onAlarm: 提醒的时候触发的响应\n        :returns: 添加成功：添加的提醒；添加失败：None\n        \"\"\"\n        if not job_id:\n            job_id = utils.getTimemStap()\n\n        job = Job(\n            remind_time=remind_time,\n            original_time=original_time,\n            content=content,\n            describe=f\"时间：{remind_time}，事项：{content}\"\n            if \"repeat\" not in remind_time\n            else f\"时间：{original_time}, 事项：{content}\",\n            job_id=job_id,\n        )\n        success = False\n        if \"repeat\" in remind_time:\n            if \"|\" in remind_time:\n                # cron 任务\n                success = self._add_cron_job(onAlarm, job_id, remind_time)\n            else:\n                # interval 任务\n                success = self._add_interval_job(onAlarm, job_id, remind_time)\n        else:\n            success = self._sched.add_job(\n                onAlarm,\n                \"date\",\n                run_date=self._get_datetime(remind_time),\n                id=job_id,\n                misfire_grace_time=60,\n            )\n        if success:\n            self._jobs.append(job)\n            return job\n        return None\n\n    def has_job(self, job_id):\n        return self._sched.get_job(job_id)\n\n    def del_job_by_id(self, job_id):\n        \"\"\"\n        删除指定 job_id 的提醒\n\n        :param job_id: 提醒id\n        \"\"\"\n        try:\n            if self._sched.get_job(job_id=job_id):\n                self._sched.remove_job(job_id=job_id)\n            self._jobs = [job for job in self._jobs if job.job_id != job_id]\n        except Exception as e:\n            logger.warning(f\"id {job_id} 的提醒已被删除。删除失败。\")\n"
  },
  {
    "path": "robot/TTS.py",
    "content": "# -*- coding: utf -8-*-\nimport os\nimport base64\nimport tempfile\nimport pypinyin\nimport subprocess\nimport uuid\n\nimport asyncio\nimport edge_tts\nimport nest_asyncio\n\nfrom aip import AipSpeech\nfrom . import utils, config, constants\nfrom robot import logging\nfrom pathlib import Path\nfrom pypinyin import lazy_pinyin\nfrom pydub import AudioSegment\nfrom abc import ABCMeta, abstractmethod\nfrom .sdk import TencentSpeech, AliSpeech, XunfeiSpeech, atc, VITSClient, VolcengineSpeech\nimport requests\nfrom xml.etree import ElementTree\n\nlogger = logging.getLogger(__name__)\nnest_asyncio.apply()\n\nclass AbstractTTS(object):\n    \"\"\"\n    Generic parent class for all TTS engines\n    \"\"\"\n\n    __metaclass__ = ABCMeta\n\n    @classmethod\n    def get_config(cls):\n        return {}\n\n    @classmethod\n    def get_instance(cls):\n        profile = cls.get_config()\n        instance = cls(**profile)\n        return instance\n\n    @abstractmethod\n    def get_speech(self, phrase):\n        pass\n\n\nclass HanTTS(AbstractTTS):\n    \"\"\"\n    HanTTS：https://github.com/junzew/HanTTS\n    要使用本模块, 需要先从 SourceForge 下载语音库 syllables.zip ：\n    https://sourceforge.net/projects/hantts/files/?source=navbar\n    并解压到 ~/.wukong 目录下\n    \"\"\"\n\n    SLUG = \"han-tts\"\n    CHUNK = 1024\n    punctuation = [\n        \"，\",\n        \"。\",\n        \"？\",\n        \"！\",\n        \"“\",\n        \"”\",\n        \"；\",\n        \"：\",\n        \"（\",\n        \"）\",\n        \":\",\n        \";\",\n        \",\",\n        \".\",\n        \"?\",\n        \"!\",\n        '\"',\n        \"'\",\n        \"(\",\n        \")\",\n    ]\n\n    def __init__(self, voice=\"syllables\", **args):\n        super(self.__class__, self).__init__()\n        self.voice = voice\n\n    @classmethod\n    def get_config(cls):\n        # Try to get han-tts config from config\n        return config.get(\"han-tts\", {})\n\n    def get_speech(self, phrase):\n        \"\"\"\n        Synthesize .wav from text\n        \"\"\"\n        src = os.path.join(constants.CONFIG_PATH, self.voice)\n        text = phrase\n\n        def preprocess(syllables):\n            temp = []\n            for syllable in syllables:\n                for p in self.punctuation:\n                    syllable = syllable.replace(p, \"\")\n                if syllable.isdigit():\n                    syllable = atc.num2chinese(syllable)\n                    new_sounds = lazy_pinyin(syllable, style=pypinyin.TONE3)\n                    for e in new_sounds:\n                        temp.append(e)\n                else:\n                    temp.append(syllable)\n            return temp\n\n        if not os.path.exists(src):\n            logger.error(\n                f\"{self.SLUG} 合成失败: 请先下载 syllables.zip (https://sourceforge.net/projects/hantts/files/?source=navbar) 并解压到 ~/.wukong 目录下\",\n                stack_info=True,\n            )\n            return None\n        logger.debug(f\"{self.SLUG} 合成中...\")\n        delay = 0\n        increment = 355  # milliseconds\n        pause = 500  # pause for punctuation\n        syllables = lazy_pinyin(text, style=pypinyin.TONE3)\n        syllables = preprocess(syllables)\n\n        # initialize to be complete silence, each character takes up ~500ms\n        result = AudioSegment.silent(duration=500 * len(text))\n        for syllable in syllables:\n            path = os.path.join(src, syllable + \".wav\")\n            sound_file = Path(path)\n            # insert 500 ms silence for punctuation marks\n            if syllable in self.punctuation:\n                short_silence = AudioSegment.silent(duration=pause)\n                result = result.overlay(short_silence, position=delay)\n                delay += increment\n                continue\n            # skip sound file that doesn't exist\n            if not sound_file.is_file():\n                continue\n            segment = AudioSegment.from_wav(path)\n            result = result.overlay(segment, position=delay)\n            delay += increment\n\n        tmpfile = \"\"\n        with tempfile.NamedTemporaryFile() as f:\n            tmpfile = f.name\n        result.export(tmpfile, format=\"wav\")\n        logger.info(f\"{self.SLUG} 语音合成成功，合成路径：{tmpfile}\")\n        return tmpfile\n\n\nclass AzureTTS(AbstractTTS):\n    \"\"\"\n    使用微软语音合成技术\n    \"\"\"\n\n    SLUG = \"azure-tts\"\n\n    def __init__(\n        self, secret_key, region, lang=\"zh-CN\", voice=\"zh-CN-XiaoxiaoNeural\", **args\n    ) -> None:\n        super(self.__class__, self).__init__()\n        self.post_url = \"https://INSERT_REGION_HERE.tts.speech.microsoft.com/cognitiveservices/v1\".replace(\n            \"INSERT_REGION_HERE\", region\n        )\n\n        self.post_header = {\n            \"Ocp-Apim-Subscription-Key\": secret_key,\n            \"Content-Type\": \"application/ssml+xml\",\n            \"X-Microsoft-OutputFormat\": \"audio-16khz-128kbitrate-mono-mp3\",\n            \"User-Agent\": \"curl\",\n        }\n        self.sess = requests.session()\n        body = ElementTree.Element(\"speak\", version=\"1.0\")\n        body.set(\"xml:lang\", \"en-us\")\n        vc = ElementTree.SubElement(body, \"voice\")\n        vc.set(\"xml:lang\", lang)\n        vc.set(\"name\", voice)\n        self.body = body\n        self.vc = vc\n\n    @classmethod\n    def get_config(cls):\n        # Try to get baidu_yuyin config from config\n        return config.get(\"azure_yuyin\", {})\n\n    def get_speech(self, phrase):\n        self.vc.text = phrase\n        result = self.sess.post(\n            self.post_url,\n            headers=self.post_header,\n            data=ElementTree.tostring(self.body),\n        )\n        # 识别正确返回语音二进制,http状态码为200\n        if result.status_code == 200:\n            tmpfile = utils.write_temp_file(result.content, \".mp3\")\n            logger.info(f\"{self.SLUG} 语音合成成功，合成路径：{tmpfile}\")\n            return tmpfile\n        else:\n            logger.critical(f\"{self.SLUG} 合成失败！\", stack_info=True)\n\n\nclass BaiduTTS(AbstractTTS):\n    \"\"\"\n    使用百度语音合成技术\n    要使用本模块, 首先到 yuyin.baidu.com 注册一个开发者账号,\n    之后创建一个新应用, 然后在应用管理的\"查看key\"中获得 API Key 和 Secret Key\n    填入 config.yml 中.\n    ...\n        baidu_yuyin:\n            appid: '9670645'\n            api_key: 'qg4haN8b2bGvFtCbBGqhrmZy'\n            secret_key: '585d4eccb50d306c401d7df138bb02e7'\n            dev_pid: 1936\n            per: 1\n            lan: 'zh'\n        ...\n    \"\"\"\n\n    SLUG = \"baidu-tts\"\n\n    def __init__(self, appid, api_key, secret_key, per=1, lan=\"zh\", **args):\n        super(self.__class__, self).__init__()\n        self.client = AipSpeech(appid, api_key, secret_key)\n        self.per, self.lan = str(per), lan\n\n    @classmethod\n    def get_config(cls):\n        # Try to get baidu_yuyin config from config\n        return config.get(\"baidu_yuyin\", {})\n\n    def get_speech(self, phrase):\n        result = self.client.synthesis(phrase, self.lan, 1, {\"per\": self.per})\n        # 识别正确返回语音二进制 错误则返回dict 参照下面错误码\n        if not isinstance(result, dict):\n            tmpfile = utils.write_temp_file(result, \".mp3\")\n            logger.info(f\"{self.SLUG} 语音合成成功，合成路径：{tmpfile}\")\n            return tmpfile\n        else:\n            logger.critical(f\"{self.SLUG} 合成失败！\", stack_info=True)\n\n\nclass TencentTTS(AbstractTTS):\n    \"\"\"\n    腾讯的语音合成\n    region: 服务地域，挑个离自己最近的区域有助于提升速度。\n        有效值：https://cloud.tencent.com/document/api/441/17365#.E5.9C.B0.E5.9F.9F.E5.88.97.E8.A1.A8\n    voiceType:\n        - 0：女声1，亲和风格(默认)\n        - 1：男声1，成熟风格\n        - 2：男声2，成熟风格\n    language:\n        - 1: 中文，最大100个汉字（标点符号算一个汉子）\n        - 2: 英文，最大支持400个字母（标点符号算一个字母）\n    \"\"\"\n\n    SLUG = \"tencent-tts\"\n\n    def __init__(\n        self,\n        appid,\n        secretid,\n        secret_key,\n        region=\"ap-guangzhou\",\n        voiceType=0,\n        language=1,\n        **args,\n    ):\n        super(self.__class__, self).__init__()\n        self.engine = TencentSpeech.tencentSpeech(secret_key, secretid)\n        self.region, self.voiceType, self.language = region, voiceType, language\n\n    @classmethod\n    def get_config(cls):\n        # Try to get tencent_yuyin config from config\n        return config.get(\"tencent_yuyin\", {})\n\n    def get_speech(self, phrase):\n        result = self.engine.TTS(phrase, self.voiceType, self.language, self.region)\n        if \"Response\" in result and \"Audio\" in result[\"Response\"]:\n            audio = result[\"Response\"][\"Audio\"]\n            data = base64.b64decode(audio)\n            tmpfile = utils.write_temp_file(data, \".wav\")\n            logger.info(f\"{self.SLUG} 语音合成成功，合成路径：{tmpfile}\")\n            return tmpfile\n        else:\n            logger.critical(f\"{self.SLUG} 合成失败：{result}\", stack_info=True)\n\n\nclass XunfeiTTS(AbstractTTS):\n    \"\"\"\n    科大讯飞的语音识别API.\n    \"\"\"\n\n    SLUG = \"xunfei-tts\"\n\n    def __init__(self, appid, api_key, api_secret, voice=\"xiaoyan\"):\n        super(self.__class__, self).__init__()\n        self.appid, self.api_key, self.api_secret, self.voice_name = (\n            appid,\n            api_key,\n            api_secret,\n            voice,\n        )\n\n    @classmethod\n    def get_config(cls):\n        # Try to get xunfei_yuyin config from config\n        return config.get(\"xunfei_yuyin\", {})\n\n    def get_speech(self, phrase):\n        return XunfeiSpeech.synthesize(\n            phrase, self.appid, self.api_key, self.api_secret, self.voice_name\n        )\n\n\nclass AliTTS(AbstractTTS):\n    \"\"\"\n    阿里的TTS\n    voice: 发音人，默认是 xiaoyun\n        全部发音人列表：https://help.aliyun.com/document_detail/84435.html?spm=a2c4g.11186623.2.24.67ce5275q2RGsT\n    \"\"\"\n\n    SLUG = \"ali-tts\"\n\n    def __init__(self, appKey, token, voice=\"xiaoyun\", **args):\n        super(self.__class__, self).__init__()\n        self.appKey, self.token, self.voice = appKey, token, voice\n\n    @classmethod\n    def get_config(cls):\n        # Try to get ali_yuyin config from config\n        return config.get(\"ali_yuyin\", {})\n\n    def get_speech(self, phrase):\n        tmpfile = AliSpeech.tts(self.appKey, self.token, self.voice, phrase)\n        if tmpfile:\n            logger.info(f\"{self.SLUG} 语音合成成功，合成路径：{tmpfile}\")\n            return tmpfile\n        else:\n            logger.critical(f\"{self.SLUG} 合成失败！\", stack_info=True)\n\n\nclass EdgeTTS(AbstractTTS):\n    \"\"\"\n    edge-tts 引擎\n    voice: 发音人，默认是 zh-CN-XiaoxiaoNeural\n        全部发音人列表：命令行执行 edge-tts --list-voices 可以打印所有语音\n    \"\"\"\n\n    SLUG = \"edge-tts\"\n\n    def __init__(self, voice=\"zh-CN-XiaoxiaoNeural\", **args):\n        super(self.__class__, self).__init__()\n        self.voice = voice\n\n    @classmethod\n    def get_config(cls):\n        # Try to get ali_yuyin config from config\n        return config.get(\"edge-tts\", {})\n\n    async def async_get_speech(self, phrase):\n        try:\n            tmpfile = os.path.join(constants.TEMP_PATH, uuid.uuid4().hex + \".mp3\")\n            tts = edge_tts.Communicate(text=phrase, voice=self.voice)\n            await tts.save(tmpfile)    \n            logger.info(f\"{self.SLUG} 语音合成成功，合成路径：{tmpfile}\")\n            return tmpfile\n        except Exception as e:\n            logger.critical(f\"{self.SLUG} 合成失败：{str(e)}！\", stack_info=True)\n            return None\n\n    def get_speech(self, phrase):\n        event_loop = asyncio.new_event_loop()\n        tmpfile = event_loop.run_until_complete(self.async_get_speech(phrase))\n        event_loop.close()\n        return tmpfile\n        \n            \n\nclass MacTTS(AbstractTTS):\n    \"\"\"\n    macOS 系统自带的TTS\n    voice: 发音人，默认是 Tingting\n        全部发音人列表：命令行执行 say -v '?' 可以打印所有语音\n        中文推荐 Tingting（普通话）或者 Sinji（粤语）\n    \"\"\"\n\n    SLUG = \"mac-tts\"\n\n    def __init__(self, voice=\"Tingting\", **args):\n        super(self.__class__, self).__init__()\n        self.voice = voice\n\n    @classmethod\n    def get_config(cls):\n        # Try to get ali_yuyin config from config\n        return config.get(\"mac-tts\", {})\n\n    def get_speech(self, phrase):\n        tmpfile = os.path.join(constants.TEMP_PATH, uuid.uuid4().hex + \".asiff\")\n        res = subprocess.run(\n            [\"say\", \"-v\", self.voice, \"-o\", tmpfile, str(phrase)],\n            shell=False,\n            universal_newlines=True,\n        )\n        if res.returncode == 0:\n            logger.info(f\"{self.SLUG} 语音合成成功，合成路径：{tmpfile}\")\n            return tmpfile\n        else:\n            logger.critical(f\"{self.SLUG} 合成失败！\", stack_info=True)\n\nclass VITS(AbstractTTS):\n    \"\"\"\n    VITS 语音合成\n    需要自行搭建vits-simple-api服务器：https://github.com/Artrajz/vits-simple-api\n    server_url : 服务器url，如http://127.0.0.1:23456\n    api_key : 若服务器配置了API Key，在此填入\n    speaker_id : 说话人ID，由所使用的模型决定\n    length : 调节语音长度，相当于调节语速，该数值越大语速越慢。\n    noise : 噪声\n    noisew : 噪声偏差\n    max : 分段阈值，按标点符号分段，加起来大于max时为一段文本。max<=0表示不分段。\n    timeout: 响应超时时间，根据vits-simple-api服务器性能不同配置合理的超时时间。\n    \"\"\"\n\n    SLUG = \"VITS\"\n\n    def __init__(self, server_url, api_key, speaker_id, length, noise, noisew, max, timeout, **args):\n        super(self.__class__, self).__init__()\n        self.server_url, self.api_key, self.speaker_id, self.length, self.noise, self.noisew, self.max, self.timeout = (\n            server_url, api_key, speaker_id, length, noise, noisew, max, timeout)\n\n    @classmethod\n    def get_config(cls):\n        return config.get(\"VITS\", {})\n\n    def get_speech(self, phrase):\n        result = VITSClient.tts(phrase, self.server_url, self.api_key, self.speaker_id, self.length, self.noise,\n                                self.noisew, self.max, self.timeout)\n        tmpfile = utils.write_temp_file(result, \".wav\")\n        logger.info(f\"{self.SLUG} 语音合成成功，合成路径：{tmpfile}\")\n        return tmpfile\n\ndef get_engine_by_slug(slug=None):\n    \"\"\"\n    Returns:\n        A TTS Engine implementation available on the current platform\n\n    Raises:\n        ValueError if no speaker implementation is supported on this platform\n    \"\"\"\n\n    if not slug or type(slug) is not str:\n        raise TypeError(\"无效的 TTS slug '%s'\", slug)\n\n    selected_engines = list(\n        filter(\n            lambda engine: hasattr(engine, \"SLUG\") and engine.SLUG == slug,\n            get_engines(),\n        )\n    )\n\n    if len(selected_engines) == 0:\n        raise ValueError(f\"错误：找不到名为 {slug} 的 TTS 引擎\")\n    else:\n        if len(selected_engines) > 1:\n            logger.warning(f\"注意: 有多个 TTS 名称与指定的引擎名 {slug} 匹配\")\n        engine = selected_engines[0]\n        logger.info(f\"使用 {engine.SLUG} TTS 引擎\")\n        return engine.get_instance()\n\nclass VolcengineTTS(AbstractTTS):\n    \"\"\"\n    VolcengineTTS 语音合成\n    \"\"\"\n\n    SLUG = \"volcengine-tts\"\n\n    def __init__(self, appid, token, cluster, voice_type, **args):\n        super(self.__class__, self).__init__()\n        self.engine = VolcengineSpeech.VolcengineTTS(appid=appid, token=token, cluster=cluster, voice_type=voice_type)\n\n    @classmethod\n    def get_config(cls):\n        # Try to get ali_yuyin config from config\n        return config.get(\"volcengine-tts\", {})\n\n    def get_speech(self, text):\n        result = self.engine.execute(text)\n        if result is None:\n            logger.critical(f\"{self.SLUG} 合成失败！\", stack_info=True)\n        else:\n            tmpfile = os.path.join(constants.TEMP_PATH, uuid.uuid4().hex + \".mp3\")\n            with open(tmpfile, \"wb\") as f:\n                f.write(result)\n            logger.info(f\"{self.SLUG} 语音合成成功，合成路径：{tmpfile}\")\n            return tmpfile\n\ndef get_engines():\n    def get_subclasses(cls):\n        subclasses = set()\n        for subclass in cls.__subclasses__():\n            subclasses.add(subclass)\n            subclasses.update(get_subclasses(subclass))\n        return subclasses\n\n    return [\n        engine\n        for engine in list(get_subclasses(AbstractTTS))\n        if hasattr(engine, \"SLUG\") and engine.SLUG\n    ]\n"
  },
  {
    "path": "robot/Updater.py",
    "content": "import os\nimport requests\nimport json\nimport semver\nfrom subprocess import call\nfrom robot import constants, logging\nfrom datetime import datetime, timedelta\n\nlogger = logging.getLogger(__name__)\nlogger.setLevel(level=logging.INFO)\n\n_updater = None\nURL = \"https://service-e32kknxi-1253537070.ap-hongkong.apigateway.myqcloud.com/release/wukong\"\nDEV_URL = \"https://service-e32kknxi-1253537070.ap-hongkong.apigateway.myqcloud.com/release/wukong-dev\"\n\n\nclass Updater(object):\n    def __init__(self):\n        self.last_check = datetime.now() - timedelta(days=1.5)\n        self.update_info = {}\n\n    def _pull(self, cwd, tag):\n        if os.path.exists(cwd):\n            return (\n                call(\n                    [f\"git checkout master && git pull && git checkout {tag}\"],\n                    cwd=cwd,\n                    shell=True,\n                )\n                == 0\n            )\n        else:\n            logger.error(f\"目录 {cwd} 不存在\")\n            return False\n\n    def _pip(self, cwd):\n        if os.path.exists(cwd):\n            return (\n                call(\n                    [\"pip3\", \"install\", \"-r\", \"requirements.txt\"], cwd=cwd, shell=False\n                )\n                == 0\n            )\n        else:\n            logger.error(f\"目录 {cwd} 不存在\")\n            return False\n\n    def update(self):\n        update_info = self.fetch()\n        success = True\n        if update_info == {}:\n            logger.info(\"恭喜你，wukong-robot 已经是最新！\")\n        if \"main\" in update_info:\n            if self._pull(\n                constants.APP_PATH, update_info[\"main\"][\"version\"]\n            ) and self._pip(constants.APP_PATH):\n                logger.info(\"wukong-robot 更新成功！\")\n                self.update_info.pop(\"main\")\n            else:\n                logger.info(\"wukong-robot 更新失败！\")\n                success = False\n        if \"contrib\" in update_info:\n            if self._pull(\n                constants.CONTRIB_PATH, update_info[\"contrib\"][\"version\"]\n            ) and self._pip(constants.CONTRIB_PATH):\n                logger.info(\"wukong-contrib 更新成功！\")\n                self.update_info.pop(\"contrib\")\n            else:\n                logger.info(\"wukong-contrib 更新失败！\")\n                success = False\n        return success\n\n    def _get_version(self, path, current):\n        if os.path.exists(os.path.join(path, \"VERSION\")):\n            with open(os.path.join(path, \"VERSION\"), \"r\") as f:\n                return f.read().strip()\n        else:\n            return current\n\n    def fetch(self):\n        global URL, DEV_URL\n        url = URL\n        now = datetime.now()\n        if (now - self.last_check).seconds <= 1800:\n            logger.debug(f\"30 分钟内已检查过更新，使用上次的检查结果：{self.update_info}\")\n            return self.update_info\n        try:\n            self.last_check = now\n            r = requests.get(url, timeout=3)\n            info = json.loads(r.text)\n            main_version = info[\"main\"][\"version\"]\n            contrib_version = info[\"contrib\"][\"version\"]\n            # 检查主仓库\n            current_main_version = self._get_version(constants.APP_PATH, main_version)\n            current_contrib_version = self._get_version(\n                constants.CONTRIB_PATH, contrib_version\n            )\n            if semver.compare(main_version, current_main_version) > 0:\n                logger.info(f\"主仓库检查到更新：{info['main']}\")\n                self.update_info[\"main\"] = info[\"main\"]\n            if semver.compare(contrib_version, current_contrib_version) > 0:\n                logger.info(f\"插件库检查到更新：{info['contrib']}\")\n                self.update_info[\"contrib\"] = info[\"contrib\"]\n            if \"notices\" in info:\n                self.update_info[\"notices\"] = info[\"notices\"]\n            return self.update_info\n        except Exception as e:\n            logger.error(f\"检查更新失败：{e}\", stack_info=True)\n            return {}\n\n\ndef fetch():\n    global _updater\n    if not _updater:\n        _updater = Updater()\n    return _updater.fetch()\n\n\nif __name__ == \"__main__\":\n    fetch()\n"
  },
  {
    "path": "robot/__init__.py",
    "content": ""
  },
  {
    "path": "robot/config.py",
    "content": "# -*- coding: utf-8 -*-\nimport yaml\nimport logging\nimport os\nfrom . import constants\n\nlogger = logging.getLogger(__name__)\n\n_config = {}\nhas_init = False\n\n\ndef reload():\n    \"\"\"\n    重新加载配置\n    \"\"\"\n    logger.info(\"配置文件发生变更，重新加载配置文件\")\n    init()\n\n\ndef init():\n    global has_init\n    if os.path.isfile(constants.CONFIG_PATH):\n        logger.critical(f\"错误：{constants.CONFIG_PATH} 应该是个目录，而不应该是个文件\")\n    if not os.path.exists(constants.CONFIG_PATH):\n        os.makedirs(constants.CONFIG_PATH)\n    if not os.path.exists(constants.getConfigPath()):\n        yes_no = input(f\"配置文件{constants.getConfigPath()}不存在，要创建吗？(y/n)\")\n        if yes_no.lower() == \"y\":\n            constants.newConfig()\n            doInit(constants.getConfigPath())\n        else:\n            doInit(constants.getDefaultConfigPath())\n    else:\n        doInit(constants.getConfigPath())\n    has_init = True\n\n\ndef doInit(config_file=constants.getDefaultConfigPath()):\n    # Create config dir if it does not exist yet\n    if not os.path.exists(constants.CONFIG_PATH):\n        try:\n            os.makedirs(constants.CONFIG_PATH)\n        except OSError:\n            logger.error(\n                f\"Could not create config dir: '{constants.CONFIG_PATH}'\",\n                stack_info=True,\n            )\n            raise\n\n    # Check if config dir is writable\n    if not os.access(constants.CONFIG_PATH, os.W_OK):\n        logger.critical(\n            \"Config dir %s is not writable. Dingdang \" + \"won't work correctly.\",\n            constants.CONFIG_PATH,\n        )\n\n    global _config\n\n    # Read config\n    logger.debug(\"Trying to read config file: '%s'\", config_file)\n    try:\n        with open(config_file, \"r\") as f:\n            _config = yaml.safe_load(f)\n    except Exception as e:\n        logger.error(f\"配置文件 {config_file} 读取失败: {e}\", stack_info=True)\n        raise\n\n\ndef get_path(items, default=None, warn=False):\n    global _config\n    curConfig = _config\n    if isinstance(items, str) and items[0] == \"/\":\n        items = items.split(\"/\")[1:]\n    for key in items:\n        if key in curConfig:\n            curConfig = curConfig[key]\n        else:\n            if warn:\n                logger.warning(\n                    \"/%s not specified in profile, defaulting to \" \"'%s'\",\n                    \"/\".join(items),\n                    default,\n                )\n            else:\n                logger.debug(\n                    \"/%s not specified in profile, defaulting to \" \"'%s'\",\n                    \"/\".join(items),\n                    default,\n                )\n            return default\n    return curConfig\n\n\ndef has_path(items):\n    global _config\n    curConfig = _config\n    if isinstance(items, str) and items[0] == \"/\":\n        items = items.split(\"/\")[1:]\n    else:\n        items = [items]\n    for key in items:\n        if key in curConfig:\n            curConfig = curConfig[key]\n        else:\n            return False\n    return True\n\n\ndef has(item):\n    \"\"\"\n    判断配置里是否包含某个配置项\n\n    :param item: 配置项名\n    :returns: True: 包含; False: 不包含\n    \"\"\"\n    return has_path(item)\n\n\ndef get(item=\"\", default=None, warn=False):\n    \"\"\"\n    获取某个配置的值\n\n    :param item: 配置项名。如果是多级配置，则以 \"/a/b\" 的形式提供\n    :param default: 默认值（可选）\n    :param warn: 不存在该配置时，是否告警\n    :returns: 这个配置的值。如果没有该配置，则提供一个默认值\n    \"\"\"\n    global has_init\n    if not has_init:\n        init()\n    if not item:\n        return _config\n    if item[0] == \"/\":\n        return get_path(item, default, warn)\n    try:\n        return _config[item]\n    except KeyError:\n        if warn:\n            logger.warning(\n                \"%s not specified in profile, defaulting to '%s'\", item, default\n            )\n        else:\n            logger.debug(\n                \"%s not specified in profile, defaulting to '%s'\", item, default\n            )\n        return default\n\n\ndef getConfig():\n    \"\"\"\n    返回全部配置数据\n\n    :returns: 全部配置数据（字典类型）\n    \"\"\"\n    return _config\n\n\ndef getText():\n    if os.path.exists(constants.getConfigPath()):\n        with open(constants.getConfigPath(), \"r\") as f:\n            return f.read()\n    return \"\"\n\n\ndef dump(configStr):\n    with open(constants.getConfigPath(), \"w\") as f:\n        f.write(configStr)\n"
  },
  {
    "path": "robot/constants.py",
    "content": "# -*- coding: utf-8 -*-\nimport os\nimport shutil\n\n# Wukong main directory\nAPP_PATH = os.path.normpath(\n    os.path.join(os.path.dirname(os.path.abspath(__file__)), os.pardir)\n)\n\nLIB_PATH = os.path.join(APP_PATH, \"robot\")\nDATA_PATH = os.path.join(APP_PATH, \"static\")\nTEMP_PATH = os.path.join(APP_PATH, \"temp\")\nTEMPLATE_PATH = os.path.join(APP_PATH, \"server\", \"templates\")\nPLUGIN_PATH = os.path.join(APP_PATH, \"plugins\")\nDEFAULT_CONFIG_NAME = \"default.yml\"\nCUSTOM_CONFIG_NAME = \"config.yml\"\n\nCONFIG_PATH = os.path.expanduser(os.getenv(\"WUKONG_CONFIG\", \"~/.wukong\"))\nCONTRIB_PATH = os.path.expanduser(os.getenv(\"WUKONG_CONFIG\", \"~/.wukong/contrib\"))\nCUSTOM_PATH = os.path.expanduser(os.getenv(\"WUKONG_CONFIG\", \"~/.wukong/custom\"))\n\n\ndef getConfigPath():\n    \"\"\"\n    获取配置文件的路径\n\n    returns: 配置文件的存储路径\n    \"\"\"\n    return os.path.join(CONFIG_PATH, CUSTOM_CONFIG_NAME)\n\n\ndef getQAPath():\n    \"\"\"\n    获取QA数据集文件的路径\n\n    returns: QA数据集文件的存储路径\n    \"\"\"\n    qa_source = os.path.join(DATA_PATH, \"qa.csv\")\n    qa_dst = os.path.join(CONFIG_PATH, \"qa.csv\")\n    if not os.path.exists(qa_dst):\n        shutil.copyfile(qa_source, qa_dst)\n    return qa_dst\n\n\ndef getConfigData(*fname):\n    \"\"\"\n    获取配置目录下的指定文件的路径\n\n    :param *fname: 指定文件名。如果传多个，则自动拼接\n    :returns: 配置目录下的某个文件的存储路径\n    \"\"\"\n    return os.path.join(CONFIG_PATH, *fname)\n\n\ndef getData(*fname):\n    \"\"\"\n    获取资源目录下指定文件的路径\n\n    :param *fname: 指定文件名。如果传多个，则自动拼接\n    :returns: 配置文件的存储路径\n    \"\"\"\n    return os.path.join(DATA_PATH, *fname)\n\n\ndef getDefaultConfigPath():\n    return getData(DEFAULT_CONFIG_NAME)\n\n\ndef newConfig():\n    shutil.copyfile(getDefaultConfigPath(), getConfigPath())\n\n\ndef getHotwordModel(fname):\n    if os.path.exists(getData(fname)):\n        return getData(fname)\n    else:\n        return getConfigData(fname)\n"
  },
  {
    "path": "robot/detector.py",
    "content": "import time\n\nfrom snowboy import snowboydecoder\nfrom robot import config, logging, utils, constants\n\nlogger = logging.getLogger(__name__)\n\ndetector = None\nrecorder = None\nporcupine = None\n\n\ndef initDetector(wukong):\n    \"\"\"\n    初始化离线唤醒热词监听器，支持 snowboy 和 porcupine 两大引擎\n    \"\"\"\n    global porcupine, recorder, detector\n    if config.get(\"detector\", \"snowboy\") == \"porcupine\":\n        logger.info(\"使用 porcupine 进行离线唤醒\")\n\n        import pvporcupine\n        from pvrecorder import PvRecorder\n\n        access_key = config.get(\"/porcupine/access_key\")\n        keyword_paths = config.get(\"/porcupine/keyword_paths\")\n        keywords = config.get(\"/porcupine/keywords\", [\"porcupine\"])\n        if keyword_paths:\n            porcupine = pvporcupine.create(\n                access_key=access_key,\n                keyword_paths=[constants.getConfigData(kw) for kw in keyword_paths],\n                sensitivities=[config.get(\"sensitivity\", 0.5)] * len(keyword_paths),\n            )\n        else:\n            porcupine = pvporcupine.create(\n                access_key=access_key,\n                keywords=keywords,\n                sensitivities=[config.get(\"sensitivity\", 0.5)] * len(keywords),\n            )\n\n        recorder = PvRecorder(device_index=-1, frame_length=porcupine.frame_length)\n        recorder.start()\n\n        try:\n            while True:\n                pcm = recorder.read()\n\n                result = porcupine.process(pcm)\n                if result >= 0:\n                    kw = keyword_paths[result] if keyword_paths else keywords[result]\n                    logger.info(\n                        \"[porcupine] Keyword {} Detected at time {}\".format(\n                            kw,\n                            time.strftime(\n                                \"%Y-%m-%d %H:%M:%S\", time.localtime(time.time())\n                            ),\n                        )\n                    )\n                    wukong._detected_callback(False)\n                    recorder.stop()\n                    wukong.conversation.interrupt()\n                    query = wukong.conversation.activeListen()\n                    wukong.conversation.doResponse(query)\n                    recorder.start()\n        except pvporcupine.PorcupineActivationError as e:\n            logger.error(\"[Porcupine] AccessKey activation error\", stack_info=True)\n            raise e\n        except pvporcupine.PorcupineActivationLimitError as e:\n            logger.error(\n                f\"[Porcupine] AccessKey {access_key} has reached it's temporary device limit\",\n                stack_info=True,\n            )\n            raise e\n        except pvporcupine.PorcupineActivationRefusedError as e:\n            logger.error(\n                \"[Porcupine] AccessKey '%s' refused\" % access_key, stack_info=True\n            )\n            raise e\n        except pvporcupine.PorcupineActivationThrottledError as e:\n            logger.error(\n                \"[Porcupine] AccessKey '%s' has been throttled\" % access_key,\n                stack_info=True,\n            )\n            raise e\n        except pvporcupine.PorcupineError as e:\n            logger.error(\"[Porcupine] 初始化 Porcupine 失败\", stack_info=True)\n            raise e\n        except KeyboardInterrupt:\n            logger.info(\"Stopping ...\")\n        finally:\n            porcupine and porcupine.delete()\n            recorder and recorder.delete()\n\n    else:\n        logger.info(\"使用 snowboy 进行离线唤醒\")\n        detector and detector.terminate()\n        models = constants.getHotwordModel(config.get(\"hotword\", \"wukong.pmdl\"))\n        detector = snowboydecoder.HotwordDetector(\n            models, sensitivity=config.get(\"sensitivity\", 0.5)\n        )\n        # main loop\n        try:\n            callbacks = wukong._detected_callback\n            detector.start(\n                detected_callback=callbacks,\n                audio_recorder_callback=wukong.conversation.converse,\n                interrupt_check=wukong._interrupt_callback,\n                silent_count_threshold=config.get(\"silent_threshold\", 15),\n                recording_timeout=config.get(\"recording_timeout\", 5) * 4,\n                sleep_time=0.03,\n            )\n            detector.terminate()\n        except Exception as e:\n            logger.critical(f\"离线唤醒机制初始化失败：{e}\", stack_info=True)\n"
  },
  {
    "path": "robot/drivers/AIY.py",
    "content": "import time\n\n\nclass AIY:\n    def __init__(self):\n        self._wakeup = False\n        self._think = False\n\n    def wakeup(self):\n        from aiy.board import Board, Led\n        from aiy.leds import Leds, Pattern, Color\n\n        self._wakeup = True\n        with Board() as board:\n            with Leds() as leds:\n                while self._wakeup:\n                    board.led.state = Led.ON\n                    leds.pattern = Pattern.breathe(1000)\n                    leds.update(Leds.rgb_pattern(Color.BLUE))\n                    time.sleep(1)\n\n    def think(self):\n        from aiy.leds import Leds, Pattern, Color\n\n        self._wakeup = False\n        self._think = True\n        with Leds() as leds:\n            while self._think:\n                leds.pattern = Pattern.blink(500)\n                leds.update(Leds.rgb_pattern(Color.GREEN))\n                time.sleep(1)\n\n    def off(self):\n        from aiy.board import Board, Led\n\n        self._wakeup = False\n        self._think = False\n        with Board() as board:\n            board.led.state = Led.OFF\n        self.led = False\n"
  },
  {
    "path": "robot/drivers/__init__.py",
    "content": ""
  },
  {
    "path": "robot/drivers/apa102.py",
    "content": "\"\"\"\nfrom https://github.com/tinue/APA102_Pi\nThis is the main driver module for APA102 LEDs\n\"\"\"\nimport spidev\nfrom math import ceil\n\nRGB_MAP = {\n    \"rgb\": [3, 2, 1],\n    \"rbg\": [3, 1, 2],\n    \"grb\": [2, 3, 1],\n    \"gbr\": [2, 1, 3],\n    \"brg\": [1, 3, 2],\n    \"bgr\": [1, 2, 3],\n}\n\n\nclass APA102:\n    \"\"\"\n    Driver for APA102 LEDS (aka \"DotStar\").\n\n    (c) Martin Erzberger 2016-2017\n\n    My very first Python code, so I am sure there is a lot to be optimized ;)\n\n    Public methods are:\n     - set_pixel\n     - set_pixel_rgb\n     - show\n     - clear_strip\n     - cleanup\n\n    Helper methods for color manipulation are:\n     - combine_color\n     - wheel\n\n    The rest of the methods are used internally and should not be used by the\n    user of the library.\n\n    Very brief overview of APA102: An APA102 LED is addressed with SPI. The bits\n    are shifted in one by one, starting with the least significant bit.\n\n    An LED usually just forwards everything that is sent to its data-in to\n    data-out. While doing this, it remembers its own color and keeps glowing\n    with that color as long as there is power.\n\n    An LED can be switched to not forward the data, but instead use the data\n    to change it's own color. This is done by sending (at least) 32 bits of\n    zeroes to data-in. The LED then accepts the next correct 32 bit LED\n    frame (with color information) as its new color setting.\n\n    After having received the 32 bit color frame, the LED changes color,\n    and then resumes to just copying data-in to data-out.\n\n    The really clever bit is this: While receiving the 32 bit LED frame,\n    the LED sends zeroes on its data-out line. Because a color frame is\n    32 bits, the LED sends 32 bits of zeroes to the next LED.\n    As we have seen above, this means that the next LED is now ready\n    to accept a color frame and update its color.\n\n    So that's really the entire protocol:\n    - Start by sending 32 bits of zeroes. This prepares LED 1 to update\n      its color.\n    - Send color information one by one, starting with the color for LED 1,\n      then LED 2 etc.\n    - Finish off by cycling the clock line a few times to get all data\n      to the very last LED on the strip\n\n    The last step is necessary, because each LED delays forwarding the data\n    a bit. Imagine ten people in a row. When you yell the last color\n    information, i.e. the one for person ten, to the first person in\n    the line, then you are not finished yet. Person one has to turn around\n    and yell it to person 2, and so on. So it takes ten additional \"dummy\"\n    cycles until person ten knows the color. When you look closer,\n    you will see that not even person 9 knows its own color yet. This\n    information is still with person 2. Essentially the driver sends additional\n    zeroes to LED 1 as long as it takes for the last color frame to make it\n    down the line to the last LED.\n    \"\"\"\n\n    # Constants\n    MAX_BRIGHTNESS = 31  # Safeguard: Set to a value appropriate for your setup\n    LED_START = 0b11100000  # Three \"1\" bits, followed by 5 brightness bits\n\n    def __init__(\n        self,\n        num_led,\n        global_brightness=MAX_BRIGHTNESS,\n        order=\"rgb\",\n        bus=0,\n        device=1,\n        max_speed_hz=8000000,\n    ):\n        self.num_led = num_led  # The number of LEDs in the Strip\n        order = order.lower()\n        self.rgb = RGB_MAP.get(order, RGB_MAP[\"rgb\"])\n        # Limit the brightness to the maximum if it's set higher\n        if global_brightness > self.MAX_BRIGHTNESS:\n            self.global_brightness = self.MAX_BRIGHTNESS\n        else:\n            self.global_brightness = global_brightness\n\n        self.leds = [self.LED_START, 0, 0, 0] * self.num_led  # Pixel buffer\n        self.spi = spidev.SpiDev()  # Init the SPI device\n        self.spi.open(bus, device)  # Open SPI port 0, slave device (CS) 1\n        # Up the speed a bit, so that the LEDs are painted faster\n        if max_speed_hz:\n            self.spi.max_speed_hz = max_speed_hz\n\n    def clock_start_frame(self):\n        \"\"\"Sends a start frame to the LED strip.\n\n        This method clocks out a start frame, telling the receiving LED\n        that it must update its own color now.\n        \"\"\"\n        self.spi.xfer2([0] * 4)  # Start frame, 32 zero bits\n\n    def clock_end_frame(self):\n        \"\"\"Sends an end frame to the LED strip.\n\n        As explained above, dummy data must be sent after the last real colour\n        information so that all of the data can reach its destination down the line.\n        The delay is not as bad as with the human example above.\n        It is only 1/2 bit per LED. This is because the SPI clock line\n        needs to be inverted.\n\n        Say a bit is ready on the SPI data line. The sender communicates\n        this by toggling the clock line. The bit is read by the LED\n        and immediately forwarded to the output data line. When the clock goes\n        down again on the input side, the LED will toggle the clock up\n        on the output to tell the next LED that the bit is ready.\n\n        After one LED the clock is inverted, and after two LEDs it is in sync\n        again, but one cycle behind. Therefore, for every two LEDs, one bit\n        of delay gets accumulated. For 300 LEDs, 150 additional bits must be fed to\n        the input of LED one so that the data can reach the last LED.\n\n        Ultimately, we need to send additional numLEDs/2 arbitrary data bits,\n        in order to trigger numLEDs/2 additional clock changes. This driver\n        sends zeroes, which has the benefit of getting LED one partially or\n        fully ready for the next update to the strip. An optimized version\n        of the driver could omit the \"clockStartFrame\" method if enough zeroes have\n        been sent as part of \"clockEndFrame\".\n        \"\"\"\n        # Round up num_led/2 bits (or num_led/16 bytes)\n        for _ in range((self.num_led + 15) // 16):\n            self.spi.xfer2([0x00])\n\n    def clear_strip(self):\n        \"\"\"Turns off the strip and shows the result right away.\"\"\"\n\n        for led in range(self.num_led):\n            self.set_pixel(led, 0, 0, 0)\n        self.show()\n\n    def set_pixel(self, led_num, red, green, blue, bright_percent=100):\n        \"\"\"Sets the color of one pixel in the LED stripe.\n\n        The changed pixel is not shown yet on the Stripe, it is only\n        written to the pixel buffer. Colors are passed individually.\n        If brightness is not set the global brightness setting is used.\n        \"\"\"\n        if led_num < 0:\n            return  # Pixel is invisible, so ignore\n        if led_num >= self.num_led:\n            return  # again, invisible\n\n        # Calculate pixel brightness as a percentage of the\n        # defined global_brightness. Round up to nearest integer\n        # as we expect some brightness unless set to 0\n        brightness = ceil(bright_percent * self.global_brightness / 100.0)\n        brightness = int(brightness)\n\n        # LED startframe is three \"1\" bits, followed by 5 brightness bits\n        ledstart = (brightness & 0b00011111) | self.LED_START\n\n        start_index = 4 * led_num\n        self.leds[start_index] = ledstart\n        self.leds[start_index + self.rgb[0]] = red\n        self.leds[start_index + self.rgb[1]] = green\n        self.leds[start_index + self.rgb[2]] = blue\n\n    def set_pixel_rgb(self, led_num, rgb_color, bright_percent=100):\n        \"\"\"Sets the color of one pixel in the LED stripe.\n\n        The changed pixel is not shown yet on the Stripe, it is only\n        written to the pixel buffer.\n        Colors are passed combined (3 bytes concatenated)\n        If brightness is not set the global brightness setting is used.\n        \"\"\"\n        self.set_pixel(\n            led_num,\n            (rgb_color & 0xFF0000) >> 16,\n            (rgb_color & 0x00FF00) >> 8,\n            rgb_color & 0x0000FF,\n            bright_percent,\n        )\n\n    def rotate(self, positions=1):\n        \"\"\"Rotate the LEDs by the specified number of positions.\n\n        Treating the internal LED array as a circular buffer, rotate it by\n        the specified number of positions. The number could be negative,\n        which means rotating in the opposite direction.\n        \"\"\"\n        cutoff = 4 * (positions % self.num_led)\n        self.leds = self.leds[cutoff:] + self.leds[:cutoff]\n\n    def show(self):\n        \"\"\"Sends the content of the pixel buffer to the strip.\n\n        Todo: More than 1024 LEDs requires more than one xfer operation.\n        \"\"\"\n        self.clock_start_frame()\n        # xfer2 kills the list, unfortunately. So it must be copied first\n        # SPI takes up to 4096 Integers. So we are fine for up to 1024 LEDs.\n        self.spi.xfer2(list(self.leds))\n        self.clock_end_frame()\n\n    def cleanup(self):\n        \"\"\"Release the SPI device; Call this method at the end\"\"\"\n\n        self.spi.close()  # Close SPI port\n\n    @staticmethod\n    def combine_color(red, green, blue):\n        \"\"\"Make one 3*8 byte color value.\"\"\"\n\n        return (red << 16) + (green << 8) + blue\n\n    def wheel(self, wheel_pos):\n        \"\"\"Get a color from a color wheel; Green -> Red -> Blue -> Green\"\"\"\n\n        if wheel_pos > 255:\n            wheel_pos = 255  # Safeguard\n        if wheel_pos < 85:  # Green -> Red\n            return self.combine_color(wheel_pos * 3, 255 - wheel_pos * 3, 0)\n        if wheel_pos < 170:  # Red -> Blue\n            wheel_pos -= 85\n            return self.combine_color(255 - wheel_pos * 3, 0, wheel_pos * 3)\n        # Blue -> Green\n        wheel_pos -= 170\n        return self.combine_color(0, wheel_pos * 3, 255 - wheel_pos * 3)\n\n    def dump_array(self):\n        \"\"\"For debug purposes: Dump the LED array onto the console.\"\"\"\n\n        print(self.leds)\n"
  },
  {
    "path": "robot/drivers/pixels.py",
    "content": "from . import apa102\nimport time\nimport threading\n\ntry:\n    import queue as Queue\nexcept ImportError:\n    import Queue as Queue\n\n\nclass Pixels:\n    PIXELS_N = 3\n\n    def __init__(self):\n        self.basis = [0] * 3 * self.PIXELS_N\n        self.basis[0] = 1\n        self.basis[4] = 1\n        self.basis[8] = 2\n\n        self.colors = [0] * 3 * self.PIXELS_N\n        self.dev = apa102.APA102(num_led=self.PIXELS_N)\n\n        self.next = threading.Event()\n        self.queue = Queue.Queue()\n        self.thread = threading.Thread(target=self._run)\n        self.thread.daemon = True\n        self.thread.start()\n\n    def wakeup(self, direction=0):\n        def f():\n            self._wakeup(direction)\n\n        self.next.set()\n        self.queue.put(f)\n\n    def listen(self):\n        self.next.set()\n        self.queue.put(self._listen)\n\n    def think(self):\n        self.next.set()\n        self.queue.put(self._think)\n\n    def speak(self):\n        self.next.set()\n        self.queue.put(self._speak)\n\n    def off(self):\n        self.next.set()\n        self.queue.put(self._off)\n\n    def _run(self):\n        while True:\n            func = self.queue.get()\n            func()\n\n    def _wakeup(self, direction=0):\n        for i in range(1, 25):\n            colors = [i * v for v in self.basis]\n            self.write(colors)\n            time.sleep(0.01)\n\n        self.colors = colors\n\n    def _listen(self):\n        for i in range(1, 25):\n            colors = [i * v for v in self.basis]\n            self.write(colors)\n            time.sleep(0.01)\n\n        self.colors = colors\n\n    def _think(self):\n        colors = self.colors\n\n        self.next.clear()\n        while not self.next.is_set():\n            colors = colors[3:] + colors[:3]\n            self.write(colors)\n            time.sleep(0.2)\n\n        t = 0.1\n        for i in range(0, 5):\n            colors = colors[3:] + colors[:3]\n            self.write([(v * (4 - i) / 4) for v in colors])\n            time.sleep(t)\n            t /= 2\n\n        # time.sleep(0.5)\n\n        self.colors = colors\n\n    def _speak(self):\n        colors = self.colors\n\n        self.next.clear()\n        while not self.next.is_set():\n            for i in range(5, 25):\n                colors = [(v * i / 24) for v in colors]\n                self.write(colors)\n                time.sleep(0.01)\n\n            time.sleep(0.3)\n\n            for i in range(24, 4, -1):\n                colors = [(v * i / 24) for v in colors]\n                self.write(colors)\n                time.sleep(0.01)\n\n            time.sleep(0.3)\n\n        self._off()\n\n    def _off(self):\n        self.write([0] * 3 * self.PIXELS_N)\n\n    def write(self, colors):\n        for i in range(self.PIXELS_N):\n            self.dev.set_pixel(\n                i, int(colors[3 * i]), int(colors[3 * i + 1]), int(colors[3 * i + 2])\n            )\n\n        self.dev.show()\n\n\npixels = Pixels()\n\n\nif __name__ == \"__main__\":\n    while True:\n\n        try:\n            pixels.wakeup()\n            time.sleep(3)\n            pixels.think()\n            time.sleep(3)\n            pixels.speak()\n            time.sleep(3)\n            pixels.off()\n            time.sleep(3)\n        except KeyboardInterrupt:\n            break\n\n    pixels.off()\n    time.sleep(1)\n"
  },
  {
    "path": "robot/logging.py",
    "content": "import logging\nimport os\n\nfrom robot import constants\nfrom logging.handlers import RotatingFileHandler\n\nPAGE = 4096\n\nDEBUG = logging.DEBUG\nINFO = logging.INFO\nWARNING = logging.WARNING\nERROR = logging.ERROR\n\n\ndef tail(filepath, n=10):\n    \"\"\"\n    实现 tail -n\n    \"\"\"\n    res = \"\"\n    with open(filepath, \"rb\") as f:\n        f_len = f.seek(0, 2)\n        rem = f_len % PAGE\n        page_n = f_len // PAGE\n        r_len = rem if rem else PAGE\n        while True:\n            # 如果读取的页大小>=文件大小，直接读取数据输出\n            if r_len >= f_len:\n                f.seek(0)\n                lines = f.readlines()[::-1]\n                break\n\n            f.seek(-r_len, 2)\n            lines = f.readlines()[::-1]\n            count = len(lines) - 1  # 末行可能不完整，减一行，加大读取量\n\n            if count >= n:  # 如果读取到的行数>=指定行数，则退出循环读取数据\n                break\n            else:  # 如果读取行数不够，载入更多的页大小读取数据\n                r_len += PAGE\n                page_n -= 1\n\n    for line in lines[:n][::-1]:\n        res += line.decode(\"utf-8\")\n    return res\n\n\ndef getLogger(name):\n    \"\"\"\n    作用同标准模块 logging.getLogger(name)\n\n    :returns: logger\n    \"\"\"\n    format = \"%(asctime)s - %(name)s - %(filename)s - %(funcName)s - line %(lineno)s - %(levelname)s - %(message)s\"\n    formatter = logging.Formatter(format)\n    logging.basicConfig(format=format)\n    logger = logging.getLogger(name)\n    logger.setLevel(logging.INFO)\n\n    # FileHandler\n    file_handler = RotatingFileHandler(\n        os.path.join(constants.TEMP_PATH, \"wukong.log\"),\n        maxBytes=1024 * 1024,\n        backupCount=5,\n    )\n    file_handler.setLevel(level=logging.NOTSET)\n    file_handler.setFormatter(formatter)\n    logger.addHandler(file_handler)\n\n    return logger\n\n\ndef readLog(lines=200):\n    \"\"\"\n    获取最新的指定行数的 log\n\n    :param lines: 最大的行数\n    :returns: 最新指定行数的 log\n    \"\"\"\n    log_path = os.path.join(constants.TEMP_PATH, \"wukong.log\")\n    if os.path.exists(log_path):\n        return tail(log_path, lines)\n    return \"\"\n"
  },
  {
    "path": "robot/plugin_loader.py",
    "content": "# -*- coding: utf-8 -*-\nimport pkgutil\nfrom . import config\nfrom . import constants\nfrom robot import logging\nfrom robot.sdk.AbstractPlugin import AbstractPlugin\n\nlogger = logging.getLogger(__name__)\n_has_init = False\n\n# plugins run at query\n_plugins_query = []\n\n\ndef init_plugins(con):\n    \"\"\"\n    动态加载技能插件\n\n    参数：\n    con -- 会话模块\n    \"\"\"\n\n    global _has_init\n    locations = [constants.PLUGIN_PATH, constants.CONTRIB_PATH, constants.CUSTOM_PATH]\n    logger.debug(f\"检查插件目录：{locations}\")\n\n    global _plugins_query\n    nameSet = set()\n\n    for finder, name, ispkg in pkgutil.walk_packages(locations):\n        try:\n            loader = finder.find_module(name)\n            mod = loader.load_module(name)\n        except Exception:\n            logger.warning(f\"插件 {name} 加载出错，跳过\", exc_info=True)\n            continue\n\n        if not hasattr(mod, \"Plugin\"):\n            logger.debug(f\"模块 {name} 非插件，跳过\")\n            continue\n\n        # plugins run at query\n        plugin = mod.Plugin(con)\n\n        if plugin.SLUG == \"AbstractPlugin\":\n            plugin.SLUG = name\n\n        # check conflict\n        if plugin.SLUG in nameSet:\n            logger.warning(f\"插件 {name} SLUG({plugin.SLUG}) 重复，跳过\")\n            continue\n        nameSet.add(plugin.SLUG)\n\n        # whether a plugin is enabled\n        if config.has(plugin.SLUG) and \"enable\" in config.get(plugin.SLUG):\n            if not config.get(plugin.SLUG)[\"enable\"]:\n                logger.info(f\"插件 {name} 已被禁用\")\n                continue\n\n        if issubclass(mod.Plugin, AbstractPlugin):\n            logger.info(f\"插件 {name} 加载成功 \")\n            _plugins_query.append(plugin)\n\n    def sort_priority(m):\n        if hasattr(m, \"PRIORITY\"):\n            return m.PRIORITY\n        return 0\n\n    _plugins_query.sort(key=sort_priority, reverse=True)\n    _has_init = True\n\n\ndef get_plugins(con):\n    global _plugins_query\n    _plugins_query = []\n    init_plugins(con)\n    return _plugins_query\n"
  },
  {
    "path": "robot/sdk/AbstractPlugin.py",
    "content": "import sys\nfrom robot import logging\nfrom robot import constants\nfrom abc import ABCMeta, abstractmethod\n\nlogger = logging.getLogger(__name__)\n\ntry:\n    sys.path.append(constants.CONTRIB_PATH)\nexcept Exception as e:\n    logger.error(f\"未检测到插件目录, Error: {e}\", stack_info=True)\n\n\nclass AbstractPlugin(metaclass=ABCMeta):\n    \"\"\"技能插件基类\"\"\"\n\n    SLUG = \"AbstractPlugin\"\n    IS_IMMERSIVE = False\n\n    def __init__(self, con):\n        if self.IS_IMMERSIVE:\n            self.isImmersive = self.IS_IMMERSIVE\n        else:\n            self.isImmersive = False\n        self.priority = 0\n        self.con = con\n        self.nlu = self.con.nlu\n\n    def play(self, src, delete=False, onCompleted=None, volume=1):\n        \"\"\"\n        播放音频\n\n        :param play: 要播放的音频地址\n        :param delete: 播放完成是否要删除，默认不删除\n        :param onCompleted: 播放完后的回调\n        :param volume: 音量\n        \"\"\"\n        self.con.play(src, delete, onCompleted, volume)\n\n    def say(self, text, cache=False, onCompleted=None, wait=False):\n        \"\"\"\n        使用TTS说一句话\n\n        :param text: 要说话的内容\n        :param cache: 是否要缓存该音频，默认不缓存\n        :param onCompleted: 播放完后的回调\n        :param wait: 已废弃\n        \"\"\"\n        self.con.say(text, cache=cache, plugin=self.SLUG, onCompleted=onCompleted)\n\n    def activeListen(self, silent=False):\n        if (\n            self.SLUG != \"geek\"\n            and self.con.immersiveMode\n            and self.con.immersiveMode == \"geek\"\n        ):\n            # 极客模式下禁止其他插件主动聆听，以避免异常问题\n            self.con.player.stop()\n            self.critical(\"错误：请退出极客模式后再试\")\n            self.say(\"错误：请退出极客模式后再试\")\n            return \"\"\n        return self.con.activeListen(silent)\n\n    def clearImmersive(self):\n        self.con.setImmersiveMode(None)\n\n    def parse(self, query):\n        \"\"\"\n        NLU 解析\n        \"\"\"\n        return self.con.doParse(query)\n\n    @abstractmethod\n    def isValid(self, query, parsed):\n        \"\"\"\n        是否适合由该插件处理\n\n        参数：\n        query -- 用户的指令字符串\n        parsed -- 用户指令经过 NLU 解析后的结果\n\n        返回：\n        True: 适合由该插件处理\n        False: 不适合由该插件处理\n        \"\"\"\n        return False\n\n    @abstractmethod\n    def handle(self, query, parsed):\n        \"\"\"\n        处理逻辑\n\n        参数：\n        query -- 用户的指令字符串\n        parsed -- 用户指令经过 NLU 解析后的结果\n        \"\"\"\n        pass\n\n    def isValidImmersive(self, query, parsed):\n        \"\"\"\n        是否适合在沉浸模式下处理，\n        仅适用于有沉浸模式的插件（如音乐等）\n        当用户唤醒时，可以响应更多指令集。\n        例如：“\"上一首\"、\"下一首\" 等\n        \"\"\"\n        return False\n\n    def pause(self):\n        \"\"\"\n        暂停当前正在处理的任务，\n        当处于该沉浸模式下且被唤醒时，\n        将自动触发这个方法，\n        可以用于强制暂停一个耗时的操作\n        \"\"\"\n        return\n\n    def restore(self):\n        \"\"\"\n        恢复当前插件，\n        仅适用于有沉浸模式的插件（如音乐等）\n        当用户误唤醒或者唤醒进行闲聊后，\n        可以自动恢复当前插件的处理逻辑\n        \"\"\"\n        return\n"
  },
  {
    "path": "robot/sdk/AliSpeech.py",
    "content": "# -*- coding: UTF-8 -*-\n\nimport http.client\nimport urllib.parse\nimport json\nfrom robot import utils\nfrom robot import logging\n\nlogger = logging.getLogger(__name__)\n\n\ndef processGETRequest(appKey, token, voice, text, format, sampleRate):\n    host = \"nls-gateway.cn-shanghai.aliyuncs.com\"\n    url = \"https://\" + host + \"/stream/v1/tts\"\n    # 设置URL请求参数\n    url = url + \"?appkey=\" + appKey\n    url = url + \"&token=\" + token\n    url = url + \"&text=\" + text\n    url = url + \"&format=\" + format\n    url = url + \"&sample_rate=\" + str(sampleRate)\n    url = url + \"&voice=\" + voice\n    logger.debug(url)\n    conn = http.client.HTTPSConnection(host)\n    conn.request(method=\"GET\", url=url)\n    # 处理服务端返回的响应\n    response = conn.getresponse()\n    logger.debug(\"Response status and response reason:\")\n    logger.debug(response.status, response.reason)\n    contentType = response.getheader(\"Content-Type\")\n    logger.debug(contentType)\n    body = response.read()\n    if \"audio/mpeg\" == contentType:\n        logger.debug(\"The GET request succeed!\")\n        tmpfile = utils.write_temp_file(body, \".mp3\")\n        conn.close()\n        return tmpfile\n    else:\n        logger.debug(\"The GET request failed: \" + str(body))\n        conn.close()\n        return None\n\n\ndef processPOSTRequest(appKey, token, voice, text, format, sampleRate):\n    host = \"nls-gateway.cn-shanghai.aliyuncs.com\"\n    url = \"https://\" + host + \"/stream/v1/tts\"\n    # 设置HTTPS Headers\n    httpHeaders = {\"Content-Type\": \"application/json\"}\n    # 设置HTTPS Body\n    body = {\n        \"appkey\": appKey,\n        \"token\": token,\n        \"text\": text,\n        \"format\": format,\n        \"sample_rate\": sampleRate,\n        \"voice\": voice,\n    }\n    body = json.dumps(body)\n    logger.debug(\"The POST request body content: \" + body)\n    # Python 2.x 请使用httplib\n    # conn = httplib.HTTPSConnection(host)\n    # Python 3.x 请使用http.client\n    conn = http.client.HTTPSConnection(host)\n    conn.request(method=\"POST\", url=url, body=body, headers=httpHeaders)\n    # 处理服务端返回的响应\n    response = conn.getresponse()\n    logger.debug(\"Response status and response reason:\")\n    logger.debug(response.status, response.reason)\n    contentType = response.getheader(\"Content-Type\")\n    logger.debug(contentType)\n    body = response.read()\n    if \"audio/mpeg\" == contentType:\n        logger.debug(\"The POST request succeed!\")\n        tmpfile = utils.write_temp_file(body, \".mp3\")\n        conn.close()\n        return tmpfile\n    else:\n        logger.critical(\"The POST request failed: \" + str(body), stack_info=True)\n        conn.close()\n        return None\n\n\ndef process(request, token, audioContent):\n    # 读取音频文件\n    host = \"nls-gateway.cn-shanghai.aliyuncs.com\"\n    # 设置HTTP请求头部\n    httpHeaders = {\n        \"X-NLS-Token\": token,\n        \"Content-type\": \"application/octet-stream\",\n        \"Content-Length\": len(audioContent),\n    }\n    conn = http.client.HTTPConnection(host)\n    conn.request(method=\"POST\", url=request, body=audioContent, headers=httpHeaders)\n    response = conn.getresponse()\n    logger.debug(\"Response status and response reason:\")\n    logger.debug(response.status, response.reason)\n    body = response.read()\n    try:\n        logger.debug(\"Recognize response is:\")\n        body = json.loads(body)\n        logger.debug(body)\n        status = body[\"status\"]\n        if status == 20000000:\n            result = body[\"result\"]\n            logger.debug(\"Recognize result: \" + result)\n            conn.close()\n            return result\n        else:\n            logger.critical(\"Recognizer failed!\", stack_info=True)\n            conn.close()\n            return None\n    except ValueError:\n        logger.debug(\"The response is not json format string\")\n        conn.close()\n        return None\n\n\ndef tts(appKey, token, voice, text):\n    # 采用RFC 3986规范进行urlencode编码\n    textUrlencode = text\n    textUrlencode = urllib.parse.quote_plus(textUrlencode)\n    textUrlencode = textUrlencode.replace(\"+\", \"%20\")\n    textUrlencode = textUrlencode.replace(\"*\", \"%2A\")\n    textUrlencode = textUrlencode.replace(\"%7E\", \"~\")\n    format = \"mp3\"\n    sampleRate = 16000\n    return processPOSTRequest(appKey, token, voice, text, format, sampleRate)\n\n\ndef asr(appKey, token, wave_file):\n    # 服务请求地址\n    url = \"http://nls-gateway.cn-shanghai.aliyuncs.com/stream/v1/asr\"\n    pcm = utils.get_pcm_from_wav(wave_file)\n    # 音频文件\n    format = \"pcm\"\n    sampleRate = 16000\n    enablePunctuationPrediction = True\n    enableInverseTextNormalization = True\n    enableVoiceDetection = False\n    # 设置RESTful请求参数\n    request = url + \"?appkey=\" + appKey\n    request = request + \"&format=\" + format\n    request = request + \"&sample_rate=\" + str(sampleRate)\n    if enablePunctuationPrediction:\n        request = request + \"&enable_punctuation_prediction=\" + \"true\"\n    if enableInverseTextNormalization:\n        request = request + \"&enable_inverse_text_normalization=\" + \"true\"\n    if enableVoiceDetection:\n        request = request + \"&enable_voice_detection=\" + \"true\"\n    logger.debug(\"Request: \" + request)\n    return process(request, token, pcm)\n"
  },
  {
    "path": "robot/sdk/BaiduSpeech.py",
    "content": "# -*- coding:utf-8 -*-\nimport os\nimport json\nimport requests\nimport time\nfrom robot import logging\n\nlogger = logging.getLogger(__name__)\nTOKEN_PATH = os.path.expanduser(\"~/.wukong/.baiduSpeech_token\")\n\n# 百度语音识别 REST_API极速版\nclass baiduSpeech(object):\n    def __init__(self, api_key, secret_key, dev_pid):\n        self.api_key, self.secret_key, self.dev_pid = api_key, secret_key, dev_pid\n        if not os.path.exists(TOKEN_PATH):\n            self.token = self.fetch_token()\n        else:\n            self.token = self.load()\n\n    def fetch_token(self):\n        token_url = \"http://openapi.baidu.com/oauth/2.0/token\"\n        body = {\n            \"grant_type\": \"client_credentials\",\n            \"client_id\": self.api_key,\n            \"client_secret\": self.secret_key,\n        }\n        try:\n            req = requests.post(\n                token_url,\n                headers={\"Content-Type\": \"application/json; charset=UTF-8\"},\n                data=body,\n            )\n            s = req.content.decode(\"utf-8\", \"ignore\")\n            result = json.loads(s)\n            if \"access_token\" in result.keys() and \"scope\" in result.keys():\n                if not \"brain_enhanced_asr\" in result[\"scope\"].split(\" \"):\n                    logger.error(\"当前百度云api_id尚未有语音识别的授权。\")\n                #### 请求access_token成功.\n                with open(TOKEN_PATH, \"w\") as f:\n                    result = {\n                        key: result.get(key) for key in [\"access_token\", \"expires_in\"]\n                    }\n                    result[\"get_time\"] = time.time()\n                    data = json.dumps(result)\n                    f.write(data)\n                return result[\"access_token\"]\n        except Exception as err:\n            logger.error(f\"请求token_access失败: {err}\", stack_info=True)\n\n    def load(self):\n        def is_json(f):\n            try:\n                json_object = json.load(f)\n            except ValueError:\n                return False\n            return json_object\n\n        try:\n            with open(TOKEN_PATH, \"r\") as f:\n                access_token = is_json(f)\n                if not access_token:\n                    return self.fetch_token()\n                elif (\n                    time.time() - access_token[\"expires_in\"] - access_token[\"get_time\"]\n                    >= 0\n                ):\n                    return self.fetch_token()\n                else:\n                    return access_token[\"access_token\"]\n        except (OSError, KeyError, ValueError) as e:\n            print(f\"加载.baiduSpeech_token文件失败，请检查！原因是{e}\")\n\n    def asr(self, pcm, file_type, sample_rate, dev_pid):\n        asr_url = \"http://vop.baidu.com/pro_api\"\n        length = len(pcm)\n        if length == 0:\n            logger.error(f\"这个语音文件 {pcm} 是空的\")\n        headers = {\n            \"Content-Type\": \"audio/\" + file_type + \";rate=\" + str(sample_rate),\n            \"Content-Length\": str(length),\n        }\n        params = {\"cuid\": \"wukong-Robot\", \"token\": self.token, \"dev_pid\": self.dev_pid}\n\n        try:\n            req = requests.post(asr_url, params=params, headers=headers, data=pcm)\n            s = req.content.decode(\"utf-8\")\n            return json.loads(s)\n        except Exception as err:\n            logger.error(f\"百度ASR极速版请求失败: {err}\", stack_info=True)\n"
  },
  {
    "path": "robot/sdk/FunASREngine.py",
    "content": "\nfrom typing import Any\n\n\nclass funASREngine(object):\n    def __init__(self, inference_type, model_dir=''):\n        assert inference_type in ['onnxruntime'] # 当前只实现了onnxruntime的推理方案\n        self.inference_type = inference_type\n        if self.inference_type == 'onnxruntime':\n            # 调用下面的引擎进初始化引擎太慢了，因此放在条件分支里面\n            from funasr_onnx import Paraformer\n            self.engine_model = Paraformer(model_dir, batch_size=1, quantize=True)\n    \n    def onnxruntime_engine(self, audio_path):\n        result = self.engine_model(audio_path)\n        return str(result[0]['preds'][0])\n\n    def __call__(self, fp):\n        result = None\n        if self.inference_type == 'onnxruntime':\n            result = self.onnxruntime_engine(fp)\n        return result"
  },
  {
    "path": "robot/sdk/History.py",
    "content": "# -*- coding: utf-8 -*-\n# 用于维护历史消息\nimport tornado.locks\n\n\ndef Singleton(cls):\n    _instance = {}\n\n    def _singleton(*args, **kargs):\n        if cls not in _instance:\n            _instance[cls] = cls(*args, **kargs)\n        return _instance[cls]\n\n    return _singleton\n\n\n@Singleton\nclass History(object):\n    def __init__(self):\n        # cond is notified whenever the message cache is updated\n        self.cond = tornado.locks.Condition()\n        self.cache = []\n        self.cache_size = 200\n\n    def get_messages_since(self, cursor):\n        \"\"\"Returns a list of messages newer than the given cursor.\n\n        ``cursor`` should be the ``uuid`` of the last message received.\n        \"\"\"\n        results = []\n        for msg in reversed(self.cache):\n            if msg[\"uuid\"] == cursor:\n                break\n            results.append(msg)\n        results.reverse()\n        return results\n\n    def add_message(self, message):\n        self.cache.append(message)\n        if len(self.cache) > self.cache_size:\n            self.cache = self.cache[-self.cache_size :]\n        self.cond.notify_all()\n"
  },
  {
    "path": "robot/sdk/LED.py",
    "content": "import _thread as thread\nfrom robot import config, logging\nfrom robot.drivers.AIY import AIY\n\nlogger = logging.getLogger(__name__)\n\naiy = AIY()\n\n\ndef wakeup():\n    if config.get(\"/LED/enable\", False):\n        if config.get(\"/LED/type\") == \"aiy\":\n            thread.start_new_thread(aiy.wakeup, ())\n        elif config.get(\"/LED/type\") == \"respeaker\":\n            from robot.drivers.pixels import pixels\n\n            pixels.wakeup()\n        else:\n            logger.error(\"错误：不支持的灯光类型\", stack_info=True)\n\n\ndef think():\n    if config.get(\"/LED/enable\", False):\n        if config.get(\"/LED/type\") == \"aiy\":\n            thread.start_new_thread(aiy.think, ())\n        elif config.get(\"/LED/type\") == \"respeaker\":\n            from robot.drivers.pixels import pixels\n\n            pixels.think()\n        else:\n            logger.error(\"错误：不支持的灯光类型\", stack_info=True)\n\n\ndef off():\n    if config.get(\"/LED/enable\", False):\n        if config.get(\"/LED/type\") == \"aiy\":\n            thread.start_new_thread(aiy.off, ())\n        elif config.get(\"/LED/type\") == \"respeaker\":\n            from robot.drivers.pixels import pixels\n\n            pixels.off()\n        else:\n            logger.error(\"错误：不支持的灯光类型\", stack_info=True)\n"
  },
  {
    "path": "robot/sdk/RASRsdk.py",
    "content": "# -*- coding:utf-8 -*-\r\nimport urllib.request\r\nimport hmac\r\nimport hashlib\r\nimport base64\r\nimport time\r\nimport random\r\nimport os\r\nimport json\r\n\r\n\r\ndef formatSignString(param):\r\n    signstr = \"POSTaai.qcloud.com/asr/v1/\"\r\n    for t in param:\r\n        if \"appid\" in t:\r\n            signstr += str(t[1])\r\n            break\r\n    signstr += \"?\"\r\n    for x in param:\r\n        tmp = x\r\n        if \"appid\" in x:\r\n            continue\r\n        for t in tmp:\r\n            signstr += str(t)\r\n            signstr += \"=\"\r\n        signstr = signstr[:-1]\r\n        signstr += \"&\"\r\n    signstr = signstr[:-1]\r\n    # print 'signstr',signstr\r\n    return signstr\r\n\r\n\r\ndef sign(signstr, secret_key):\r\n    sign_bytes = bytes(signstr, \"utf-8\")\r\n    secret_bytes = bytes(secret_key, \"utf-8\")\r\n    hmacstr = hmac.new(secret_bytes, sign_bytes, hashlib.sha1).digest()\r\n    s = base64.b64encode(hmacstr).decode(\"utf-8\")\r\n    return s\r\n\r\n\r\ndef randstr(n):\r\n    seed = \"1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\"\r\n    sa = []\r\n    for i in range(n):\r\n        sa.append(random.choice(seed))\r\n    salt = \"\".join(sa)\r\n    # print salt\r\n    return salt\r\n\r\n\r\ndef sendVoice(\r\n    secret_key,\r\n    secretid,\r\n    appid,\r\n    engine_model_type,\r\n    res_type,\r\n    result_text_format,\r\n    voice_format,\r\n    filepath,\r\n    cutlength,\r\n    template_name=\"\",\r\n):\r\n    if len(str(secret_key)) == 0:\r\n        print(\"secretKey can not empty\")\r\n        return\r\n    if len(str(secretid)) == 0:\r\n        print(\"secretid can not empty\")\r\n        return\r\n    if len(str(appid)) == 0:\r\n        print(\"appid can not empty\")\r\n        return\r\n    if len(str(engine_model_type)) == 0 or (\r\n        str(engine_model_type) != \"8k_0\"\r\n        and str(engine_model_type) != \"16k_0\"\r\n        and str(engine_model_type) != \"16k_en\"\r\n    ):\r\n        print(\"engine_model_type is not right\")\r\n        return\r\n    if len(str(res_type)) == 0 or (str(res_type) != \"0\" and str(res_type) != \"1\"):\r\n        print(\"res_type is not right\")\r\n        return\r\n    if len(str(result_text_format)) == 0 or (\r\n        str(result_text_format) != \"0\"\r\n        and str(result_text_format) != \"1\"\r\n        and str(result_text_format) != \"2\"\r\n        and str(result_text_format) != \"3\"\r\n    ):\r\n        print(\"result_text_format is not right\")\r\n        return\r\n    if len(str(voice_format)) == 0 or (\r\n        str(voice_format) != \"1\"\r\n        and str(voice_format) != \"4\"\r\n        and str(voice_format) != \"6\"\r\n    ):\r\n        print(\"voice_format is not right\")\r\n        return\r\n    if len(str(filepath)) == 0:\r\n        print(\"filepath can not empty\")\r\n        return\r\n    if (\r\n        len(str(cutlength)) == 0\r\n        or str(cutlength).isdigit() == False\r\n        or cutlength > 200000\r\n    ):\r\n        print(\"cutlength can not empty\")\r\n        return\r\n    # secret_key = \"oaYWFO70LGDmcpfwo8uF1IInayysGtgZ\"\r\n    query_arr = dict()\r\n    query_arr[\"appid\"] = appid\r\n    query_arr[\"projectid\"] = 1013976\r\n    if len(template_name) > 0:\r\n        query_arr[\"template_name\"] = template_name\r\n    query_arr[\"sub_service_type\"] = 1\r\n    query_arr[\"engine_model_type\"] = engine_model_type\r\n    query_arr[\"res_type\"] = res_type\r\n    query_arr[\"result_text_format\"] = result_text_format\r\n    query_arr[\"voice_id\"] = randstr(16)\r\n    query_arr[\"timeout\"] = 100\r\n    query_arr[\"source\"] = 0\r\n    query_arr[\"secretid\"] = secretid\r\n    query_arr[\"timestamp\"] = str(int(time.time()))\r\n    query_arr[\"expired\"] = int(time.time()) + 24 * 60 * 60\r\n    query_arr[\"nonce\"] = query_arr[\"timestamp\"][0:4]\r\n    query_arr[\"voice_format\"] = voice_format\r\n    file_object = open(filepath, \"rb\")\r\n    file_object.seek(0, os.SEEK_END)\r\n    datalen = file_object.tell()\r\n    file_object.seek(0, os.SEEK_SET)\r\n    seq = 0\r\n    response = []\r\n    while datalen > 0:\r\n        end = 0\r\n        if datalen < cutlength:\r\n            end = 1\r\n        query_arr[\"end\"] = end\r\n        query_arr[\"seq\"] = seq\r\n        query = sorted(query_arr.items(), key=lambda d: d[0])\r\n        signstr = formatSignString(query)\r\n        autho = sign(signstr, secret_key)\r\n\r\n        if datalen < cutlength:\r\n            content = file_object.read(datalen)\r\n        else:\r\n            content = file_object.read(cutlength)\r\n        seq = seq + 1\r\n        datalen = datalen - cutlength\r\n        headers = dict()\r\n        headers[\"Authorization\"] = autho\r\n        headers[\"Content-Length\"] = len(content)\r\n        requrl = \"http://\"\r\n        requrl += signstr[4::]\r\n        req = urllib.request.Request(requrl, data=content, headers=headers)\r\n        res_data = urllib.request.urlopen(req)\r\n        r = res_data.read().decode(\"utf-8\")\r\n        res = json.loads(r)\r\n        if res[\"code\"] == 0:\r\n            response.append(res[\"text\"])\r\n    file_object.close()\r\n    return response[len(response) - 1]\r\n"
  },
  {
    "path": "robot/sdk/TencentSpeech.py",
    "content": "# coding: utf-8\n#!/usr/bin/env python3\n\n\n\"Tencent ASR && TTS API\"\n__author__ = \"Charles Li, Joseph Pan\"\n\nimport time\nimport uuid\nimport json\nimport random\nimport requests\nimport hmac\nimport base64\nimport urllib\n\n# 腾讯web API一句话识别请求\nclass tencentSpeech(object):\n    __slots__ = (\n        \"SECRET_ID\",\n        \"SECRET_KEY\",\n        \"SourceType\",\n        \"URL\",\n        \"VoiceFormat\",\n        \"PrimaryLanguage\",\n        \"Text\",\n        \"VoiceType\",\n        \"Region\",\n    )\n\n    def __init__(self, SECRET_KEY, SECRET_ID):\n        self.SECRET_KEY, self.SECRET_ID = SECRET_KEY, SECRET_ID\n\n    @property\n    def secret_id(self):\n        return self.SECRET_ID\n\n    @secret_id.setter\n    def secret_id(self, SECRET_ID):\n        if not isinstance(SECRET_ID, str):\n            raise ValueError(\"SecretId must be a string!\")\n        if len(SECRET_ID) == 0:\n            raise ValueError(\"SecretId can not be empty!\")\n        self.SECRET_ID = SECRET_ID\n\n    @property\n    def secret_key(self):\n        return self.SECRET_KEY\n\n    @secret_key.setter\n    def secret_key(self, SECRET_KEY):\n        if not isinstance(SECRET_KEY, str):\n            raise ValueError(\"SecretKey must be a string!\")\n        if len(SECRET_KEY) == 0:\n            raise ValueError(\"SecretKey can not be empty!\")\n        self.SECRET_KEY = SECRET_KEY\n\n    @property\n    def source_type(self):\n        return self.sourcetype\n\n    @source_type.setter\n    def source_type(self, SourceType):\n        if not isinstance(SourceType, str):\n            raise ValueError(\"SecretType must be an string!\")\n        if len(SourceType) == 0:\n            raise ValueError(\"SourceType can not be empty!\")\n        self.SourceType = SourceType\n\n    @property\n    def url(self):\n        return self.URL\n\n    @url.setter\n    def url(self, URL):\n        if not isinstance(URL, str):\n            raise ValueError(\"url must be an string!\")\n        if len(URL) == 0:\n            raise ValueError(\"url can not be empty!\")\n        self.URL = URL\n\n    @property\n    def voiceformat(self):\n        return self.VoiceFormat\n\n    @voiceformat.setter\n    def voiceformat(self, VoiceFormat):\n        if not isinstance(VoiceFormat, str):\n            raise ValueError(\"voiceformat must be an string!\")\n        if len(VoiceFormat) == 0:\n            raise ValueError(\"voiceformat can not be empty!\")\n        self.VoiceFormat = VoiceFormat\n\n    @property\n    def text(self):\n        return self.Text\n\n    @text.setter\n    def text(self, Text):\n        if not isinstance(Text, str):\n            raise ValueError(\"text must be an string!\")\n        if len(Text) == 0:\n            raise ValueError(\"text can not be empty!\")\n        self.Text = Text\n\n    @property\n    def region(self):\n        return self.Region\n\n    @region.setter\n    def region(self, Region):\n        if not isinstance(Region, str):\n            raise ValueError(\"region must be an string!\")\n        if len(Region) == 0:\n            raise ValueError(\"region can not be empty!\")\n        self.Region = Region\n\n    @property\n    def primarylanguage(self):\n        return self.PrimaryLanguage\n\n    @primarylanguage.setter\n    def primarylanguage(self, PrimaryLanguage):\n        self.PrimaryLanguage = PrimaryLanguage\n\n    @property\n    def voicetype(self):\n        return self.VoiceType\n\n    @voicetype.setter\n    def voicetype(self, VoiceType):\n        self.VoiceType = VoiceType\n\n    def TTS(self, text, voicetype, primarylanguage, region):\n        self.text, self.voicetype, self.primarylanguage, self.region = (\n            text,\n            voicetype,\n            primarylanguage,\n            region,\n        )\n        return self.textToSpeech()\n\n    def textToSpeech(self):\n        # 生成body\n        def make_body(config_dict, sign_encode):\n            ##注意URL编码的时候分str编码，整段编码会丢data\n            body = \"\"\n            for a, b in config_dict:\n                body += urllib.parse.quote(a) + \"=\" + urllib.parse.quote(str(b)) + \"&\"\n            return body + \"Signature=\" + sign_encode\n\n        HOST = \"aai.tencentcloudapi.com\"\n        config_dict = {\n            \"Action\": \"TextToVoice\",\n            \"Version\": \"2018-05-22\",\n            \"ProjectId\": 0,\n            \"Region\": self.Region,\n            \"VoiceType\": self.VoiceType,\n            \"Timestamp\": int(time.time()),\n            \"Nonce\": random.randint(100000, 200000),\n            \"SecretId\": self.SECRET_ID,\n            \"Text\": self.Text,\n            \"PrimaryLanguage\": self.PrimaryLanguage,\n            \"ModelType\": 1,\n            \"SessionId\": uuid.uuid1(),\n        }\n        # 按key排序\n        config_dict = sorted(config_dict.items())\n        signstr = self.formatSignString(config_dict)\n        sign_encode = urllib.parse.quote(self.encode_sign(signstr, self.SECRET_KEY))\n        body = make_body(config_dict, sign_encode)\n        # Get URL\n        req_url = \"https://aai.tencentcloudapi.com\"\n        header = {\n            \"Host\": HOST,\n            \"Content-Type\": \"application/x-www-form-urlencoded\",\n            \"Charset\": \"UTF-8\",\n        }\n        request = requests.post(req_url, headers=header, data=body)\n        # 有些音频utf8解码失败，存在编码错误\n        s = request.content.decode(\"utf8\", \"ignore\")\n        return json.loads(s)\n\n    def ASR(self, URL, voiceformat, sourcetype, region):\n        self.url, self.voiceformat, self.source_type, self.region = (\n            URL,\n            voiceformat,\n            sourcetype,\n            region,\n        )\n        return self.oneSentenceRecognition()\n\n    def oneSentenceRecognition(self):\n        # 生成body\n        def make_body(config_dict, sign_encode):\n            ##注意URL编码的时候分str编码，整段编码会丢data\n            body = \"\"\n            for a, b in config_dict:\n                body += urllib.parse.quote(a) + \"=\" + urllib.parse.quote(str(b)) + \"&\"\n            return body + \"Signature=\" + sign_encode\n\n        HOST = \"aai.tencentcloudapi.com\"\n        config_dict = {\n            \"Action\": \"SentenceRecognition\",\n            \"Version\": \"2018-05-22\",\n            \"Region\": self.Region,\n            \"ProjectId\": 0,\n            \"SubServiceType\": 2,\n            \"EngSerViceType\": \"16k\",\n            \"VoiceFormat\": self.VoiceFormat,\n            \"UsrAudioKey\": random.randint(0, 20),\n            \"Timestamp\": int(time.time()),\n            \"Nonce\": random.randint(100000, 200000),\n            \"SecretId\": self.SECRET_ID,\n            \"SourceType\": self.SourceType,\n        }\n        if self.SourceType == \"0\":\n            config_dict[\"Url\"] = urllib.parse.quote(str(self.url))\n        else:\n            # 不能大于1M\n            file_path = self.URL\n            file = open(file_path, \"rb\")\n            content = file.read()\n            config_dict[\"DataLen\"] = len(content)\n            config_dict[\"Data\"] = base64.b64encode(content).decode()\n            # config_dict['Data'] = content\n            file.close()\n        # 按key排序\n        config_dict = sorted(config_dict.items())\n        signstr = self.formatSignString(config_dict)\n        sign_encode = urllib.parse.quote(self.encode_sign(signstr, self.SECRET_KEY))\n        body = make_body(config_dict, sign_encode)\n        # Get URL\n        req_url = \"https://aai.tencentcloudapi.com\"\n        header = {\n            \"Host\": HOST,\n            \"Content-Type\": \"application/x-www-form-urlencoded\",\n            \"Charset\": \"UTF-8\",\n        }\n        request = requests.post(req_url, headers=header, data=body)\n        # 有些音频utf8解码失败，存在编码错误\n        s = request.content.decode(\"utf8\", \"ignore\")\n        return s\n\n    # 拼接url和参数\n    def formatSignString(self, config_dict):\n        signstr = \"POSTaai.tencentcloudapi.com/?\"\n        argArr = []\n        for a, b in config_dict:\n            argArr.append(a + \"=\" + str(b))\n        config_str = \"&\".join(argArr)\n        return signstr + config_str\n\n    # 生成签名\n    def encode_sign(self, signstr, SECRET_KEY):\n        myhmac = hmac.new(SECRET_KEY.encode(), signstr.encode(), digestmod=\"sha1\")\n        code = myhmac.digest()\n        # hmac() 完一定要decode()和 python 2 hmac不一样\n        signature = base64.b64encode(code).decode()\n        return signature\n"
  },
  {
    "path": "robot/sdk/Unihiker.py",
    "content": "from robot import constants, config\nfrom unihiker import Audio, GUI\nfrom pinpong.board import Board, Pin, Tone\nfrom pinpong.extension.unihiker import *\n\n\nclass Unihiker(object):\n    def __init__(self):\n        Board().begin()\n        self._gui = GUI()\n        self._tone = Tone(Pin(Pin.P26))\n        self._gui.draw_image(w=240, h=320, image=constants.getData(\"background.png\"))\n        self._my_bubble = self._gui.draw_text(\n            x=20, y=25, w=150, color=\"red\", text=\"(请说唤醒词)\", font_size=10\n        )\n        self._bot_bubble = self._gui.draw_text(\n            x=40, y=80, w=150, color=\"black\", text=\"\", font_size=10\n        )\n\n    def _play_tones(self, tones, duration):\n        for tone in tones:\n            self._tone.freq(tone)\n            self._tone.on()\n            time.sleep(duration)\n            self._tone.off()\n\n    def wakeup(self):\n        if config.get(\"/unihiker/beep\", False):\n            self._play_tones([225, 329], 0.1)\n\n    def think(self):\n        if config.get(\"/unihiker/beep\", False):\n            self._play_tones([329, 225], 0.1)\n\n    def record(self, t, text=\"\"):\n        self._my_bubble.config(\n            text=text, color=\"black\"\n        ) if t == 0 else self._bot_bubble.config(text=text)\n"
  },
  {
    "path": "robot/sdk/VITSClient.py",
    "content": "# coding: utf-8\n# !/usr/bin/env python3\n\n\"\"\"VITS TTS API\"\"\"\n\nimport requests\n\n\ndef tts(text, server_url, api_key, speaker_id, length, noise, noisew, max, timeout):\n    data = {\n        \"text\": text,\n        \"id\": speaker_id,\n        \"format\": \"wav\",\n        \"lang\": \"auto\",\n        \"length\": length,\n        \"noise\": noise,\n        \"noisew\": noisew,\n        \"max\": max\n    }\n    headers = {\"X-API-KEY\": api_key}\n    url = f\"{server_url}/voice\"\n    res = requests.post(url=url, data=data, headers=headers, timeout=timeout)\n    res.raise_for_status()\n    return res.content\n"
  },
  {
    "path": "robot/sdk/VolcengineSpeech.py",
    "content": "#coding=utf-8\n\n\"\"\"\nrequires Python 3.6 or later\n\npip install asyncio\npip install websockets\n\"\"\"\n\nimport asyncio\nimport base64\nfrom cProfile import run\nimport gzip\nimport hmac\nimport json\nimport requests\nimport logging\nimport os\nfrom typing_extensions import Self\nimport uuid\nimport wave\nfrom enum import Enum\nfrom hashlib import sha256\nfrom io import BytesIO\nfrom typing import List\nfrom urllib.parse import urlparse\nimport time\nimport websockets\nfrom robot import config\n\n\naudio_format = \"wav\"   # wav 或者 mp3，根据实际音频格式设置\n\nPROTOCOL_VERSION = 0b0001\nDEFAULT_HEADER_SIZE = 0b0001\n\nPROTOCOL_VERSION_BITS = 4\nHEADER_BITS = 4\nMESSAGE_TYPE_BITS = 4\nMESSAGE_TYPE_SPECIFIC_FLAGS_BITS = 4\nMESSAGE_SERIALIZATION_BITS = 4\nMESSAGE_COMPRESSION_BITS = 4\nRESERVED_BITS = 8\n\n# Message Type:\nCLIENT_FULL_REQUEST = 0b0001\nCLIENT_AUDIO_ONLY_REQUEST = 0b0010\nSERVER_FULL_RESPONSE = 0b1001\nSERVER_ACK = 0b1011\nSERVER_ERROR_RESPONSE = 0b1111\n\n# Message Type Specific Flags\nNO_SEQUENCE = 0b0000  # no check sequence\nPOS_SEQUENCE = 0b0001\nNEG_SEQUENCE = 0b0010\nNEG_SEQUENCE_1 = 0b0011\n\n# Message Serialization\nNO_SERIALIZATION = 0b0000\nJSON = 0b0001\nTHRIFT = 0b0011\nCUSTOM_TYPE = 0b1111\n\n# Message Compression\nNO_COMPRESSION = 0b0000\nGZIP = 0b0001\nCUSTOM_COMPRESSION = 0b1111\n\n\ndef generate_header(\n    version=PROTOCOL_VERSION,\n    message_type=CLIENT_FULL_REQUEST,\n    message_type_specific_flags=NO_SEQUENCE,\n    serial_method=JSON,\n    compression_type=GZIP,\n    reserved_data=0x00,\n    extension_header=bytes()\n):\n    \"\"\"\n    protocol_version(4 bits), header_size(4 bits),\n    message_type(4 bits), message_type_specific_flags(4 bits)\n    serialization_method(4 bits) message_compression(4 bits)\n    reserved （8bits) 保留字段\n    header_extensions 扩展头(大小等于 8 * 4 * (header_size - 1) )\n    \"\"\"\n    header = bytearray()\n    header_size = int(len(extension_header) / 4) + 1\n    header.append((version << 4) | header_size)\n    header.append((message_type << 4) | message_type_specific_flags)\n    header.append((serial_method << 4) | compression_type)\n    header.append(reserved_data)\n    header.extend(extension_header)\n    return header\n\n\ndef generate_full_default_header():\n    return generate_header()\n\n\ndef generate_audio_default_header():\n    return generate_header(\n        message_type=CLIENT_AUDIO_ONLY_REQUEST\n    )\n\n\ndef generate_last_audio_default_header():\n    return generate_header(\n        message_type=CLIENT_AUDIO_ONLY_REQUEST,\n        message_type_specific_flags=NEG_SEQUENCE\n    )\n\ndef parse_response(res):\n    \"\"\"\n    protocol_version(4 bits), header_size(4 bits),\n    message_type(4 bits), message_type_specific_flags(4 bits)\n    serialization_method(4 bits) message_compression(4 bits)\n    reserved （8bits) 保留字段\n    header_extensions 扩展头(大小等于 8 * 4 * (header_size - 1) )\n    payload 类似与http 请求体\n    \"\"\"\n    protocol_version = res[0] >> 4\n    header_size = res[0] & 0x0f\n    message_type = res[1] >> 4\n    message_type_specific_flags = res[1] & 0x0f\n    serialization_method = res[2] >> 4\n    message_compression = res[2] & 0x0f\n    reserved = res[3]\n    header_extensions = res[4:header_size * 4]\n    payload = res[header_size * 4:]\n    result = {}\n    payload_msg = None\n    payload_size = 0\n    if message_type == SERVER_FULL_RESPONSE:\n        payload_size = int.from_bytes(payload[:4], \"big\", signed=True)\n        payload_msg = payload[4:]\n    elif message_type == SERVER_ACK:\n        seq = int.from_bytes(payload[:4], \"big\", signed=True)\n        result['seq'] = seq\n        if len(payload) >= 8:\n            payload_size = int.from_bytes(payload[4:8], \"big\", signed=False)\n            payload_msg = payload[8:]\n    elif message_type == SERVER_ERROR_RESPONSE:\n        code = int.from_bytes(payload[:4], \"big\", signed=False)\n        result['code'] = code\n        payload_size = int.from_bytes(payload[4:8], \"big\", signed=False)\n        payload_msg = payload[8:]\n    if payload_msg is None:\n        return result\n    if message_compression == GZIP:\n        payload_msg = gzip.decompress(payload_msg)\n    if serialization_method == JSON:\n        payload_msg = json.loads(str(payload_msg, \"utf-8\"))\n    elif serialization_method != NO_SERIALIZATION:\n        payload_msg = str(payload_msg, \"utf-8\")\n    result['payload_msg'] = payload_msg\n    result['payload_size'] = payload_size\n    return result\n\n\ndef read_wav_info(data: bytes = None):\n    with BytesIO(data) as _f:\n        wave_fp = wave.open(_f, 'rb')\n        nchannels, sampwidth, framerate, nframes = wave_fp.getparams()[:4]\n        wave_bytes = wave_fp.readframes(nframes)\n    return nchannels, sampwidth, framerate, nframes, len(wave_bytes)\n\nclass AudioType(Enum):\n    LOCAL = 1  # 使用本地音频文件\n\nclass AsrWsClient:\n    def __init__(self, audio_path, cluster, **kwargs):\n        \"\"\"\n        :param config: config\n        \"\"\"\n        self.audio_path = audio_path\n        self.cluster = cluster\n        self.success_code = 1000  # success code, default is 1000\n        self.seg_duration = int(kwargs.get(\"seg_duration\", 15000))\n        self.nbest = int(kwargs.get(\"nbest\", 1))\n        self.appid = kwargs.get(\"appid\", \"\")\n        self.token = kwargs.get(\"token\", \"\")\n        self.ws_url = kwargs.get(\"ws_url\", \"wss://openspeech.bytedance.com/api/v2/asr\")\n        self.uid = kwargs.get(\"uid\", \"streaming_asr_demo\")\n        self.workflow = kwargs.get(\"workflow\", \"audio_in,resample,partition,vad,fe,decode,itn,nlu_punctuate\")\n        self.show_language = kwargs.get(\"show_language\", False)\n        self.show_utterances = kwargs.get(\"show_utterances\", False)\n        self.result_type = kwargs.get(\"result_type\", \"full\")\n        self.format = kwargs.get(\"format\", \"wav\")\n        self.rate = kwargs.get(\"sample_rate\", 16000)\n        self.language = kwargs.get(\"language\", \"zh-CN\")\n        self.bits = kwargs.get(\"bits\", 16)\n        self.channel = kwargs.get(\"channel\", 1)\n        self.codec = kwargs.get(\"codec\", \"raw\")\n        self.audio_type = kwargs.get(\"audio_type\", AudioType.LOCAL)\n        self.secret = kwargs.get(\"secret\", \"access_secret\")\n        self.auth_method = kwargs.get(\"auth_method\", \"token\")\n        self.mp3_seg_size = int(kwargs.get(\"mp3_seg_size\", 10000))\n\n    def construct_request(self, reqid):\n        req = {\n            'app': {\n                'appid': self.appid,\n                'cluster': self.cluster,\n                'token': self.token,\n            },\n            'user': {\n                'uid': self.uid\n            },\n            'request': {\n                'reqid': reqid,\n                'nbest': self.nbest,\n                'workflow': self.workflow,\n                'show_language': self.show_language,\n                'show_utterances': self.show_utterances,\n                'result_type': self.result_type,\n                \"sequence\": 1\n            },\n            'audio': {\n                'format': self.format,\n                'rate': self.rate,\n                'language': self.language,\n                'bits': self.bits,\n                'channel': self.channel,\n                'codec': self.codec\n            }\n        }\n        return req\n\n    @staticmethod\n    def slice_data(data: bytes, chunk_size: int):\n        \"\"\"\n        slice data\n        :param data: wav data\n        :param chunk_size: the segment size in one request\n        :return: segment data, last flag\n        \"\"\"\n        data_len = len(data)\n        offset = 0\n        while offset + chunk_size < data_len:\n            yield data[offset: offset + chunk_size], False\n            offset += chunk_size\n        else:\n            yield data[offset: data_len], True\n\n    def _real_processor(self, request_params: dict) -> dict:\n        pass\n\n    def token_auth(self):\n        return {'Authorization': 'Bearer; {}'.format(self.token)}\n\n    def signature_auth(self, data):\n        header_dicts = {\n            'Custom': 'auth_custom',\n        }\n\n        url_parse = urlparse(self.ws_url)\n        input_str = 'GET {} HTTP/1.1\\n'.format(url_parse.path)\n        auth_headers = 'Custom'\n        for header in auth_headers.split(','):\n            input_str += '{}\\n'.format(header_dicts[header])\n        input_data = bytearray(input_str, 'utf-8')\n        input_data += data\n        mac = base64.urlsafe_b64encode(\n            hmac.new(self.secret.encode('utf-8'), input_data, digestmod=sha256).digest())\n        header_dicts['Authorization'] = 'HMAC256; access_token=\"{}\"; mac=\"{}\"; h=\"{}\"'.format(self.token,\n                                                                                              str(mac, 'utf-8'), auth_headers)\n        return header_dicts\n\n    async def segment_data_processor(self, wav_data: bytes, segment_size: int):\n        reqid = str(uuid.uuid4())\n        # 构建 full client request，并序列化压缩\n        request_params = self.construct_request(reqid)\n        payload_bytes = str.encode(json.dumps(request_params))\n        payload_bytes = gzip.compress(payload_bytes)\n        full_client_request = bytearray(generate_full_default_header())\n        full_client_request.extend((len(payload_bytes)).to_bytes(4, 'big'))  # payload size(4 bytes)\n        full_client_request.extend(payload_bytes)  # payload\n        header = None\n        if self.auth_method == \"token\":\n            header = self.token_auth()\n        elif self.auth_method == \"signature\":\n            header = self.signature_auth(full_client_request)\n        async with websockets.connect(self.ws_url, extra_headers=header, max_size=1000000000) as ws:\n            # 发送 full client request\n            await ws.send(full_client_request)\n            res = await ws.recv()\n            result = parse_response(res)\n            if 'payload_msg' in result and result['payload_msg']['code'] != self.success_code:\n                return result\n            for seq, (chunk, last) in enumerate(AsrWsClient.slice_data(wav_data, segment_size), 1):\n                # if no compression, comment this line\n                payload_bytes = gzip.compress(chunk)\n                audio_only_request = bytearray(generate_audio_default_header())\n                if last:\n                    audio_only_request = bytearray(generate_last_audio_default_header())\n                audio_only_request.extend((len(payload_bytes)).to_bytes(4, 'big'))  # payload size(4 bytes)\n                audio_only_request.extend(payload_bytes)  # payload\n                # 发送 audio-only client request\n                await ws.send(audio_only_request)\n                res = await ws.recv()\n                result = parse_response(res)\n                if 'payload_msg' in result and result['payload_msg']['code'] != self.success_code:\n                    return result\n        return result\n\n    async def execute(self):\n        with open(self.audio_path, mode=\"rb\") as _f:\n            data = _f.read()\n        audio_data = bytes(data)\n        if self.format == \"mp3\":\n            segment_size = self.mp3_seg_size\n            return await self.segment_data_processor(audio_data, segment_size)\n        if self.format != \"wav\":\n            raise Exception(\"format should in wav or mp3\")\n        nchannels, sampwidth, framerate, nframes, wav_len = read_wav_info(\n            audio_data)\n        size_per_sec = nchannels * sampwidth * framerate\n        segment_size = int(size_per_sec * self.seg_duration / 1000)\n        return await self.segment_data_processor(audio_data, segment_size)\n\nclass VolcengineASR(object):\n    def __init__(self, **kwargs) -> None:\n        self.appid = kwargs['appid']\n        self.token = kwargs['token']\n        self.cluster = kwargs['cluster']\n    \n    def execute(self, path):\n        \"\"\"\n        :param audio_item: {\"path\": \"xxx\"}\n        :return:\n        \"\"\"\n        audio_type = AudioType.LOCAL\n        text = \"\"\n        asr_http_client = AsrWsClient(\n            audio_path=path,\n            cluster= self.cluster,\n            appid = self.appid,\n            token = self.token,\n            audio_type=audio_type,\n        )\n        try:\n            result = asyncio.run(asr_http_client.execute())\n            if result['payload_msg']['code'] == 1000:\n                text = result[\"payload_msg\"][\"result\"][0][\"text\"]\n        except Exception as e:\n            text = \"\"\n        return text\n\nclass VolcengineTTS(object):\n    def __init__(self, appid, token, cluster, voice_type) -> None:\n        self.appid, self.token, self.cluster, self.voice_type = appid, token, cluster, voice_type\n\n    def execute(self, text):\n        api_url = \"https://openspeech.bytedance.com/api/v1/tts\"\n        header = {\"Authorization\": f\"Bearer;{self.token}\"}\n        request_json = {\n            \"app\": {\n                \"appid\": self.appid,\n                \"token\": self.token,\n                \"cluster\": self.cluster\n            },\n            \"user\": {\n                \"uid\": \"388808087185088\"\n            },\n            \"audio\": {\n                \"voice_type\": self.voice_type,\n                \"encoding\": \"mp3\",\n                \"speed_ratio\": 1.0,\n                \"volume_ratio\": 1.0,\n                \"pitch_ratio\": 1.0,\n            },\n            \"request\": {\n                \"reqid\": str(uuid.uuid4()),\n                \"text\": text,\n                \"text_type\": \"plain\",\n                \"operation\": \"query\",\n                \"with_frontend\": 1,\n                \"frontend_type\": \"unitTson\"\n            }\n        }\n        try:\n            resp = requests.post(api_url, json.dumps(request_json), headers=header)\n            if \"data\" in resp.json():\n                data = resp.json()[\"data\"]\n                return base64.b64decode(data)\n        except Exception as e:\n            e.with_traceback()\n            return None"
  },
  {
    "path": "robot/sdk/XunfeiSpeech.py",
    "content": "import websocket\nimport hashlib\nimport base64\nimport hmac\nimport json\nimport wave\nimport tempfile\nfrom urllib.parse import urlencode\nimport time\nimport ssl\nfrom wsgiref.handlers import format_date_time\nfrom datetime import datetime\nfrom time import mktime\nimport _thread as thread\n\nfrom robot import logging\n\nlogger = logging.getLogger(__name__)\n\nSTATUS_FIRST_FRAME = 0  # 第一帧的标识\nSTATUS_CONTINUE_FRAME = 1  # 中间帧标识\nSTATUS_LAST_FRAME = 2  # 最后一帧的标识\n\nasrWsParam = None\nttsWsParam = None\n\ngResult = \"\"\ngTTSResult = \"\"\n\n\nclass ASR_Ws_Param(object):\n    # 初始化\n    def __init__(self, APPID, APIKey, APISecret, AudioFile):\n        # 控制台鉴权信息\n        self.APPID = APPID\n        self.APIKey = APIKey\n        self.APISecret = APISecret\n        self.AudioFile = AudioFile\n\n        # 公共参数(common)\n        self.CommonArgs = {\"app_id\": self.APPID}\n        # 业务参数(business)，更多个性化参数可在官网查看\n        self.BusinessArgs = {\"domain\": \"iat\", \"language\": \"zh_cn\", \"accent\": \"mandarin\"}\n\n    # 生成url\n    def create_url(self):\n        url = \"wss://ws-api.xfyun.cn/v2/iat\"\n        # 生成RFC1123格式的时间戳\n        now = datetime.now()\n        date = format_date_time(mktime(now.timetuple()))\n\n        # 拼接字符串\n        signature_origin = \"host: \" + \"ws-api.xfyun.cn\" + \"\\n\"\n        signature_origin += \"date: \" + date + \"\\n\"\n        signature_origin += \"GET \" + \"/v2/iat \" + \"HTTP/1.1\"\n        # 进行hmac-sha256进行加密\n        signature_sha = hmac.new(\n            self.APISecret.encode(\"utf-8\"),\n            signature_origin.encode(\"utf-8\"),\n            digestmod=hashlib.sha256,\n        ).digest()\n        signature_sha = base64.b64encode(signature_sha).decode(encoding=\"utf-8\")\n\n        authorization_origin = (\n            'api_key=\"%s\", algorithm=\"%s\", headers=\"%s\", signature=\"%s\"'\n            % (self.APIKey, \"hmac-sha256\", \"host date request-line\", signature_sha)\n        )\n        authorization = base64.b64encode(authorization_origin.encode(\"utf-8\")).decode(\n            encoding=\"utf-8\"\n        )\n        # 将请求的鉴权参数组合为字典\n        v = {\"authorization\": authorization, \"date\": date, \"host\": \"ws-api.xfyun.cn\"}\n        # 拼接鉴权参数，生成url\n        url = url + \"?\" + urlencode(v)\n        # 此处打印出建立连接时候的url,参考本demo的时候可取消上方打印的注释，比对相同参数时生成的url与自己代码生成的url是否一致\n        logger.debug(\"websocket url :\", url)\n        return url\n\n\nclass TTS_Ws_Param(object):\n    # 初始化\n    def __init__(self, APPID, APIKey, APISecret, Text, voice_name=\"xiaoyan\"):\n        self.APPID = APPID\n        self.APIKey = APIKey\n        self.APISecret = APISecret\n        self.Text = Text\n\n        # 公共参数(common)\n        self.CommonArgs = {\"app_id\": self.APPID}\n        # 业务参数(business)，更多个性化参数可在官网查看\n        self.BusinessArgs = {\n            \"aue\": \"raw\",\n            \"auf\": \"audio/L16;rate=16000\",\n            \"vcn\": voice_name,\n            \"tte\": \"utf8\",\n        }\n        self.Data = {\n            \"status\": 2,\n            \"text\": str(base64.b64encode(self.Text.encode(\"utf-8\")), \"UTF8\"),\n        }\n\n    # 生成url\n    def create_url(self):\n        url = \"wss://tts-api.xfyun.cn/v2/tts\"\n        # 生成RFC1123格式的时间戳\n        now = datetime.now()\n        date = format_date_time(mktime(now.timetuple()))\n\n        # 拼接字符串\n        signature_origin = \"host: \" + \"ws-api.xfyun.cn\" + \"\\n\"\n        signature_origin += \"date: \" + date + \"\\n\"\n        signature_origin += \"GET \" + \"/v2/tts \" + \"HTTP/1.1\"\n        # 进行hmac-sha256进行加密\n        signature_sha = hmac.new(\n            self.APISecret.encode(\"utf-8\"),\n            signature_origin.encode(\"utf-8\"),\n            digestmod=hashlib.sha256,\n        ).digest()\n        signature_sha = base64.b64encode(signature_sha).decode(encoding=\"utf-8\")\n\n        authorization_origin = (\n            'api_key=\"%s\", algorithm=\"%s\", headers=\"%s\", signature=\"%s\"'\n            % (self.APIKey, \"hmac-sha256\", \"host date request-line\", signature_sha)\n        )\n        authorization = base64.b64encode(authorization_origin.encode(\"utf-8\")).decode(\n            encoding=\"utf-8\"\n        )\n        # 将请求的鉴权参数组合为字典\n        v = {\"authorization\": authorization, \"date\": date, \"host\": \"ws-api.xfyun.cn\"}\n        # 拼接鉴权参数，生成url\n        url = url + \"?\" + urlencode(v)\n        # print(\"date: \",date)\n        # print(\"v: \",v)\n        # 此处打印出建立连接时候的url,参考本demo的时候可取消上方打印的注释，比对相同参数时生成的url与自己代码生成的url是否一致\n        # print('websocket url :', url)\n        return url\n\n\n# ASR 收到websocket消息的处理\ndef asr_on_message(ws, message):\n    global gResult\n    try:\n        code = json.loads(message)[\"code\"]\n        sid = json.loads(message)[\"sid\"]\n        if code != 0:\n            errMsg = json.loads(message)[\"message\"]\n            logger.critical(\n                \"xunfei-asr 识别出错了：sid:%s call error:%s code is:%s\"\n                % (sid, errMsg, code),\n                stack_info=True,\n            )\n        else:\n            data = json.loads(message)[\"data\"][\"result\"][\"ws\"]\n            result = \"\"\n            for i in data:\n                for w in i[\"cw\"]:\n                    result += w[\"w\"]\n            gResult = gResult + result\n            logger.info(\n                \"sid:%s call success!,data is:%s\"\n                % (sid, json.dumps(data, ensure_ascii=False))\n            )\n    except Exception as e:\n        logger.critical(f\"xunfei-asr 识别出错了：{e}\", stack_info=True)\n\n\n# ASR 收到websocket错误的处理\ndef asr_on_error(ws, error):\n    logger.error(\"xunfei-asr 识别出错：\", error)\n\n\n# ASR 收到websocket关闭的处理\ndef asr_on_close(ws, _foo, _bar):\n    logger.debug(\"### closed ###\")\n\n\n# ASR 收到websocket连接建立的处理\ndef asr_on_open(ws):\n    global asrWsParam\n\n    def run(*args):\n        frameSize = 1220  # 每一帧的音频大小\n        intervel = 0.04  # 发送音频间隔(单位:s)\n        status = STATUS_FIRST_FRAME  # 音频的状态信息，标识音频是第一帧，还是中间帧、最后一帧\n        with open(asrWsParam.AudioFile, \"rb\") as fp:\n            while True:\n                buf = fp.read(frameSize)\n                # 文件结束\n                if not buf:\n                    status = STATUS_LAST_FRAME\n                # 第一帧处理\n                # 发送第一帧音频，带business 参数\n                # appid 必须带上，只需第一帧发送\n                if status == STATUS_FIRST_FRAME:\n\n                    d = {\n                        \"common\": asrWsParam.CommonArgs,\n                        \"business\": asrWsParam.BusinessArgs,\n                        \"data\": {\n                            \"status\": 0,\n                            \"format\": \"audio/L16;rate=16000\",\n                            \"audio\": str(base64.b64encode(buf), \"utf-8\"),\n                            \"encoding\": \"raw\",\n                        },\n                    }\n                    d = json.dumps(d)\n                    ws.send(d)\n                    status = STATUS_CONTINUE_FRAME\n                # 中间帧处理\n                elif status == STATUS_CONTINUE_FRAME:\n                    d = {\n                        \"data\": {\n                            \"status\": 1,\n                            \"format\": \"audio/L16;rate=16000\",\n                            \"audio\": str(base64.b64encode(buf), \"utf-8\"),\n                            \"encoding\": \"raw\",\n                        }\n                    }\n                    ws.send(json.dumps(d))\n                # 最后一帧处理\n                elif status == STATUS_LAST_FRAME:\n                    d = {\n                        \"data\": {\n                            \"status\": 2,\n                            \"format\": \"audio/L16;rate=16000\",\n                            \"audio\": str(base64.b64encode(buf), \"utf-8\"),\n                            \"encoding\": \"raw\",\n                        }\n                    }\n                    ws.send(json.dumps(d))\n                    time.sleep(1)\n                    break\n                # 模拟音频采样间隔\n                time.sleep(intervel)\n        ws.close()\n\n    thread.start_new_thread(run, ())\n\n\n# 收到websocket消息的处理\ndef tts_on_message(ws, message):\n    try:\n        code = json.loads(message)[\"code\"]\n        sid = json.loads(message)[\"sid\"]\n        audio = json.loads(message)[\"data\"][\"audio\"]\n        audio = base64.b64decode(audio)\n        if code != 0:\n            errMsg = json.loads(message)[\"message\"]\n            logger.error(\"sid:%s call error:%s code is:%s\" % (sid, errMsg, code))\n        else:\n            with open(gTTSPath, \"ab\") as f:\n                f.write(audio)\n    except Exception as e:\n        logger.error(\"receive msg,but parse exception:\", e)\n\n\n# 收到websocket错误的处理\ndef tts_on_error(ws, error):\n    logger.error(\"xunfei-tts 合成出错：\", error)\n\n\n# 收到websocket关闭的处理\ndef tts_on_close(ws, _foo, _bar):\n    global gTTSResult\n    logger.debug(\"### closed ###\")\n    pcmdata = None\n    try:\n        with open(gTTSPath, \"rb\") as pcmfile:\n            pcmdata = pcmfile.read()\n        tmpfile = \"\"\n        with tempfile.NamedTemporaryFile() as f:\n            tmpfile = f.name\n        with wave.open(tmpfile, \"wb\") as wavfile:\n            wavfile.setparams((1, 2, 16000, 0, \"NONE\", \"NONE\"))\n            wavfile.writeframes(pcmdata)\n        gTTSResult = tmpfile\n    except Exception as e:\n        logger.error(f\"XunfeiSpeech error: {e}\", stack_info=True)\n\n\n# 收到websocket连接建立的处理\ndef tts_on_open(ws):\n    global ttsWsParam\n\n    def run(*args):\n        intervel = 2  # 等待结果间隔(单位:s)\n\n        d = {\n            \"common\": ttsWsParam.CommonArgs,\n            \"business\": ttsWsParam.BusinessArgs,\n            \"data\": ttsWsParam.Data,\n        }\n        d = json.dumps(d)\n        ws.send(d)\n        # sleep等待服务端返回结果\n        time.sleep(intervel)\n        ws.close()\n\n    thread.start_new_thread(run, ())\n\n\ndef transcribe(fpath, appid, api_key, api_secret):\n    \"\"\"\n    科大讯飞ASR\n    \"\"\"\n    global asrWsParam, gResult\n    gResult = \"\"\n    asrWsParam = ASR_Ws_Param(appid, api_key, APISecret=api_secret, AudioFile=fpath)\n    websocket.enableTrace(False)\n    wsUrl = asrWsParam.create_url()\n    ws = websocket.WebSocketApp(\n        wsUrl, on_message=asr_on_message, on_error=asr_on_error, on_close=asr_on_close\n    )\n    ws.on_open = asr_on_open\n    ws.run_forever(sslopt={\"cert_reqs\": ssl.CERT_NONE})\n    return gResult\n\n\ndef synthesize(msg, appid, api_key, api_secret, voice_name=\"xiaoyan\"):\n    \"\"\"\n    科大讯飞TTS\n    \"\"\"\n    global ttsWsParam, gTTSPath, gTTSResult\n    with tempfile.NamedTemporaryFile() as f:\n        gTTSPath = f.name\n    ttsWsParam = TTS_Ws_Param(\n        APPID=appid,\n        APIKey=api_key,\n        APISecret=api_secret,\n        Text=msg,\n        voice_name=voice_name,\n    )\n    websocket.enableTrace(False)\n    wsUrl = ttsWsParam.create_url()\n    ws = websocket.WebSocketApp(\n        wsUrl, on_message=tts_on_message, on_error=tts_on_error, on_close=tts_on_close\n    )\n    ws.on_open = tts_on_open\n    ws.run_forever(sslopt={\"cert_reqs\": ssl.CERT_NONE})\n    return gTTSResult\n"
  },
  {
    "path": "robot/sdk/__init__.py",
    "content": ""
  },
  {
    "path": "robot/sdk/atc.py",
    "content": "# # -*- coding=utf-8 -*-\n# digit=['零','一','二','三','四','五','六','七','八','九']\n# unit=['零','十','百','千','万','亿']\n# def arabic_to_chinese(number):\n# \tif number < 0:\n# \t\traise Exception(\"negative arg\")\n# \tif number < 10:\n# \t\treturn digit[number]\n# \telif number < 100:\n# \t\th = number // 10\n# \t\tif h != 1:\n# \t\t\treturn str(h) + \"十\" + arabic_to_chinese(number % 10)\n# \t\telse:\n# \t\t\treturn \"十\" + arabic_to_chinese(number % 10)\n# \telif number < 1000:\n# \t\tth = number // 100\n# \t\treturn str(th) + \"百\" + arabic_to_chinese(number % 100)\n# \telif number < 10000:\n# \t\tw = number // 1000\n# \t\treturn str(w) + \"千\" + arabic_to_chinese(number % 1000)\n# \telse:\n# \t\tpass\n\n\n# c = 1\n# def test(num, expected):\n# \tglobal c\n# \tactual = arabic_to_chinese(num)\n# \tif (actual != expected):\n# \t\tprint(c, actual, expected)\n# \telse:\n# \t\tprint(c, \"pass\")\n# \tc+=1\n\n\n# test(0, '零')\n# test(1, '一')\n# test(5, '五')\n# test(12, '十二')\n# test(30, '三十')\n# test(37, '三十七')\n# test(100, '一百')\n# test(150,'一百五十')\n# test(156,'一百五十六')\n# test(999,'九百九十九')\n# test(1000 ,'一千')\n# test(1001 ,'一千零一')\n# test(1001 ,'一千零一')\n\n# -*- coding: utf-8 -*-\n\n# Licensed under WTFPL or the Unlicense or CC0.\n# This uses Python 3, but it's easy to port to Python 2 by changing\n# strings to u'xx'.\n\nimport itertools\n\n\ndef num2chinese(num, big=False, simp=True, o=False, twoalt=False):\n    \"\"\"\n    Converts numbers to Chinese representations.\n    `big`   : use financial characters.\n    `simp`  : use simplified characters instead of traditional characters.\n    `o`     : use 〇 for zero.\n    `twoalt`: use 两/兩 for two when appropriate.\n    Note that `o` and `twoalt` is ignored when `big` is used,\n    and `twoalt` is ignored when `o` is used for formal representations.\n    \"\"\"\n    # check num first\n    nd = str(num)\n    if abs(float(nd)) >= 1e48:\n        raise ValueError(\"number out of range\")\n    elif \"e\" in nd:\n        raise ValueError(\"scientific notation is not supported\")\n    c_symbol = \"正负点\" if simp else \"正負點\"\n    if o:  # formal\n        twoalt = False\n    if big:\n        c_basic = \"零壹贰叁肆伍陆柒捌玖\" if simp else \"零壹貳參肆伍陸柒捌玖\"\n        c_unit1 = \"拾佰仟\"\n        c_twoalt = \"贰\" if simp else \"貳\"\n    else:\n        c_basic = \"〇一二三四五六七八九\" if o else \"零一二三四五六七八九\"\n        c_unit1 = \"十百千\"\n        if twoalt:\n            c_twoalt = \"两\" if simp else \"兩\"\n        else:\n            c_twoalt = \"二\"\n    c_unit2 = \"万亿兆京垓秭穰沟涧正载\" if simp else \"萬億兆京垓秭穰溝澗正載\"\n    revuniq = lambda l: \"\".join(k for k, g in itertools.groupby(reversed(l)))\n    nd = str(num)\n    result = []\n    if nd[0] == \"+\":\n        result.append(c_symbol[0])\n    elif nd[0] == \"-\":\n        result.append(c_symbol[1])\n    if \".\" in nd:\n        integer, remainder = nd.lstrip(\"+-\").split(\".\")\n    else:\n        integer, remainder = nd.lstrip(\"+-\"), None\n    if int(integer):\n        splitted = [integer[max(i - 4, 0) : i] for i in range(len(integer), 0, -4)]\n        intresult = []\n        for nu, unit in enumerate(splitted):\n            # special cases\n            if int(unit) == 0:  # 0000\n                intresult.append(c_basic[0])\n                continue\n            elif nu > 0 and int(unit) == 2:  # 0002\n                intresult.append(c_twoalt + c_unit2[nu - 1])\n                continue\n            ulist = []\n            unit = unit.zfill(4)\n            for nc, ch in enumerate(reversed(unit)):\n                if ch == \"0\":\n                    if ulist:  # ???0\n                        ulist.append(c_basic[0])\n                elif nc == 0:\n                    ulist.append(c_basic[int(ch)])\n                elif nc == 1 and ch == \"1\" and unit[1] == \"0\":\n                    # special case for tens\n                    # edit the 'elif' if you don't like\n                    # 十四, 三千零十四, 三千三百一十四\n                    ulist.append(c_unit1[0])\n                elif nc > 1 and ch == \"2\":\n                    ulist.append(c_twoalt + c_unit1[nc - 1])\n                else:\n                    ulist.append(c_basic[int(ch)] + c_unit1[nc - 1])\n            ustr = revuniq(ulist)\n            if nu == 0:\n                intresult.append(ustr)\n            else:\n                intresult.append(ustr + c_unit2[nu - 1])\n        result.append(revuniq(intresult).strip(c_basic[0]))\n    else:\n        result.append(c_basic[0])\n    if remainder:\n        result.append(c_symbol[2])\n        result.append(\"\".join(c_basic[int(ch)] for ch in remainder))\n    return \"\".join(result)\n"
  },
  {
    "path": "robot/sdk/unit.py",
    "content": "# encoding:utf-8\nimport os\nimport uuid\nimport json\nimport requests\nimport datetime\nfrom uuid import getnode as get_mac\nfrom robot import constants, logging\nfrom dateutil import parser as dparser\n\nlogger = logging.getLogger(__name__)\n\n\ndef get_token(api_key, secret_key):\n    cache = open(os.path.join(constants.TEMP_PATH, \"baidustt.ini\"), \"a+\")\n    try:\n        pms = cache.readlines()\n        if len(pms) > 0:\n            time = pms[0]\n            tk = pms[1]\n            # 计算token是否过期 官方说明一个月，这里保守29天\n            time = dparser.parse(time)\n            endtime = datetime.datetime.now()\n            if (endtime - time).days <= 29:\n                return tk\n    finally:\n        cache.close()\n    URL = \"http://openapi.baidu.com/oauth/2.0/token\"\n    params = {\n        \"grant_type\": \"client_credentials\",\n        \"client_id\": api_key,\n        \"client_secret\": secret_key,\n    }\n    r = requests.get(URL, params=params)\n    try:\n        r.raise_for_status()\n        token = r.json()[\"access_token\"]\n        return token\n    except requests.exceptions.HTTPError:\n        return \"\"\n\n\ndef getUnit(query, service_id, api_key, secret_key):\n    \"\"\"\n    NLU 解析\n\n    :param query: 用户的指令字符串\n    :param service_id: UNIT 的 service_id\n    :param api_key: UNIT apk_key\n    :param secret_key: UNIT secret_key\n    :returns: UNIT 解析结果。如果解析失败，返回 None\n    \"\"\"\n    access_token = get_token(api_key, secret_key)\n    url = (\n        \"https://aip.baidubce.com/rpc/2.0/unit/service/chat?access_token=\"\n        + access_token\n    )\n    request = {\"query\": query, \"user_id\": str(get_mac())[:32]}\n    body = {\n        \"log_id\": str(uuid.uuid1()),\n        \"version\": \"2.0\",\n        \"service_id\": service_id,\n        \"session_id\": str(uuid.uuid1()),\n        \"request\": request,\n    }\n    try:\n        headers = {\"Content-Type\": \"application/json\"}\n        request = requests.post(url, json=body, headers=headers)\n        return json.loads(request.text)\n    except Exception:\n        return None\n\n\ndef getIntent(parsed):\n    \"\"\"\n    提取意图\n\n    :param parsed: UNIT 解析结果\n    :returns: 意图数组\n    \"\"\"\n    if parsed and \"result\" in parsed and \"response_list\" in parsed[\"result\"]:\n        try:\n            return parsed[\"result\"][\"response_list\"][0][\"schema\"][\"intent\"]\n        except Exception as e:\n            logger.warning(e)\n            return \"\"\n    else:\n        return \"\"\n\n\ndef hasIntent(parsed, intent):\n    \"\"\"\n    判断是否包含某个意图\n\n    :param parsed: UNIT 解析结果\n    :param intent: 意图的名称\n    :returns: True: 包含; False: 不包含\n    \"\"\"\n    if parsed and \"result\" in parsed and \"response_list\" in parsed[\"result\"]:\n        response_list = parsed[\"result\"][\"response_list\"]\n        for response in response_list:\n            if (\n                \"schema\" in response\n                and \"intent\" in response[\"schema\"]\n                and response[\"schema\"][\"intent\"] == intent\n            ):\n                return True\n        return False\n    else:\n        return False\n\n\ndef getSlots(parsed, intent=\"\"):\n    \"\"\"\n        提取某个意图的所有词槽\n\n        :param parsed: UNIT 解析结果\n        :param intent: 意图的名称\n        :returns: 词槽列表。你可以通过 name 属性筛选词槽，\n    再通过 normalized_word 属性取出相应的值\n    \"\"\"\n    if parsed and \"result\" in parsed and \"response_list\" in parsed[\"result\"]:\n        response_list = parsed[\"result\"][\"response_list\"]\n        if intent == \"\":\n            try:\n                return parsed[\"result\"][\"response_list\"][0][\"schema\"][\"slots\"]\n            except Exception as e:\n                logger.warning(e)\n                return []\n        for response in response_list:\n            if (\n                \"schema\" in response\n                and \"intent\" in response[\"schema\"]\n                and \"slots\" in response[\"schema\"]\n                and response[\"schema\"][\"intent\"] == intent\n            ):\n                return response[\"schema\"][\"slots\"]\n        return []\n    else:\n        return []\n\n\ndef getSlotWords(parsed, intent, name):\n    \"\"\"\n    找出命中某个词槽的内容\n\n    :param parsed: UNIT 解析结果\n    :param intent: 意图的名称\n    :param name: 词槽名\n    :returns: 命中该词槽的值的列表。\n    \"\"\"\n    slots = getSlots(parsed, intent)\n    words = []\n    for slot in slots:\n        if slot[\"name\"] == name:\n            words.append(slot[\"normalized_word\"])\n    return words\n\n\ndef getSlotOriginalWords(parsed, intent, name):\n    \"\"\"\n    找出命中某个词槽的原始内容\n\n    :param parsed: UNIT 解析结果\n    :param intent: 意图的名称\n    :param name: 词槽名\n    :returns: 命中该词槽的值的列表。\n    \"\"\"\n    slots = getSlots(parsed, intent)\n    words = []\n    for slot in slots:\n        if slot[\"name\"] == name:\n            words.append(slot[\"original_word\"])\n    return words\n\n\ndef getSayByConfidence(parsed):\n    \"\"\"\n    提取 UNIT 置信度最高的回复文本\n\n    :param parsed: UNIT 解析结果\n    :returns: UNIT 的回复文本\n    \"\"\"\n    if parsed and \"result\" in parsed and \"response_list\" in parsed[\"result\"]:\n        response_list = parsed[\"result\"][\"response_list\"]\n        answer = {}\n        for response in response_list:\n            if (\n                \"schema\" in response\n                and \"intent_confidence\" in response[\"schema\"]\n                and (\n                    not answer\n                    or response[\"schema\"][\"intent_confidence\"]\n                    > answer[\"schema\"][\"intent_confidence\"]\n                )\n            ):\n                answer = response\n        return answer[\"action_list\"][0][\"say\"]\n    else:\n        return \"\"\n\n\ndef getSay(parsed, intent=\"\"):\n    \"\"\"\n    提取 UNIT 的回复文本\n\n    :param parsed: UNIT 解析结果\n    :param intent: 意图的名称\n    :returns: UNIT 的回复文本\n    \"\"\"\n    if parsed and \"result\" in parsed and \"response_list\" in parsed[\"result\"]:\n        response_list = parsed[\"result\"][\"response_list\"]\n        if intent == \"\":\n            try:\n                return response_list[0][\"action_list\"][0][\"say\"]\n            except Exception as e:\n                logger.warning(e)\n                return \"\"\n        for response in response_list:\n            if (\n                \"schema\" in response\n                and \"intent\" in response[\"schema\"]\n                and response[\"schema\"][\"intent\"] == intent\n            ):\n                try:\n                    return response[\"action_list\"][0][\"say\"]\n                except Exception as e:\n                    logger.warning(e)\n                    return \"\"\n        return \"\"\n    else:\n        return \"\"\n\n\nif __name__ == \"__main__\":\n    parsed = getUnit(\n        \"今天的天气\",\n        \"S13442\",\n        \"w5v7gUV3iPGsGntcM84PtOOM\",\n        \"KffXwW6E1alcGplcabcNs63Li6GvvnfL\",\n    )\n    print(parsed)\n"
  },
  {
    "path": "robot/statistic.py",
    "content": "# -*- coding: utf -8-*-\n\nfrom . import config\nimport uuid\nimport requests\nimport threading\n\n\ndef getUUID():\n    mac = uuid.UUID(int=uuid.getnode()).hex[-12:]\n    return \":\".join([mac[e : e + 2] for e in range(0, 11, 2)])\n\n\ndef report(t):\n    ReportThread(t).start()\n\n\nclass ReportThread(threading.Thread):\n    def __init__(self, t):\n        # 需要执行父类的初始化方法\n        threading.Thread.__init__(self)\n        self.t = t\n\n    def run(self):\n        to_report = config.get(\"statistic\", True)\n        if to_report:\n            try:\n                persona = config.get(\"robot_name_cn\", \"孙悟空\")\n                url = \"http://livecv.hahack.com:8022/statistic\"\n                payload = {\n                    \"type\": str(self.t),\n                    \"uuid\": getUUID(),\n                    \"name\": persona,\n                    \"project\": \"wukong\",\n                }\n                requests.post(url, data=payload, timeout=3)\n            except Exception:\n                return\n"
  },
  {
    "path": "robot/utils.py",
    "content": "# -*- coding: utf-8 -*-\n\nimport os\nimport tempfile\nimport wave\nimport shutil\nimport re\nimport time\nimport json\nimport yaml\nimport hashlib\nimport subprocess\nfrom . import constants, config\nfrom robot import logging\nfrom pydub import AudioSegment\nfrom pytz import timezone\nimport _thread as thread\n\nimport smtplib\nfrom email.mime.text import MIMEText\nfrom email.mime.multipart import MIMEMultipart\n\nlogger = logging.getLogger(__name__)\n\ndo_not_bother = False\nis_recordable = True\n\n\ndef sendEmail(\n    SUBJECT, BODY, ATTACH_LIST, TO, FROM, SENDER, PASSWORD, SMTP_SERVER, SMTP_PORT\n):\n    \"\"\"\n    发送邮件\n\n    :param SUBJECT: 邮件标题\n    :param BODY: 邮件正文\n    :param ATTACH_LIST: 附件\n    :param TO: 收件人\n    :param FROM: 发件人\n    :param SENDER: 发件人信息\n    :param PASSWORD: 密码\n    :param SMTP_SERVER: smtp 服务器\n    :param SMTP_PORT: smtp 端口号\n    :returns: True: 发送成功; False: 发送失败\n    \"\"\"\n    txt = MIMEText(BODY.encode(\"utf-8\"), \"html\", \"utf-8\")\n    msg = MIMEMultipart()\n    msg.attach(txt)\n\n    for attach in ATTACH_LIST:\n        try:\n            att = MIMEText(open(attach, \"rb\").read(), \"base64\", \"utf-8\")\n            filename = os.path.basename(attach)\n            att[\"Content-Type\"] = \"application/octet-stream\"\n            att[\"Content-Disposition\"] = 'attachment; filename=\"%s\"' % filename\n            msg.attach(att)\n        except Exception:\n            logger.error(f\"附件 {attach} 发送失败！\", stack_info=True)\n            continue\n\n    msg[\"From\"] = SENDER\n    msg[\"To\"] = TO\n    msg[\"Subject\"] = SUBJECT\n\n    try:\n        session = smtplib.SMTP(SMTP_SERVER)\n        session.connect(SMTP_SERVER, SMTP_PORT)\n        session.starttls()\n        session.login(FROM, PASSWORD)\n        session.sendmail(SENDER, TO, msg.as_string())\n        session.close()\n        return True\n    except Exception as e:\n        logger.error(e, stack_info=True)\n        return False\n\n\ndef emailUser(SUBJECT=\"\", BODY=\"\", ATTACH_LIST=[]):\n    \"\"\"\n    给用户发送邮件\n\n    :param SUBJECT: subject line of the email\n    :param BODY: body text of the email\n    :returns: True: 发送成功; False: 发送失败\n    \"\"\"\n    # add footer\n    if BODY:\n        BODY = \"%s，<br><br>这是您要的内容：<br>%s<br>\" % (config[\"first_name\"], BODY)\n\n    recipient = config.get(\"/email/address\", \"\")\n    robot_name = config.get(\"robot_name_cn\", \"wukong-robot\")\n    recipient = robot_name + \" <%s>\" % recipient\n    user = config.get(\"/email/address\", \"\")\n    password = config.get(\"/email/password\", \"\")\n    server = config.get(\"/email/smtp_server\", \"\")\n    port = config.get(\"/email/smtp_port\", \"\")\n\n    if not recipient or not user or not password or not server or not port:\n        return False\n    try:\n        sendEmail(\n            SUBJECT, BODY, ATTACH_LIST, user, user, recipient, password, server, port\n        )\n        return True\n    except Exception as e:\n        logger.error(e, stack_info=True)\n        return False\n\n\ndef get_file_content(filePath, flag=\"rb\"):\n    \"\"\"\n    读取文件内容并返回\n\n    :param filePath: 文件路径\n    :returns: 文件内容\n    :raises IOError: 读取失败则抛出 IOError\n    \"\"\"\n    with open(filePath, flag) as fp:\n        return fp.read()\n\n\ndef check_and_delete(fp, wait=0):\n    \"\"\"\n    检查并删除文件/文件夹\n\n    :param fp: 文件路径\n    \"\"\"\n\n    def run():\n        if wait > 0:\n            time.sleep(wait)\n        if isinstance(fp, str) and os.path.exists(fp):\n            if os.path.isfile(fp):\n                os.remove(fp)\n            else:\n                shutil.rmtree(fp)\n\n    thread.start_new_thread(run, ())\n\n\ndef write_temp_file(data, suffix, mode=\"w+b\"):\n    \"\"\"\n    写入临时文件\n\n    :param data: 数据\n    :param suffix: 后缀名\n    :param mode: 写入模式，默认为 w+b\n    :returns: 文件保存后的路径\n    \"\"\"\n    with tempfile.NamedTemporaryFile(mode=mode, suffix=suffix, delete=False) as f:\n        f.write(data)\n        tmpfile = f.name\n    return tmpfile\n\n\ndef get_pcm_from_wav(wav_path):\n    \"\"\"\n    从 wav 文件中读取 pcm\n\n    :param wav_path: wav 文件路径\n    :returns: pcm 数据\n    \"\"\"\n    wav = wave.open(wav_path, \"rb\")\n    return wav.readframes(wav.getnframes())\n\n\ndef convert_wav_to_mp3(wav_path):\n    \"\"\"\n    将 wav 文件转成 mp3\n\n    :param wav_path: wav 文件路径\n    :returns: mp3 文件路径\n    \"\"\"\n    if not os.path.exists(wav_path):\n        logger.critical(f\"文件错误 {wav_path}\", stack_info=True)\n        return None\n    mp3_path = wav_path.replace(\".wav\", \".mp3\")\n    AudioSegment.from_wav(wav_path).export(mp3_path, format=\"mp3\")\n    return mp3_path\n\n\ndef convert_mp3_to_wav(mp3_path):\n    \"\"\"\n    将 mp3 文件转成 wav\n\n    :param mp3_path: mp3 文件路径\n    :returns: wav 文件路径\n    \"\"\"\n    target = mp3_path.replace(\".mp3\", \".wav\")\n    if not os.path.exists(mp3_path):\n        logger.critical(f\"文件错误 {mp3_path}\", stack_info=True)\n        return None\n    AudioSegment.from_mp3(mp3_path).export(target, format=\"wav\")\n    return target\n\n\ndef clean():\n    \"\"\"清理垃圾数据\"\"\"\n    temp = constants.TEMP_PATH\n    temp_files = os.listdir(temp)\n    for f in temp_files:\n        if os.path.isfile(os.path.join(temp, f)) and re.match(\n            r\"output[\\d]*\\.wav\", os.path.basename(f)\n        ):\n            os.remove(os.path.join(temp, f))\n\n\ndef setRecordable(value):\n    \"\"\"设置是否可以开始录制语音\"\"\"\n    global is_recordable\n    is_recordable = value\n\n\ndef isRecordable():\n    \"\"\"是否可以开始录制语音\"\"\"\n    global is_recordable\n    return is_recordable\n\n\ndef is_proper_time():\n    \"\"\"是否合适时间\"\"\"\n    global do_not_bother\n    if do_not_bother == True:\n        return False\n    if not config.has(\"do_not_bother\"):\n        return True\n    bother_profile = config.get(\"do_not_bother\")\n    if not bother_profile[\"enable\"]:\n        return True\n    if \"since\" not in bother_profile or \"till\" not in bother_profile:\n        return True\n    since = bother_profile[\"since\"]\n    till = bother_profile[\"till\"]\n    current = time.localtime(time.time()).tm_hour\n    if till > since:\n        return current not in range(since, till)\n    else:\n        return not (current in range(since, 25) or current in range(-1, till))\n\n\ndef get_do_not_bother_on_hotword():\n    \"\"\"打开勿扰模式唤醒词\"\"\"\n    return config.get(\"/do_not_bother/on_hotword\", \"悟空别吵.pmdl\")\n\n\ndef get_do_not_bother_off_hotword():\n    \"\"\"关闭勿扰模式唤醒词\"\"\"\n    return config.get(\"/do_not_bother/off_hotword\", \"悟空醒醒.pmdl\")\n\n\ndef getTimezone():\n    \"\"\"获取时区\"\"\"\n    return timezone(config.get(\"timezone\", \"HKT\"))\n\n\ndef getTimemStap():\n    \"\"\"获取时间戳\"\"\"\n    return str(time.time()).replace(\".\", \"\")\n\n\ndef getCache(msg):\n    \"\"\"获取缓存的语音\"\"\"\n    md5 = hashlib.md5(msg.encode(\"utf-8\")).hexdigest()\n    cache_paths = [\n        os.path.join(constants.TEMP_PATH, md5 + ext)\n        for ext in [\".mp3\", \".wav\", \".asiff\"]\n    ]\n    return next((path for path in cache_paths if os.path.exists(path)), None)\n\n\ndef saveCache(voice, msg):\n    \"\"\"获取缓存的语音\"\"\"\n    _, ext = os.path.splitext(voice)\n    md5 = hashlib.md5(msg.encode(\"utf-8\")).hexdigest()\n    target = os.path.join(constants.TEMP_PATH, md5 + ext)\n    shutil.copyfile(voice, target)\n    return target\n\n\ndef lruCache():\n    \"\"\"清理最近未使用的缓存\"\"\"\n\n    def run(*args):\n        if config.get(\"/lru_cache/enable\", True):\n            days = config.get(\"/lru_cache/days\", 7)\n            subprocess.run(\n                'find . -name \"*.mp3\" -atime +%d -exec rm {} \\;' % days,\n                cwd=constants.TEMP_PATH,\n                shell=True,\n            )\n\n    thread.start_new_thread(run, ())\n\n\ndef validyaml(filename):\n    \"\"\"\n    校验 YAML 格式是否正确\n\n    :param filename: yaml文件路径\n    :returns: True: 正确; False: 不正确\n    \"\"\"\n    try:\n        with open(filename) as f:\n            str = f.read()\n            yaml.safe_load(str)\n            return True\n    except Exception:\n        return False\n\n\ndef validjson(s):\n    \"\"\"\n    校验某个 JSON 字符串是否正确\n\n    :param s: JOSN字符串\n    :returns: True: 正确; False: 不正确\n    \"\"\"\n    try:\n        json.loads(s)\n        return True\n    except Exception:\n        return False\n\n\ndef getPunctuations():\n    return [\",\", \"，\", \".\", \"。\", \"?\", \"？\", \"!\", \"！\", \"\\n\"]\n\n\ndef stripPunctuation(s):\n    \"\"\"\n    移除字符串末尾的标点\n    \"\"\"\n    punctuations = getPunctuations()\n    if any(s.endswith(p) for p in punctuations):\n        s = s[:-1]\n    return s\n"
  },
  {
    "path": "server/server.py",
    "content": "import os\nimport yaml\nimport json\nimport time\nimport base64\nimport random\nimport hashlib\nimport asyncio\nimport requests\nimport markdown\nimport threading\nimport subprocess\nimport tornado.web\nimport tornado.ioloop\nimport tornado.options\nimport tornado.httpserver\n\nfrom tornado.websocket import WebSocketHandler\nfrom urllib.parse import unquote\n\nfrom robot.sdk.History import History\nfrom robot import config, utils, logging, Updater, constants\nfrom tools import make_json, solr_tools\n\nlogger = logging.getLogger(__name__)\n\nconversation, wukong = None, None\ncommiting = False\n\nsuggestions = [\n    \"现在几点\",\n    \"你吃饭了吗\",\n    \"上海的天气\",\n    \"写一首关于大海的诗\",\n    \"来玩成语接龙\",\n    \"我有多少邮件\",\n    \"你叫什么名字\",\n    \"讲个笑话\",\n]\n\n\nclass BaseHandler(tornado.web.RequestHandler):\n    def isValidated(self):\n        if not self.get_secure_cookie(\"validation\"):\n            return False\n        return str(\n            self.get_secure_cookie(\"validation\"), encoding=\"utf-8\"\n        ) == config.get(\"/server/validate\", \"\")\n\n    def validate(self, validation):\n        if validation and '\"' in validation:\n            validation = validation.replace('\"', \"\")\n        return validation == config.get(\"/server/validate\", \"\") or validation == str(\n            self.get_cookie(\"validation\")\n        )\n\n\nclass MainHandler(BaseHandler):\n    def get(self):\n        global conversation, wukong, suggestions\n        if not self.isValidated():\n            self.redirect(\"/login\")\n            return\n        if conversation:\n            info = Updater.fetch()\n            suggestion = random.choice(suggestions)\n            notices = None\n            if \"notices\" in info:\n                notices = info[\"notices\"]\n            self.render(\n                \"index.html\",\n                update_info=info,\n                suggestion=suggestion,\n                notices=notices,\n                location=self.request.host,\n            )\n        else:\n            self.render(\"index.html\")\n\n\nclass MessageUpdatesHandler(BaseHandler):\n    \"\"\"Long-polling request for new messages.\n\n    Waits until new messages are available before returning anything.\n    \"\"\"\n\n    async def post(self):\n        if not self.validate(self.get_argument(\"validate\", default=None)):\n            res = {\"code\": 1, \"message\": \"illegal visit\"}\n            self.write(json.dumps(res))\n        else:\n            cursor = self.get_argument(\"cursor\", None)\n            history = History()\n            messages = history.get_messages_since(cursor)\n            while not messages:\n                # Save the Future returned here so we can cancel it in\n                # on_connection_close.\n                self.wait_future = history.cond.wait(timeout=1)\n                try:\n                    await self.wait_future\n                except asyncio.CancelledError:\n                    return\n                messages = history.get_messages_since(cursor)\n            if self.request.connection.stream.closed():\n                return\n            res = {\"code\": 0, \"message\": \"ok\", \"history\": json.dumps(messages)}\n            self.write(json.dumps(res))\n        self.finish()\n\n    def on_connection_close(self):\n        self.wait_future.cancel()\n\n\n\"\"\"\n负责跟前端通信，把机器人的响应内容传输给前端\n\"\"\"\n\n\nclass ChatWebSocketHandler(WebSocketHandler, BaseHandler):\n    clients = set()\n\n    def open(self):\n        self.clients.add(self)\n\n    def on_close(self):\n        self.clients.remove(self)\n\n    def send_response(self, msg, uuid, plugin=\"\"):\n        response = {\n            \"action\": \"new_message\",\n            \"type\": 1,\n            \"text\": msg,\n            \"uuid\": uuid,\n            \"plugin\": plugin,\n        }\n        self.write_message(json.dumps(response))\n\n\nclass ChatHandler(BaseHandler):\n    def onResp(self, msg, audio, plugin):\n        logger.info(f\"response msg: {msg}\")\n        res = {\n            \"code\": 0,\n            \"message\": \"ok\",\n            \"resp\": msg,\n            \"audio\": audio,\n            \"plugin\": plugin,\n        }\n        try:\n            self.write(json.dumps(res))\n            self.flush()\n        except:\n            pass\n\n    def onStream(self, data, uuid):\n        # 通过 ChatWebSocketHandler 发送给前端\n        for client in ChatWebSocketHandler.clients:\n            client.send_response(data, uuid, \"\")\n\n    def post(self):\n        global conversation\n        if self.validate(self.get_argument(\"validate\", default=None)):\n            if self.get_argument(\"type\") == \"text\":\n                query = self.get_argument(\"query\")\n                uuid = self.get_argument(\"uuid\")\n                if query == \"\":\n                    res = {\"code\": 1, \"message\": \"query text is empty\"}\n                    self.write(json.dumps(res))\n                else:\n                    conversation.doResponse(\n                        query,\n                        uuid,\n                        onSay=lambda msg, audio, plugin: self.onResp(\n                            msg, audio, plugin\n                        ),\n                        onStream=lambda data, resp_uuid: self.onStream(data, resp_uuid),\n                    )\n\n            elif self.get_argument(\"type\") == \"voice\":\n                voice_data = self.get_argument(\"voice\")\n                tmpfile = utils.write_temp_file(base64.b64decode(voice_data), \".wav\")\n                fname, suffix = os.path.splitext(tmpfile)\n                nfile = fname + \"-16k\" + suffix\n                # downsampling\n                soxCall = \"sox \" + tmpfile + \" \" + nfile + \" rate 16k\"\n                subprocess.call([soxCall], shell=True, close_fds=True)\n                utils.check_and_delete(tmpfile)\n                conversation.doConverse(\n                    nfile,\n                    onSay=lambda msg, audio, plugin: self.onResp(msg, audio, plugin),\n                    onStream=lambda data, resp_uuid: self.onStream(\n                        data, resp_uuid)\n\n                )\n            else:\n                res = {\"code\": 1, \"message\": \"illegal type\"}\n                self.write(json.dumps(res))\n        else:\n            res = {\"code\": 1, \"message\": \"illegal visit\"}\n            self.write(json.dumps(res))\n        self.finish()\n\n\nclass GetHistoryHandler(BaseHandler):\n    def get(self):\n        global conversation\n        if not self.validate(self.get_argument(\"validate\", default=None)):\n            res = {\"code\": 1, \"message\": \"illegal visit\"}\n            self.write(json.dumps(res))\n        else:\n            res = {\n                \"code\": 0,\n                \"message\": \"ok\",\n                \"history\": json.dumps(conversation.getHistory().cache),\n            }\n            self.write(json.dumps(res))\n        self.finish()\n\n\nclass GetLogHandler(BaseHandler):\n    def get(self):\n        if not self.validate(self.get_argument(\"validate\", default=None)):\n            res = {\"code\": 1, \"message\": \"illegal visit\"}\n            self.write(json.dumps(res))\n        else:\n            lines = self.get_argument(\"lines\", default=200)\n            res = {\"code\": 0, \"message\": \"ok\", \"log\": logging.readLog(lines)}\n            self.write(json.dumps(res))\n        self.finish()\n\n\nclass LogPageHandler(BaseHandler):\n    def get(self):\n        if not self.isValidated():\n            self.redirect(\"/login\")\n        else:\n            self.render(\"log.html\")\n\n\nclass OperateHandler(BaseHandler):\n    def post(self):\n        global wukong\n        if self.validate(self.get_argument(\"validate\", default=None)):\n            type = self.get_argument(\"type\")\n            if type in [\"restart\", \"0\"]:\n                res = {\"code\": 0, \"message\": \"ok\"}\n                self.write(json.dumps(res))\n                self.finish()\n                time.sleep(3)\n                wukong.restart()\n            else:\n                res = {\"code\": 1, \"message\": f\"illegal type {type}\"}\n                self.write(json.dumps(res))\n                self.finish()\n        else:\n            res = {\"code\": 1, \"message\": \"illegal visit\"}\n            self.write(json.dumps(res))\n            self.finish()\n\n\nclass ConfigPageHandler(BaseHandler):\n    def get(self):\n        if not self.isValidated():\n            self.redirect(\"/login\")\n        else:\n            self.render(\"config.html\", sensitivity=config.get(\"sensitivity\"))\n\n\nclass ConfigHandler(BaseHandler):\n    def get(self):\n        if not self.validate(self.get_argument(\"validate\", default=None)):\n            res = {\"code\": 1, \"message\": \"illegal visit\"}\n            self.write(json.dumps(res))\n        else:\n            key = self.get_argument(\"key\", default=\"\")\n            res = \"\"\n            if key == \"\":\n                res = {\n                    \"code\": 0,\n                    \"message\": \"ok\",\n                    \"config\": config.getText(),\n                    \"sensitivity\": config.get(\"sensitivity\", 0.5),\n                }\n            else:\n                res = {\"code\": 0, \"message\": \"ok\", \"value\": config.get(key)}\n            self.write(json.dumps(res))\n        self.finish()\n\n    def post(self):\n        if self.validate(self.get_argument(\"validate\", default=None)):\n            configStr = self.get_argument(\"config\")\n            try:\n                cfg = unquote(configStr)\n                yaml.safe_load(cfg)\n                config.dump(cfg)\n                res = {\"code\": 0, \"message\": \"ok\"}\n                self.write(json.dumps(res))\n            except:\n                res = {\"code\": 1, \"message\": \"YAML解析失败，请检查内容\"}\n                self.write(json.dumps(res))\n        else:\n            res = {\"code\": 1, \"message\": \"illegal visit\"}\n            self.write(json.dumps(res))\n        self.finish()\n\n\nclass DonateHandler(BaseHandler):\n    def get(self):\n        if not self.isValidated():\n            self.redirect(\"/login\")\n            return\n        r = requests.get(\n            \"https://raw.githubusercontent.com/wzpan/wukong-contrib/master/docs/donate.md\"\n        )\n        content = markdown.markdown(\n            r.text,\n            extensions=[\"codehilite\", \"tables\", \"fenced_code\", \"meta\", \"nl2br\", \"toc\"],\n        )\n        self.render(\"donate.html\", content=content)\n\n\nclass QAHandler(BaseHandler):\n    def get(self):\n        if not self.isValidated():\n            self.redirect(\"/login\")\n        else:\n            content = \"\"\n            with open(constants.getQAPath(), \"r\") as f:\n                content = f.read()\n            self.render(\"qa.html\", content=content)\n\n    def post(self):\n        if self.validate(self.get_argument(\"validate\", default=None)):\n            qaStr = self.get_argument(\"qa\")\n            qaJson = os.path.join(constants.TEMP_PATH, \"qa_json\")\n            try:\n                make_json.convert(qaStr, qaJson)\n                solr_tools.clear_documents(\n                    config.get(\"/anyq/host\", \"0.0.0.0\"),\n                    \"collection1\",\n                    config.get(\"/anyq/solr_port\", \"8900\"),\n                )\n                solr_tools.upload_documents(\n                    config.get(\"/anyq/host\", \"0.0.0.0\"),\n                    \"collection1\",\n                    config.get(\"/anyq/solr_port\", \"8900\"),\n                    qaJson,\n                    10,\n                )\n                with open(constants.getQAPath(), \"w\") as f:\n                    f.write(qaStr)\n                res = {\"code\": 0, \"message\": \"ok\"}\n                self.write(json.dumps(res))\n            except Exception as e:\n                logger.error(e, stack_info=True)\n                res = {\"code\": 1, \"message\": \"提交失败，请检查内容\"}\n                self.write(json.dumps(res))\n        else:\n            res = {\"code\": 1, \"message\": \"illegal visit\"}\n            self.write(json.dumps(res))\n        self.finish()\n\n\nclass APIHandler(BaseHandler):\n    def get(self):\n        if not self.isValidated():\n            self.redirect(\"/login\")\n        else:\n            content = \"\"\n            r = requests.get(\n                \"https://raw.githubusercontent.com/wzpan/wukong-contrib/master/docs/api.md\"\n            )\n            content = markdown.markdown(\n                r.text,\n                extensions=[\n                    \"codehilite\",\n                    \"tables\",\n                    \"fenced_code\",\n                    \"meta\",\n                    \"nl2br\",\n                    \"toc\",\n                ],\n            )\n            self.render(\"api.html\", content=content)\n\n\nclass UpdateHandler(BaseHandler):\n    def post(self):\n        global wukong\n        if self.validate(self.get_argument(\"validate\", default=None)):\n            if wukong.update():\n                res = {\"code\": 0, \"message\": \"ok\"}\n                self.write(json.dumps(res))\n                self.finish()\n                time.sleep(3)\n                wukong.restart()\n            else:\n                res = {\"code\": 1, \"message\": \"更新失败，请手动更新\"}\n                self.write(json.dumps(res))\n        else:\n            res = {\"code\": 1, \"message\": \"illegal visit\"}\n            self.write(json.dumps(res))\n        self.finish()\n\n\nclass LoginHandler(BaseHandler):\n    def get(self):\n        if self.isValidated():\n            self.redirect(\"/\")\n        else:\n            self.render(\"login.html\", error=None)\n\n    def post(self):\n        if self.get_argument(\"username\") == config.get(\n            \"/server/username\"\n        ) and hashlib.md5(\n            self.get_argument(\"password\").encode(\"utf-8\")\n        ).hexdigest() == config.get(\n            \"/server/validate\"\n        ):\n            logger.info(\"login success\")\n            self.set_secure_cookie(\"validation\", config.get(\"/server/validate\"))\n            self.redirect(\"/\")\n        else:\n            self.render(\"login.html\", error=\"登录失败\")\n\n\nclass LogoutHandler(BaseHandler):\n    def get(self):\n        if self.isValidated():\n            self.set_secure_cookie(\"validation\", \"\")\n        self.redirect(\"/login\")\n\n\nsettings = {\n    \"cookie_secret\": config.get(\n        \"/server/cookie_secret\", \"__GENERATE_YOUR_OWN_RANDOM_VALUE_HERE__\"\n    ),\n    \"template_path\": os.path.join(constants.APP_PATH, \"server/templates\"),\n    \"static_path\": os.path.join(constants.APP_PATH, \"server/static\"),\n    \"login_url\": \"/login\",\n    \"debug\": False,\n}\n\napplication = tornado.web.Application(\n    [\n        (r\"/\", MainHandler),\n        (r\"/login\", LoginHandler),\n        (r\"/history\", GetHistoryHandler),\n        (r\"/chat\", ChatHandler),\n        (r\"/websocket\", ChatWebSocketHandler),\n        (r\"/chat/updates\", MessageUpdatesHandler),\n        (r\"/config\", ConfigHandler),\n        (r\"/configpage\", ConfigPageHandler),\n        (r\"/operate\", OperateHandler),\n        (r\"/logpage\", LogPageHandler),\n        (r\"/log\", GetLogHandler),\n        (r\"/logout\", LogoutHandler),\n        (r\"/api\", APIHandler),\n        (r\"/qa\", QAHandler),\n        (r\"/upgrade\", UpdateHandler),\n        (r\"/donate\", DonateHandler),\n        # 废弃老接口\n        (r\"/getlog\", GetLogHandler),\n        (r\"/gethistory\", GetHistoryHandler),\n        (r\"/getconfig\", ConfigHandler),\n        (\n            r\"/photo/(.+\\.(?:png|jpg|jpeg|bmp|gif|JPG|PNG|JPEG|BMP|GIF))\",\n            tornado.web.StaticFileHandler,\n            {\"path\": config.get(\"/camera/dest_path\", \"server/static\")},\n        ),\n        (\n            r\"/audio/(.+\\.(?:mp3|wav|pcm))\",\n            tornado.web.StaticFileHandler,\n            {\"path\": constants.TEMP_PATH},\n        ),\n        (r\"/static/(.*)\", tornado.web.StaticFileHandler, {\"path\": \"server/static\"}),\n    ],\n    **settings,\n)\n\n\ndef start_server(con, wk):\n    global conversation, wukong\n    conversation = con\n    wukong = wk\n    if config.get(\"/server/enable\", False):\n        port = config.get(\"/server/port\", \"5001\")\n        try:\n            asyncio.set_event_loop(asyncio.new_event_loop())\n            application.listen(int(port))\n            tornado.ioloop.IOLoop.instance().start()\n        except Exception as e:\n            logger.critical(f\"服务器启动失败: {e}\", stack_info=True)\n\n\ndef run(conversation, wukong, debug=False):\n    settings[\"debug\"] = debug\n    t = threading.Thread(target=lambda: start_server(conversation, wukong))\n    t.start()\n"
  },
  {
    "path": "server/static/api.css",
    "content": "table {\n    margin-top:15px;\n    border-collapse:collapse;\n    border:1px solid #aaa;\n    width:100%;\n    margin-bottom:2em;\n}\ntable th {\n    vertical-align:baseline;\n    padding:5px 15px 5px 6px;\n    background-color:#3F3F3F;\n    border:1px solid #3F3F3F;\n    text-align:left;\n    color:#fff;\n}\ntable td {\n    vertical-align:middle;\n    padding:6px 15px 6px 6px;\n    border:1px solid #aaa;\n}\ntable tr:nth-child(odd) {\n    background-color:#F5F5F5;\n\n}\ntable tr:nth-child(even) {\n    background-color:#fff;\n}\n\nh1{\n    line-height:1.2em;\n}\n\nh2 {\n    margin-top:1em;\n    margin-bottom:0.6667em;\n}\n\nh1,h2,h3,h4,h5,h6{\n    text-rendering:optimizelegibility;\n    font-weight:bold\n}\npre {\n    word-break: break-all;\n    white-space: pre-wrap;\n}\n"
  },
  {
    "path": "server/static/bootbox.js",
    "content": "/**\n * bootbox.js [v4.4.0]\n *\n * http://bootboxjs.com/license.txt\n */\n\n// @see https://github.com/makeusabrew/bootbox/issues/180\n// @see https://github.com/makeusabrew/bootbox/issues/186\n(function (root, factory) {\n\n  \"use strict\";\n  if (typeof define === \"function\" && define.amd) {\n    // AMD. Register as an anonymous module.\n    define([\"jquery\"], factory);\n  } else if (typeof exports === \"object\") {\n    // Node. Does not work with strict CommonJS, but\n    // only CommonJS-like environments that support module.exports,\n    // like Node.\n    module.exports = factory(require(\"jquery\"));\n  } else {\n    // Browser globals (root is window)\n    root.bootbox = factory(root.jQuery);\n  }\n\n}(this, function init($, undefined) {\n\n  \"use strict\";\n\n  // the base DOM structure needed to create a modal\n  var templates = {\n    dialog:\n      \"<div class='bootbox modal' tabindex='-1' role='dialog'>\" +\n        \"<div class='modal-dialog'>\" +\n          \"<div class='modal-content'>\" +\n            \"<div class='modal-body'><div class='bootbox-body'></div></div>\" +\n          \"</div>\" +\n        \"</div>\" +\n      \"</div>\",\n    header:\n      \"<div class='modal-header'>\" +\n        \"<h4 class='modal-title'></h4>\" +\n      \"</div>\",\n    footer:\n      \"<div class='modal-footer'></div>\",\n    closeButton:\n      \"<button type='button' class='bootbox-close-button close' data-dismiss='modal' aria-hidden='true'>&times;</button>\",\n    form:\n      \"<form class='bootbox-form'></form>\",\n    inputs: {\n      text:\n        \"<input class='bootbox-input bootbox-input-text form-control' autocomplete=off type=text />\",\n      textarea:\n        \"<textarea class='bootbox-input bootbox-input-textarea form-control'></textarea>\",\n      email:\n        \"<input class='bootbox-input bootbox-input-email form-control' autocomplete='off' type='email' />\",\n      select:\n        \"<select class='bootbox-input bootbox-input-select form-control'></select>\",\n      checkbox:\n        \"<div class='checkbox'><label><input class='bootbox-input bootbox-input-checkbox' type='checkbox' /></label></div>\",\n      date:\n        \"<input class='bootbox-input bootbox-input-date form-control' autocomplete=off type='date' />\",\n      time:\n        \"<input class='bootbox-input bootbox-input-time form-control' autocomplete=off type='time' />\",\n      number:\n        \"<input class='bootbox-input bootbox-input-number form-control' autocomplete=off type='number' />\",\n      password:\n        \"<input class='bootbox-input bootbox-input-password form-control' autocomplete='off' type='password' />\"\n    }\n  };\n\n  var defaults = {\n    // default language\n    locale: \"en\",\n    // show backdrop or not. Default to static so user has to interact with dialog\n    backdrop: \"static\",\n    // animate the modal in/out\n    animate: true,\n    // additional class string applied to the top level dialog\n    className: null,\n    // whether or not to include a close button\n    closeButton: true,\n    // show the dialog immediately by default\n    show: true,\n    // dialog container\n    container: \"body\"\n  };\n\n  // our public object; augmented after our private API\n  var exports = {};\n\n  /**\n   * @private\n   */\n  function _t(key) {\n    var locale = locales[defaults.locale];\n    return locale ? locale[key] : locales.en[key];\n  }\n\n  function processCallback(e, dialog, callback) {\n    e.stopPropagation();\n    e.preventDefault();\n\n    // by default we assume a callback will get rid of the dialog,\n    // although it is given the opportunity to override this\n\n    // so, if the callback can be invoked and it *explicitly returns false*\n    // then we'll set a flag to keep the dialog active...\n    var preserveDialog = $.isFunction(callback) && callback.call(dialog, e) === false;\n\n    // ... otherwise we'll bin it\n    if (!preserveDialog) {\n      dialog.modal(\"hide\");\n    }\n  }\n\n  function getKeyLength(obj) {\n    // @TODO defer to Object.keys(x).length if available?\n    var k, t = 0;\n    for (k in obj) {\n      t ++;\n    }\n    return t;\n  }\n\n  function each(collection, iterator) {\n    var index = 0;\n    $.each(collection, function(key, value) {\n      iterator(key, value, index++);\n    });\n  }\n\n  function sanitize(options) {\n    var buttons;\n    var total;\n\n    if (typeof options !== \"object\") {\n      throw new Error(\"Please supply an object of options\");\n    }\n\n    if (!options.message) {\n      throw new Error(\"Please specify a message\");\n    }\n\n    // make sure any supplied options take precedence over defaults\n    options = $.extend({}, defaults, options);\n\n    if (!options.buttons) {\n      options.buttons = {};\n    }\n\n    buttons = options.buttons;\n\n    total = getKeyLength(buttons);\n\n    each(buttons, function(key, button, index) {\n\n      if ($.isFunction(button)) {\n        // short form, assume value is our callback. Since button\n        // isn't an object it isn't a reference either so re-assign it\n        button = buttons[key] = {\n          callback: button\n        };\n      }\n\n      // before any further checks make sure by now button is the correct type\n      if ($.type(button) !== \"object\") {\n        throw new Error(\"button with key \" + key + \" must be an object\");\n      }\n\n      if (!button.label) {\n        // the lack of an explicit label means we'll assume the key is good enough\n        button.label = key;\n      }\n\n      if (!button.className) {\n        if (total <= 2 && index === total-1) {\n          // always add a primary to the main option in a two-button dialog\n          button.className = \"btn-primary\";\n        } else {\n          button.className = \"btn-default\";\n        }\n      }\n    });\n\n    return options;\n  }\n\n  /**\n   * map a flexible set of arguments into a single returned object\n   * if args.length is already one just return it, otherwise\n   * use the properties argument to map the unnamed args to\n   * object properties\n   * so in the latter case:\n   * mapArguments([\"foo\", $.noop], [\"message\", \"callback\"])\n   * -> { message: \"foo\", callback: $.noop }\n   */\n  function mapArguments(args, properties) {\n    var argn = args.length;\n    var options = {};\n\n    if (argn < 1 || argn > 2) {\n      throw new Error(\"Invalid argument length\");\n    }\n\n    if (argn === 2 || typeof args[0] === \"string\") {\n      options[properties[0]] = args[0];\n      options[properties[1]] = args[1];\n    } else {\n      options = args[0];\n    }\n\n    return options;\n  }\n\n  /**\n   * merge a set of default dialog options with user supplied arguments\n   */\n  function mergeArguments(defaults, args, properties) {\n    return $.extend(\n      // deep merge\n      true,\n      // ensure the target is an empty, unreferenced object\n      {},\n      // the base options object for this type of dialog (often just buttons)\n      defaults,\n      // args could be an object or array; if it's an array properties will\n      // map it to a proper options object\n      mapArguments(\n        args,\n        properties\n      )\n    );\n  }\n\n  /**\n   * this entry-level method makes heavy use of composition to take a simple\n   * range of inputs and return valid options suitable for passing to bootbox.dialog\n   */\n  function mergeDialogOptions(className, labels, properties, args) {\n    //  build up a base set of dialog properties\n    var baseOptions = {\n      className: \"bootbox-\" + className,\n      buttons: createLabels.apply(null, labels)\n    };\n\n    // ensure the buttons properties generated, *after* merging\n    // with user args are still valid against the supplied labels\n    return validateButtons(\n      // merge the generated base properties with user supplied arguments\n      mergeArguments(\n        baseOptions,\n        args,\n        // if args.length > 1, properties specify how each arg maps to an object key\n        properties\n      ),\n      labels\n    );\n  }\n\n  /**\n   * from a given list of arguments return a suitable object of button labels\n   * all this does is normalise the given labels and translate them where possible\n   * e.g. \"ok\", \"confirm\" -> { ok: \"OK, cancel: \"Annuleren\" }\n   */\n  function createLabels() {\n    var buttons = {};\n\n    for (var i = 0, j = arguments.length; i < j; i++) {\n      var argument = arguments[i];\n      var key = argument.toLowerCase();\n      var value = argument.toUpperCase();\n\n      buttons[key] = {\n        label: _t(value)\n      };\n    }\n\n    return buttons;\n  }\n\n  function validateButtons(options, buttons) {\n    var allowedButtons = {};\n    each(buttons, function(key, value) {\n      allowedButtons[value] = true;\n    });\n\n    each(options.buttons, function(key) {\n      if (allowedButtons[key] === undefined) {\n        throw new Error(\"button key \" + key + \" is not allowed (options are \" + buttons.join(\"\\n\") + \")\");\n      }\n    });\n\n    return options;\n  }\n\n  exports.alert = function() {\n    var options;\n\n    options = mergeDialogOptions(\"alert\", [\"ok\"], [\"message\", \"callback\"], arguments);\n\n    if (options.callback && !$.isFunction(options.callback)) {\n      throw new Error(\"alert requires callback property to be a function when provided\");\n    }\n\n    /**\n     * overrides\n     */\n    options.buttons.ok.callback = options.onEscape = function() {\n      if ($.isFunction(options.callback)) {\n        return options.callback.call(this);\n      }\n      return true;\n    };\n\n    return exports.dialog(options);\n  };\n\n  exports.confirm = function() {\n    var options;\n\n    options = mergeDialogOptions(\"confirm\", [\"cancel\", \"confirm\"], [\"message\", \"callback\"], arguments);\n\n    /**\n     * overrides; undo anything the user tried to set they shouldn't have\n     */\n    options.buttons.cancel.callback = options.onEscape = function() {\n      return options.callback.call(this, false);\n    };\n\n    options.buttons.confirm.callback = function() {\n      return options.callback.call(this, true);\n    };\n\n    // confirm specific validation\n    if (!$.isFunction(options.callback)) {\n      throw new Error(\"confirm requires a callback\");\n    }\n\n    return exports.dialog(options);\n  };\n\n  exports.prompt = function() {\n    var options;\n    var defaults;\n    var dialog;\n    var form;\n    var input;\n    var shouldShow;\n    var inputOptions;\n\n    // we have to create our form first otherwise\n    // its value is undefined when gearing up our options\n    // @TODO this could be solved by allowing message to\n    // be a function instead...\n    form = $(templates.form);\n\n    // prompt defaults are more complex than others in that\n    // users can override more defaults\n    // @TODO I don't like that prompt has to do a lot of heavy\n    // lifting which mergeDialogOptions can *almost* support already\n    // just because of 'value' and 'inputType' - can we refactor?\n    defaults = {\n      className: \"bootbox-prompt\",\n      buttons: createLabels(\"cancel\", \"confirm\"),\n      value: \"\",\n      inputType: \"text\"\n    };\n\n    options = validateButtons(\n      mergeArguments(defaults, arguments, [\"title\", \"callback\"]),\n      [\"cancel\", \"confirm\"]\n    );\n\n    // capture the user's show value; we always set this to false before\n    // spawning the dialog to give us a chance to attach some handlers to\n    // it, but we need to make sure we respect a preference not to show it\n    shouldShow = (options.show === undefined) ? true : options.show;\n\n    /**\n     * overrides; undo anything the user tried to set they shouldn't have\n     */\n    options.message = form;\n\n    options.buttons.cancel.callback = options.onEscape = function() {\n      return options.callback.call(this, null);\n    };\n\n    options.buttons.confirm.callback = function() {\n      var value;\n\n      switch (options.inputType) {\n        case \"text\":\n        case \"textarea\":\n        case \"email\":\n        case \"select\":\n        case \"date\":\n        case \"time\":\n        case \"number\":\n        case \"password\":\n          value = input.val();\n          break;\n\n        case \"checkbox\":\n          var checkedItems = input.find(\"input:checked\");\n\n          // we assume that checkboxes are always multiple,\n          // hence we default to an empty array\n          value = [];\n\n          each(checkedItems, function(_, item) {\n            value.push($(item).val());\n          });\n          break;\n      }\n\n      return options.callback.call(this, value);\n    };\n\n    options.show = false;\n\n    // prompt specific validation\n    if (!options.title) {\n      throw new Error(\"prompt requires a title\");\n    }\n\n    if (!$.isFunction(options.callback)) {\n      throw new Error(\"prompt requires a callback\");\n    }\n\n    if (!templates.inputs[options.inputType]) {\n      throw new Error(\"invalid prompt type\");\n    }\n\n    // create the input based on the supplied type\n    input = $(templates.inputs[options.inputType]);\n\n    switch (options.inputType) {\n      case \"text\":\n      case \"textarea\":\n      case \"email\":\n      case \"date\":\n      case \"time\":\n      case \"number\":\n      case \"password\":\n        input.val(options.value);\n        break;\n\n      case \"select\":\n        var groups = {};\n        inputOptions = options.inputOptions || [];\n\n        if (!$.isArray(inputOptions)) {\n          throw new Error(\"Please pass an array of input options\");\n        }\n\n        if (!inputOptions.length) {\n          throw new Error(\"prompt with select requires options\");\n        }\n\n        each(inputOptions, function(_, option) {\n\n          // assume the element to attach to is the input...\n          var elem = input;\n\n          if (option.value === undefined || option.text === undefined) {\n            throw new Error(\"given options in wrong format\");\n          }\n\n          // ... but override that element if this option sits in a group\n\n          if (option.group) {\n            // initialise group if necessary\n            if (!groups[option.group]) {\n              groups[option.group] = $(\"<optgroup/>\").attr(\"label\", option.group);\n            }\n\n            elem = groups[option.group];\n          }\n\n          elem.append(\"<option value='\" + option.value + \"'>\" + option.text + \"</option>\");\n        });\n\n        each(groups, function(_, group) {\n          input.append(group);\n        });\n\n        // safe to set a select's value as per a normal input\n        input.val(options.value);\n        break;\n\n      case \"checkbox\":\n        var values   = $.isArray(options.value) ? options.value : [options.value];\n        inputOptions = options.inputOptions || [];\n\n        if (!inputOptions.length) {\n          throw new Error(\"prompt with checkbox requires options\");\n        }\n\n        if (!inputOptions[0].value || !inputOptions[0].text) {\n          throw new Error(\"given options in wrong format\");\n        }\n\n        // checkboxes have to nest within a containing element, so\n        // they break the rules a bit and we end up re-assigning\n        // our 'input' element to this container instead\n        input = $(\"<div/>\");\n\n        each(inputOptions, function(_, option) {\n          var checkbox = $(templates.inputs[options.inputType]);\n\n          checkbox.find(\"input\").attr(\"value\", option.value);\n          checkbox.find(\"label\").append(option.text);\n\n          // we've ensured values is an array so we can always iterate over it\n          each(values, function(_, value) {\n            if (value === option.value) {\n              checkbox.find(\"input\").prop(\"checked\", true);\n            }\n          });\n\n          input.append(checkbox);\n        });\n        break;\n    }\n\n    // @TODO provide an attributes option instead\n    // and simply map that as keys: vals\n    if (options.placeholder) {\n      input.attr(\"placeholder\", options.placeholder);\n    }\n\n    if (options.pattern) {\n      input.attr(\"pattern\", options.pattern);\n    }\n\n    if (options.maxlength) {\n      input.attr(\"maxlength\", options.maxlength);\n    }\n\n    // now place it in our form\n    form.append(input);\n\n    form.on(\"submit\", function(e) {\n      e.preventDefault();\n      // Fix for SammyJS (or similar JS routing library) hijacking the form post.\n      e.stopPropagation();\n      // @TODO can we actually click *the* button object instead?\n      // e.g. buttons.confirm.click() or similar\n      dialog.find(\".btn-primary\").click();\n    });\n\n    dialog = exports.dialog(options);\n\n    // clear the existing handler focusing the submit button...\n    dialog.off(\"shown.bs.modal\");\n\n    // ...and replace it with one focusing our input, if possible\n    dialog.on(\"shown.bs.modal\", function() {\n      // need the closure here since input isn't\n      // an object otherwise\n      input.focus();\n    });\n\n    if (shouldShow === true) {\n      dialog.modal(\"show\");\n    }\n\n    return dialog;\n  };\n\n  exports.dialog = function(options) {\n    options = sanitize(options);\n\n    var dialog = $(templates.dialog);\n    var innerDialog = dialog.find(\".modal-dialog\");\n    var body = dialog.find(\".modal-body\");\n    var buttons = options.buttons;\n    var buttonStr = \"\";\n    var callbacks = {\n      onEscape: options.onEscape\n    };\n\n    if ($.fn.modal === undefined) {\n      throw new Error(\n        \"$.fn.modal is not defined; please double check you have included \" +\n        \"the Bootstrap JavaScript library. See http://getbootstrap.com/javascript/ \" +\n        \"for more details.\"\n      );\n    }\n\n    each(buttons, function(key, button) {\n\n      // @TODO I don't like this string appending to itself; bit dirty. Needs reworking\n      // can we just build up button elements instead? slower but neater. Then button\n      // can just become a template too\n      buttonStr += \"<button data-bb-handler='\" + key + \"' type='button' class='btn \" + button.className + \"'>\" + button.label + \"</button>\";\n      callbacks[key] = button.callback;\n    });\n\n    body.find(\".bootbox-body\").html(options.message);\n\n    if (options.animate === true) {\n      dialog.addClass(\"fade\");\n    }\n\n    if (options.className) {\n      dialog.addClass(options.className);\n    }\n\n    if (options.size === \"large\") {\n      innerDialog.addClass(\"modal-lg\");\n    } else if (options.size === \"small\") {\n      innerDialog.addClass(\"modal-sm\");\n    }\n\n    if (options.title) {\n      body.before(templates.header);\n    }\n\n    if (options.closeButton) {\n      var closeButton = $(templates.closeButton);\n\n      if (options.title) {\n        dialog.find(\".modal-header\").prepend(closeButton);\n      } else {\n        closeButton.css(\"margin-top\", \"-10px\").prependTo(body);\n      }\n    }\n\n    if (options.title) {\n      dialog.find(\".modal-title\").html(options.title);\n    }\n\n    if (buttonStr.length) {\n      body.after(templates.footer);\n      dialog.find(\".modal-footer\").html(buttonStr);\n    }\n\n\n    /**\n     * Bootstrap event listeners; used handle extra\n     * setup & teardown required after the underlying\n     * modal has performed certain actions\n     */\n\n    dialog.on(\"hidden.bs.modal\", function(e) {\n      // ensure we don't accidentally intercept hidden events triggered\n      // by children of the current dialog. We shouldn't anymore now BS\n      // namespaces its events; but still worth doing\n      if (e.target === this) {\n        dialog.remove();\n      }\n    });\n\n    /*\n    dialog.on(\"show.bs.modal\", function() {\n      // sadly this doesn't work; show is called *just* before\n      // the backdrop is added so we'd need a setTimeout hack or\n      // otherwise... leaving in as would be nice\n      if (options.backdrop) {\n        dialog.next(\".modal-backdrop\").addClass(\"bootbox-backdrop\");\n      }\n    });\n    */\n\n    dialog.on(\"shown.bs.modal\", function() {\n      dialog.find(\".btn-primary:first\").focus();\n    });\n\n    /**\n     * Bootbox event listeners; experimental and may not last\n     * just an attempt to decouple some behaviours from their\n     * respective triggers\n     */\n\n    if (options.backdrop !== \"static\") {\n      // A boolean true/false according to the Bootstrap docs\n      // should show a dialog the user can dismiss by clicking on\n      // the background.\n      // We always only ever pass static/false to the actual\n      // $.modal function because with `true` we can't trap\n      // this event (the .modal-backdrop swallows it)\n      // However, we still want to sort of respect true\n      // and invoke the escape mechanism instead\n      dialog.on(\"click.dismiss.bs.modal\", function(e) {\n        // @NOTE: the target varies in >= 3.3.x releases since the modal backdrop\n        // moved *inside* the outer dialog rather than *alongside* it\n        if (dialog.children(\".modal-backdrop\").length) {\n          e.currentTarget = dialog.children(\".modal-backdrop\").get(0);\n        }\n\n        if (e.target !== e.currentTarget) {\n          return;\n        }\n\n        dialog.trigger(\"escape.close.bb\");\n      });\n    }\n\n    dialog.on(\"escape.close.bb\", function(e) {\n      if (callbacks.onEscape) {\n        processCallback(e, dialog, callbacks.onEscape);\n      }\n    });\n\n    /**\n     * Standard jQuery event listeners; used to handle user\n     * interaction with our dialog\n     */\n\n    dialog.on(\"click\", \".modal-footer button\", function(e) {\n      var callbackKey = $(this).data(\"bb-handler\");\n\n      processCallback(e, dialog, callbacks[callbackKey]);\n    });\n\n    dialog.on(\"click\", \".bootbox-close-button\", function(e) {\n      // onEscape might be falsy but that's fine; the fact is\n      // if the user has managed to click the close button we\n      // have to close the dialog, callback or not\n      processCallback(e, dialog, callbacks.onEscape);\n    });\n\n    dialog.on(\"keyup\", function(e) {\n      if (e.which === 27) {\n        dialog.trigger(\"escape.close.bb\");\n      }\n    });\n\n    // the remainder of this method simply deals with adding our\n    // dialogent to the DOM, augmenting it with Bootstrap's modal\n    // functionality and then giving the resulting object back\n    // to our caller\n\n    $(options.container).append(dialog);\n\n    dialog.modal({\n      backdrop: options.backdrop ? \"static\": false,\n      keyboard: false,\n      show: false\n    });\n\n    if (options.show) {\n      dialog.modal(\"show\");\n    }\n\n    // @TODO should we return the raw element here or should\n    // we wrap it in an object on which we can expose some neater\n    // methods, e.g. var d = bootbox.alert(); d.hide(); instead\n    // of d.modal(\"hide\");\n\n   /*\n    function BBDialog(elem) {\n      this.elem = elem;\n    }\n\n    BBDialog.prototype = {\n      hide: function() {\n        return this.elem.modal(\"hide\");\n      },\n      show: function() {\n        return this.elem.modal(\"show\");\n      }\n    };\n    */\n\n    return dialog;\n\n  };\n\n  exports.setDefaults = function() {\n    var values = {};\n\n    if (arguments.length === 2) {\n      // allow passing of single key/value...\n      values[arguments[0]] = arguments[1];\n    } else {\n      // ... and as an object too\n      values = arguments[0];\n    }\n\n    $.extend(defaults, values);\n  };\n\n  exports.hideAll = function() {\n    $(\".bootbox\").modal(\"hide\");\n\n    return exports;\n  };\n\n\n  /**\n   * standard locales. Please add more according to ISO 639-1 standard. Multiple language variants are\n   * unlikely to be required. If this gets too large it can be split out into separate JS files.\n   */\n  var locales = {\n    bg_BG : {\n      OK      : \"Ок\",\n      CANCEL  : \"Отказ\",\n      CONFIRM : \"Потвърждавам\"\n    },\n    br : {\n      OK      : \"OK\",\n      CANCEL  : \"Cancelar\",\n      CONFIRM : \"Sim\"\n    },\n    cs : {\n      OK      : \"OK\",\n      CANCEL  : \"Zrušit\",\n      CONFIRM : \"Potvrdit\"\n    },\n    da : {\n      OK      : \"OK\",\n      CANCEL  : \"Annuller\",\n      CONFIRM : \"Accepter\"\n    },\n    de : {\n      OK      : \"OK\",\n      CANCEL  : \"Abbrechen\",\n      CONFIRM : \"Akzeptieren\"\n    },\n    el : {\n      OK      : \"Εντάξει\",\n      CANCEL  : \"Ακύρωση\",\n      CONFIRM : \"Επιβεβαίωση\"\n    },\n    en : {\n      OK      : \"OK\",\n      CANCEL  : \"Cancel\",\n      CONFIRM : \"OK\"\n    },\n    es : {\n      OK      : \"OK\",\n      CANCEL  : \"Cancelar\",\n      CONFIRM : \"Aceptar\"\n    },\n    et : {\n      OK      : \"OK\",\n      CANCEL  : \"Katkesta\",\n      CONFIRM : \"OK\"\n    },\n    fa : {\n      OK      : \"قبول\",\n      CANCEL  : \"لغو\",\n      CONFIRM : \"تایید\"\n    },\n    fi : {\n      OK      : \"OK\",\n      CANCEL  : \"Peruuta\",\n      CONFIRM : \"OK\"\n    },\n    fr : {\n      OK      : \"OK\",\n      CANCEL  : \"Annuler\",\n      CONFIRM : \"D'accord\"\n    },\n    he : {\n      OK      : \"אישור\",\n      CANCEL  : \"ביטול\",\n      CONFIRM : \"אישור\"\n    },\n    hu : {\n      OK      : \"OK\",\n      CANCEL  : \"Mégsem\",\n      CONFIRM : \"Megerősít\"\n    },\n    hr : {\n      OK      : \"OK\",\n      CANCEL  : \"Odustani\",\n      CONFIRM : \"Potvrdi\"\n    },\n    id : {\n      OK      : \"OK\",\n      CANCEL  : \"Batal\",\n      CONFIRM : \"OK\"\n    },\n    it : {\n      OK      : \"OK\",\n      CANCEL  : \"Annulla\",\n      CONFIRM : \"Conferma\"\n    },\n    ja : {\n      OK      : \"OK\",\n      CANCEL  : \"キャンセル\",\n      CONFIRM : \"確認\"\n    },\n    lt : {\n      OK      : \"Gerai\",\n      CANCEL  : \"Atšaukti\",\n      CONFIRM : \"Patvirtinti\"\n    },\n    lv : {\n      OK      : \"Labi\",\n      CANCEL  : \"Atcelt\",\n      CONFIRM : \"Apstiprināt\"\n    },\n    nl : {\n      OK      : \"OK\",\n      CANCEL  : \"Annuleren\",\n      CONFIRM : \"Accepteren\"\n    },\n    no : {\n      OK      : \"OK\",\n      CANCEL  : \"Avbryt\",\n      CONFIRM : \"OK\"\n    },\n    pl : {\n      OK      : \"OK\",\n      CANCEL  : \"Anuluj\",\n      CONFIRM : \"Potwierdź\"\n    },\n    pt : {\n      OK      : \"OK\",\n      CANCEL  : \"Cancelar\",\n      CONFIRM : \"Confirmar\"\n    },\n    ru : {\n      OK      : \"OK\",\n      CANCEL  : \"Отмена\",\n      CONFIRM : \"Применить\"\n    },\n    sq : {\n      OK : \"OK\",\n      CANCEL : \"Anulo\",\n      CONFIRM : \"Prano\"\n    },\n    sv : {\n      OK      : \"OK\",\n      CANCEL  : \"Avbryt\",\n      CONFIRM : \"OK\"\n    },\n    th : {\n      OK      : \"ตกลง\",\n      CANCEL  : \"ยกเลิก\",\n      CONFIRM : \"ยืนยัน\"\n    },\n    tr : {\n      OK      : \"Tamam\",\n      CANCEL  : \"İptal\",\n      CONFIRM : \"Onayla\"\n    },\n    zh_CN : {\n      OK      : \"OK\",\n      CANCEL  : \"取消\",\n      CONFIRM : \"确认\"\n    },\n    zh_TW : {\n      OK      : \"OK\",\n      CANCEL  : \"取消\",\n      CONFIRM : \"確認\"\n    }\n  };\n\n  exports.addLocale = function(name, values) {\n    $.each([\"OK\", \"CANCEL\", \"CONFIRM\"], function(_, v) {\n      if (!values[v]) {\n        throw new Error(\"Please supply a translation for '\" + v + \"'\");\n      }\n    });\n\n    locales[name] = {\n      OK: values.OK,\n      CANCEL: values.CANCEL,\n      CONFIRM: values.CONFIRM\n    };\n\n    return exports;\n  };\n\n  exports.removeLocale = function(name) {\n    delete locales[name];\n\n    return exports;\n  };\n\n  exports.setLocale = function(name) {\n    return exports.setDefaults(\"locale\", name);\n  };\n\n  exports.init = function(_$) {\n    return init(_$ || $);\n  };\n\n  return exports;\n}));\n"
  },
  {
    "path": "server/static/bubble.css",
    "content": "/* ------------------------------------------\n   PURE CSS SPEECH BUBBLES\n   by Nicolas Gallagher\n   - http://nicolasgallagher.com/pure-css-speech-bubbles/\n\nhttp://nicolasgallagher.com\nhttp://twitter.com/necolas\n\nCreated: 02 March 2010\nVersion: 1.2 (03 March 2011)\n\nDual licensed under MIT and GNU GPLv2 � Nicolas Gallagher \n------------------------------------------ */\n\n/* NOTE: Some declarations use longhand notation so that it can be clearly\n   explained what specific properties or values do and what their relationship\n   is to other properties or values in creating the effect */\n\n.right { float:right; width:100%; }\n.left { float:left; width:100%; /*ie6 hack*/_background:none; _border:none;}\n\n/* ============================================================================================================================\n   == BUBBLE ORANGE\n   ** ============================================================================================================================ */\n\n/* THE SPEECH BUBBLE\n   ------------------------------------------------------------------------------------------------------------------------------- */\n\n.bubble-orange {\n  width:auto;\n  max-width:40%;\n  position:relative;\n  padding:15px 15px 20px;\n  margin:0.5em 0 0.5em;\n  background: #f3961c;\n  word-break: break-all;\n  color:#fff;\n  /* css3 */\n  -webkit-border-radius:10px;\n  -moz-border-radius:10px;\n  border-radius:10px;\n}\n\n/* Variant : for left positioned triangle\n   ------------------------------------------ */\n\n.left .bubble-orange {\n  margin-left:100px;\n  float:left;\n}\n\n/* Variant : for right positioned triangle\n   ------------------------------------------ */\n\n.right .bubble-orange {\n  margin-right:100px;\n  float:right;\n}\n\n.bubble-orange:hover{\n  background:#f9d835;\n  color:#000;\n}\n\n\n/* THE TRIANGLE\n   ------------------------------------------------------------------------------------------------------------------------------- */\n\n.bubble-orange:after {\n  content:\"\";\n  position:absolute;\n  bottom:-20px; /* value = - border-top-width - border-bottom-width */\n  left:50px; /* controls horizontal position */\n  border-width:15px 15px 0; /* vary these values to change the angle of the vertex */\n  border-style:solid;\n  border-color:#f3961c transparent;\n  /* reduce the damage in FF3.0 */\n  display:block; \n  width:0;\n}\n\n/* Variant : left\n   ------------------------------------------ */\n\n/* creates the smaller  triangle */\n.left .bubble-orange:after {\n  top:16px; /* value = (:before top) + (:before border-top) - (:after border-top) */\n  bottom:auto;\n  left:-21px; /* value = - border-left-width - border-right-width */\n  border-width:9px 21px 9px 0;\n  border-color:transparent #f3961c;\n}\n\n/* Variant : right\n   ------------------------------------------ */\n\n/* creates the smaller  triangle */\n.right .bubble-orange:after {\n  top:16px; /* value = (:before top) + (:before border-top) - (:after border-top) */\n  bottom:auto;\n  left:auto;\n  right:-21px; /* value = - border-left-width - border-right-width */\n  border-width:9px 0 9px 21px;\n  border-color:transparent #f3961c;\n}\n\n\n/* ============================================================================================================================\n   == BUBBLE WHITE\n   ** ============================================================================================================================ */\n\n/* THE SPEECH BUBBLE\n   ------------------------------------------------------------------------------------------------------------------------------- */\n\n.bubble-white {\n  width:auto;\n  max-width:95%;\n  white-space: normal;\n  overflow-x: auto;\n  /*word-break: break-all;*/\n  position:relative;\n  padding:15px 15px 5px;\n  margin:0.5em 0 0.5em;\n  background: #fcfcfc;\n  color:#000;\n  /* css3 */\n  -webkit-border-radius:10px;\n  -moz-border-radius:10px;\n  border-radius:10px;\n}\n\n/* Variant : for left positioned triangle\n   ------------------------------------------ */\n\n.left .bubble-white {\n  float:left;\n}\n\n/* Variant : for right positioned triangle\n   ------------------------------------------ */\n\n.right .bubble-white {\n  float:right;\n}\n\n\n/* THE TRIANGLE\n   ------------------------------------------------------------------------------------------------------------------------------- */\n\n.bubble-white:after {\n  content:\"\";\n  position:absolute;\n  bottom:-20px; /* value = - border-top-width - border-bottom-width */\n  left:50px; /* controls horizontal position */\n  border-width:15px 15px 0; /* vary these values to change the angle of the vertex */\n  border-style:solid;\n  border-color:#ccc transparent;\n  /* reduce the damage in FF3.0 */\n  display:block; \n  width:0;\n}\n\n/* Variant : left\n   ------------------------------------------ */\n\n/* creates the smaller  triangle */\n.left .bubble-white:after {\n  top:16px; /* value = (:before top) + (:before border-top) - (:after border-top) */\n  bottom:auto;\n  left:-21px; /* value = - border-left-width - border-right-width */\n  border-width:9px 21px 9px 0;\n  border-color:transparent #fcfcfc;\n}\n\n/* Variant : right\n   ------------------------------------------ */\n\n/* creates the smaller  triangle */\n.right .bubble-white:after {\n  top:16px; /* value = (:before top) + (:before border-top) - (:after border-top) */\n  bottom:auto;\n  left:auto;\n  right:-21px; /* value = - border-left-width - border-right-width */\n  border-width:9px 0 9px 21px;\n  border-color:transparent #fcfcfc;\n}\n\n\n\n\n/* ============================================================================================================================\n   == BUBBLE BLUE\n   ** ============================================================================================================================ */\n\n/* THE SPEECH BUBBLE\n   ------------------------------------------------------------------------------------------------------------------------------- */\n\n.bubble-blue {\n  width:auto;\n  max-width:50%;\n  word-break: break-all;\n  position:relative;\n  padding:15px;\n  margin:0.5em 0 0.5em;\n  color:#fff;\n  background:#075698; /* default background for browsers without gradient support */\n  /* css3 */\n  -webkit-border-radius:10px;\n  -moz-border-radius:10px;\n  border-radius:10px;\n}\n\n/* Variant : for left positioned triangle\n   ------------------------------------------ */\n\n.left .bubble-blue {\n  margin-left:100px;\n  float:left;\n}\n\n/* Variant : for right positioned triangle\n   ------------------------------------------ */\n\n.right .bubble-blue {\n  float:right;\n}\n\n.bubble-blue:hover{\n  background:#2e88c4;\n  color:#000;\n}\n\n\n/* THE TRIANGLE\n   ------------------------------------------------------------------------------------------------------------------------------- */\n\n.bubble-blue:after {\n  content:\"\";\n  position:absolute;\n  bottom:-20px; /* value = - border-top-width - border-bottom-width */\n  left:50px; /* controls horizontal position */\n  border-width:20px 0 0 20px; /* vary these values to change the angle of the vertex */\n  border-style:solid;\n  border-color:#075698 transparent; \n  /* reduce the damage in FF3.0 */\n  display:block; \n  width:0;\n}\n\n/* Variant : left\n   ------------------------------------------ */\n\n.left .bubble-blue:after {\n  top:16px; \n  left:-40px; /* value = - border-left-width - border-right-width */\n  bottom:auto;\n  border-width:15px 40px 0 0; /* vary these values to change the angle of the vertex */\n  border-color:transparent #075698; \n}\n\n/* Variant : right\n   ------------------------------------------ */\n\n.right .bubble-blue:after {\n  top:16px; \n  right:-40px; /* value = - border-left-width - border-right-width */\n  bottom:auto;\n  left:auto;\n  border-width:15px 0 0 40px; /* vary these values to change the angle of the vertex */\n  border-color:transparent #075698 ; \n}\n\n\n/* ============================================================================================================================\n   == BUBBLE RED\n   ** ============================================================================================================================ */\n\n/* THE SPEECH BUBBLE\n   ------------------------------------------------------------------------------------------------------------------------------- */\n\n.bubble-red {\n  width:auto;\n  max-width:30%;\n  word-break: break-all;\n  position:relative;\n  padding:15px;\n  margin:0.5em 0 0.5em;\n  color:#fff;\n  background:#c81e2b; /* default background for browsers without gradient support */\n  /* css3 */\n  -webkit-border-radius:10px;\n  -moz-border-radius:10px;\n  border-radius:10px;\n}\n\n/* Variant : for left positioned triangle\n   ------------------------------------------ */\n\n.left .bubble-red {\n  margin-left:100px;\n  float:left;\n}\n\n/* Variant : for right positioned triangle\n   ------------------------------------------ */\n\n.right .bubble-red {\n  margin-right:100px;\n  float:right;\n}\n\n.bubble-red:hover{\n  background:#f04349;\n  color:#000;\n}\n\n\n/* THE TRIANGLE\n   ------------------------------------------------------------------------------------------------------------------------------- */\n\n.bubble-red:after {\n  content:\"\";\n  position:absolute;\n  bottom:-20px; /* value = - border-top-width - border-bottom-width */\n  left:50px; /* controls horizontal position */\n  border-width:20px 0 0 20px; /* vary these values to change the angle of the vertex */\n  border-style:solid;\n  border-color:#c81e2b transparent; \n  /* reduce the damage in FF3.0 */\n  display:block; \n  width:0;\n}\n\n/* Variant : left\n   ------------------------------------------ */\n\n.left .bubble-red:after {\n  top:16px; \n  left:-40px; /* value = - border-left-width - border-right-width */\n  bottom:auto;\n  border-width:15px 40px 0 0; /* vary these values to change the angle of the vertex */\n  border-color:transparent #c81e2b; \n}\n\n/* Variant : right\n   ------------------------------------------ */\n\n.right .bubble-red:after {\n  top:16px; \n  right:-40px; /* value = - border-left-width - border-right-width */\n  bottom:auto;\n  left:auto;\n  border-width:15px 0 0 40px; /* vary these values to change the angle of the vertex */\n  border-color:transparent #c81e2b ; \n}\n\n\n/* ============================================================================================================================\n   == BUBBLE GREEN\n   ** ============================================================================================================================ */\n\n/* THE SPEECH BUBBLE\n   ------------------------------------------------------------------------------------------------------------------------------- */\n\n.bubble-green {\n  width:auto;\n  max-width:40%;\n  word-break: break-all;\n  position:relative;\n  padding:15px 15px 5px;\n  margin:0.5em 0 0.5em;\n  background: #7CCD7C;\n  color:#000;\n  /* css3 */\n  -webkit-border-radius:10px;\n  -moz-border-radius:10px;\n  border-radius:10px;\n}\n\n.bubble-text {\n   text-align: left;\n   margin-bottom: 10px\n}\n\n/* Variant : for left positioned triangle\n   ------------------------------------------ */\n\n.left .bubble-green {\n  float:left;\n}\n\n/* Variant : for right positioned triangle\n   ------------------------------------------ */\n\n.right .bubble-green {\n  margin-right:20px;\n  float:right;\n}\n\n\n/* THE TRIANGLE\n   ------------------------------------------------------------------------------------------------------------------------------- */\n\n.bubble-green:after {\n  content:\"\";\n  position:absolute;\n  bottom:-20px; /* value = - border-top-width - border-bottom-width */\n  left:50px; /* controls horizontal position */\n  border-width:15px 15px 0; /* vary these values to change the angle of the vertex */\n  border-style:solid;\n  border-color:#7CCD7C transparent;\n  /* reduce the damage in FF3.0 */\n  display:block; \n  width:0;\n}\n\n/* Variant : left\n   ------------------------------------------ */\n\n/* creates the smaller  triangle */\n.left .bubble-green:after {\n  top:16px; /* value = (:before top) + (:before border-top) - (:after border-top) */\n  bottom:auto;\n  left:-21px; /* value = - border-left-width - border-right-width */\n  border-width:9px 21px 9px 0;\n  border-color:transparent #7CCD7C;\n}\n\n/* Variant : right\n   ------------------------------------------ */\n\n/* creates the smaller  triangle */\n.right .bubble-green:after {\n  top:16px; /* value = (:before top) + (:before border-top) - (:after border-top) */\n  bottom:auto;\n  left:auto;\n  right:-21px; /* value = - border-left-width - border-right-width */\n  border-width:9px 0 9px 21px;\n  border-color:transparent #7CCD7C;\n}\n\n.right .bubble-avatar{\n  width:80px;\n  height:38px;\n  text-align:center;\n  position:absolute;\n  right: -110px;\n  color: #000;\n}\n\n.left .bubble-avatar{\n  width:80px;\n  height:38px;\n  text-align:center;\n  position:absolute;\n  left: -110px;\n  color: #000;\n}\n"
  },
  {
    "path": "server/static/config.js",
    "content": "function saveConfig(msg) {\n    if (window.location.href.indexOf('bot.hahack.com') >= 0) {\n        bootbox.alert(\"demo 站点禁止修改配置!\");\n        return;\n    }\n    $.ajax({\n        url: '/config',\n        type: \"POST\",\n        data: {\"config\": encodeURIComponent($('#config-input').val()), 'validate': getCookie('validation')},\n        success: function(res) {\n            var data = JSON.parse(res);\n            if (!msg) msg='';\n            if (data.code == 0) {\n                toastr.success('设置成功'+msg);\n            } else {\n                toastr.error(data.message, '设置失败');\n            }\n        },\n        error: function() {\n            toastr.error('服务器异常', '设置失败');\n        }\n    });\n}\n\n$(function() {\n    $.ajax({\n        url: '/config',\n        type: \"GET\",\n        data: {'validate': getCookie('validation')},\n        success: function(res) {\n            var data = JSON.parse(res);            \n            if (data.code == 0) {\n                let config = data.config;\n                let sensitivity = data.sensitivity;\n                if (config == '') {\n                    $('#config-placeholder').append(`\n    <center>\n    <p> 找不到配置文件 <code>~/.wukong/config.yml</code> ，请先创建一份！</p>\n    </center>\n`);\n                } else {\n                    $('#config-placeholder').append(`\n    <form class=\"form config-form\" action=\"#\">\n    <div class=\"input-group\" id=\"container\">\n      <div class=\"input-group-prepend\">\n        <span class=\"input-group-text\">config.yml</span>\n      </div>\n        <textarea rows=\"20\" class=\"form-control\" id=\"config-input\" placer='1' aria-label=\"With textarea\">${config}</textarea>\n    </div>\n    <hr>\n    <center>\n    <button type=\"button\" class=\"btn btn-primary mb-2\" id=\"SAVE\"><i class=\"fas fa-save\"></i> 保存</button>&nbsp;\n    <button type=\"button\" class=\"btn btn-danger mb-2\" data-toggle=\"modal\" data-target=\"#restartModal\"><i class=\"fas fa-power-off\"></i> 重启</button>\n    </center>\n  </form>\n`);\n                }\n                $('#sensitivitiy-value').text(sensitivity);\n                $('input#sensitivitiy').val(parseFloat(sensitivity));\n                $('input#sensitivity').on('input propertychange', function(e) {\n                    e.preventDefault();\n                    var value = $(this).val();\n                    $('#sensitivitiy-value').text(value);\n                });\n                $('input#sensitivity').on('change', function(e) {\n                    e.preventDefault();\n                    var value = $(this).val();\n                    var config = $('#config-input').val();\n                    config.indexOf('')\n                    var subStr=new RegExp('sensitivity: [0-9]+\\.?[0-9]?')\n                    result = config.replace(subStr, \"sensitivity: \" + value + \" \");\n                    $('#config-input').text(result);\n                    saveConfig('，请重启生效');\n                });\n                $('button#RESTART').on('click', function(e) {\n                    restart();\n                });\n                $('button#SAVE').on('click', function(e) {\n                    saveConfig();\n                });\n            } else {\n                toastr.error(data.message, '指令发送失败');\n            }\n        },\n        error: function() {\n            toastr.error('服务器异常', '指令发送失败');\n        }\n    });   \n    \n});\n\n"
  },
  {
    "path": "server/static/index.js",
    "content": "var md = window.markdownit({\n    html: true,\n    linkify: true,\n    typographer: true,\n    highlight: function (str, lang) {\n      if (lang && hljs.getLanguage(lang)) {\n        try {\n          return '<pre class=\"hljs\"><code>' +\n                 hljs.highlight(str, { language: lang, ignoreIllegals: true }).value +\n                 '</code></pre>';\n        } catch (__) {}\n      }\n  \n      return '<pre class=\"hljs\"><code>' + md.utils.escapeHtml(str) + '</code></pre>';  \n    }\n  });\n\nfunction appendHistory(type, message, uuid, plugin) {\n    if (!uuid) return;\n    if (type == 0) {\n        // 用户消息\n        $('.history').append(`\n              <div class=\"right\">\n                 <div class=\"bubble bubble-green\">\n                   <div class=\"bubble-text\" id=\"${uuid}\">${message}</div>\n                 </div>\n              </div>\n`);\n    } else {\n        messages = message.split('\\n');\n        $('.history').append(`\n          <div class=\"left\">\n             <div class=\"bubble bubble-white\">\n               <div class=\"bubble-text\" id=\"${uuid}\"></div>\n             </div>\n           </div>\n        `);\n        $(`#${uuid}`).append(md.render(`${message}`));\n        if (plugin) {\n            $(`#${uuid}`).after(`\n               <span class=\"badge badge-info plugin\">${plugin}</span>\n            `);\n        }\n    }\n    $(\"#\"+uuid).hide();\n    $(\"#\"+uuid).fadeIn(500, ()=>{\n        var scrollHeight = $('.history').prop(\"scrollHeight\");\n        $('.history').scrollTop(scrollHeight, 200);\n    });\n}\n\nfunction showProgress() {\n    progressJs().increase();\n}\n\nfunction upgrade() {\n    var args = {'validate': getCookie('validation')}\n    $.ajax({\n        url: '/upgrade',\n        type: \"POST\",\n        data: $.param(args),        \n        success: function(res) {\n            $('.UPDATE-SPIN')[0].hidden = true;\n            $('.UPDATE')[0].disabled = false;\n            res = JSON.parse(res);\n            if (res.code == 0) {\n                toastr.success('更新成功，5秒后将自动重启')\n                \n                $('#updateModal').modal('hide')\n                progressJs().start();\n                setInterval(\"showProgress()\", 1000);\n                setTimeout(()=>{\n                    progressJs().end();\n                    clearInterval();\n                    location.reload();\n                }, 5000);\n            } else {\n                toastr.error(res.message, '更新失败');\n                $('#updateModal').modal('hide')\n            }            \n        },\n        error: function() {\n            \n            toastr.error('服务器异常', '更新失败');\n            $('#updateModal').modal('hide')\n        }\n    });\n}\n\n//用于生成uuid\nfunction S4() {\n    return (((1+Math.random())*0x10000)|0).toString(16).substring(1);\n}\nfunction guid() {\n    return (S4()+S4()+\"-\"+S4()+\"-\"+S4()+\"-\"+S4()+\"-\"+S4()+S4()+S4());\n}\n\n// 创建WebSocket连接\nvar socket = new WebSocket(\"ws://\" + location.host + \"/websocket\");\n\n// 监听WebSocket打开事件\nsocket.onopen = function (e) {\n    console.log(\"WebSocket连接已打开\");\n};\n\n// 监听WebSocket关闭事件\nsocket.onclose = function (e) {\n    console.log(\"WebSocket连接已关闭\");\n};\n\nvar rawData = {}\n\nvar showMessage = function(data) {\n    var existing = $(\"#\" + data.uuid);\n    if (existing.length > 0) {\n        // 如果存在，追加内容，并重新用 markdown 渲染\n        if (rawData[data.uuid] == undefined) {\n            rawData[data.uuid] = data['text'];\n        } else {\n            rawData[data.uuid] += data['text'];\n        }\n        $(`#${data.uuid}`)[0].innerHTML = md.render(rawData[data.uuid]);\n    } else {\n        rawData[data.uuid] = data['text'];\n        appendHistory(data['type'], data['text'], data['uuid'], data['plugin']);\n    }\n}\n\n// 监听WebSocket消息事件\nsocket.onmessage = function (e) {\n    var data = JSON.parse(e.data);\n    if (data.action === \"new_message\") {\n        // console.log(\"收到新消息: \", data);\n        showMessage(data)\n        let scrollHeight = $('.history').prop(\"scrollHeight\");\n        $('.history').scrollTop(scrollHeight, 200);\n    }\n};\n\n$(document).ready(function() {\n    if (!window.console) window.console = {};\n    if (!window.console.log) window.console.log = function() {};\n    $('.CHAT').on('click', function(e) {\n        e.preventDefault();\n        var disabled = $('#query');\n        disabled.disable();\n        var uuid = 'chat' + guid();\n        var query = $(\"input#query\")[0].value;\n        if (query.trim() == '') {\n            toastr.error('请输入有效的命令');\n            return;\n        }\n        appendHistory(0, query, uuid);\n        $('input#query').val('');\n        var args = {\"type\": \"text\", \"query\": query, 'validate': getCookie('validation'), \"uuid\": uuid}\n        $.ajax({\n            url: '/chat',\n            type: \"POST\",\n            data: $.param(args),\n            success: function(res) {\n                disabled.enable();\n                if (!res) return;\n                var data = JSON.parse(res);\n                if (data.code == 0) {\n                    toastr.success('指令发送成功');\n                } else {\n                    toastr.error(data.message, '指令发送失败');\n                }\n            },\n            error: function() {\n                disabled.enable();\n                toastr.error('服务器异常', '指令发送失败');\n            }\n        });\n    });\n\n\n    $('.UPDATE').on('click', function(e) {\n    $('.UPDATE-SPIN')[0].hidden = false;\n       $(this)[0].disabled = true;\n       upgrade();\n    });\n\n    updater.poll();\n});\n\n\njQuery.fn.disable = function() {\n    this.enable(false);\n    return this;\n};\n\njQuery.fn.enable = function(opt_enable) {\n    if (arguments.length && !opt_enable) {\n        this.attr(\"disabled\", \"disabled\");\n    } else {\n        this.removeAttr(\"disabled\");\n    }\n    return this;\n};\n\nvar updater = {\n    errorSleepTime: 500,\n    cursor: null,\n\n    poll: function() {\n        console.log('updater poll');\n        var args = {'validate': getCookie('validation')}        \n        if (updater.cursor) args.cursor = updater.cursor;\n        $.ajax({\n            url: '/chat/updates',\n            type: \"POST\",\n            data: $.param(args),\n            success: updater.onSuccess,\n            error: updater.onError\n        });        \n    },\n\n    onSuccess: function(response) {\n        console.log(\"updater poll success\")\n        try {\n            var res = JSON.parse(response);            \n            updater.newMessages(res);\n        } catch (e) {\n            updater.onError();\n            return;\n        }\n        updater.errorSleepTime = 500;\n        window.setTimeout(updater.poll, 0);\n    },\n\n    onError: function(response) {\n        updater.errorSleepTime *= 2;\n        console.error(\"get history failed! sleeping for\", updater.errorSleepTime, \"ms\");\n        window.setTimeout(updater.poll, updater.errorSleepTime);\n    },\n\n    newMessages: function(response) {\n        if (response.code != 0 || !response.history) return;\n        var messages = JSON.parse(response.history);\n        updater.cursor = messages[messages.length - 1].uuid;\n        console.log(messages.length, \"new messages, cursor:\", updater.cursor);\n        for (var i = 0; i < messages.length; i++) {\n            updater.showMessage(messages[i]);\n        }\n    },\n\n    showMessage: function(message) {\n        var existing = $(\"#\" + message.uuid);\n        if (existing.length > 0) return;\n        appendHistory(message['type'], message['text'], message['uuid'], message['plugin']);\n    }\n};\n"
  },
  {
    "path": "server/static/jquery.fancybox.css",
    "content": "body.compensate-for-scrollbar {\n  overflow: hidden; }\n\n.fancybox-active {\n  height: auto; }\n\n.fancybox-is-hidden {\n  left: -9999px;\n  margin: 0;\n  position: absolute !important;\n  top: -9999px;\n  visibility: hidden; }\n\n.fancybox-container {\n  -webkit-backface-visibility: hidden;\n  backface-visibility: hidden;\n  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif, 'Apple Color Emoji',\r 'Segoe UI Emoji', 'Segoe UI Symbol';\n  height: 100%;\n  left: 0;\n  position: fixed;\n  -webkit-tap-highlight-color: transparent;\n  top: 0;\n  -webkit-transform: translateZ(0);\n  transform: translateZ(0);\n  width: 100%;\n  z-index: 99992; }\n\n.fancybox-container * {\n  box-sizing: border-box; }\n\n.fancybox-outer,\n.fancybox-inner,\n.fancybox-bg,\n.fancybox-stage {\n  bottom: 0;\n  left: 0;\n  position: absolute;\n  right: 0;\n  top: 0; }\n\n.fancybox-outer {\n  -webkit-overflow-scrolling: touch;\n  overflow-y: auto; }\n\n.fancybox-bg {\n  background: #1e1e1e;\n  opacity: 0;\n  transition-duration: inherit;\n  transition-property: opacity;\n  transition-timing-function: cubic-bezier(0.47, 0, 0.74, 0.71); }\n\n.fancybox-is-open .fancybox-bg {\n  opacity: .87;\n  transition-timing-function: cubic-bezier(0.22, 0.61, 0.36, 1); }\n\n.fancybox-infobar,\n.fancybox-toolbar,\n.fancybox-caption,\n.fancybox-navigation .fancybox-button {\n  direction: ltr;\n  opacity: 0;\n  position: absolute;\n  transition: opacity .25s, visibility 0s linear .25s;\n  visibility: hidden;\n  z-index: 99997; }\n\n.fancybox-show-infobar .fancybox-infobar,\n.fancybox-show-toolbar .fancybox-toolbar,\n.fancybox-show-caption .fancybox-caption,\n.fancybox-show-nav .fancybox-navigation .fancybox-button {\n  opacity: 1;\n  transition: opacity .25s, visibility 0s;\n  visibility: visible; }\n\n.fancybox-infobar {\n  color: #ccc;\n  font-size: 13px;\n  -webkit-font-smoothing: subpixel-antialiased;\n  height: 44px;\n  left: 0;\n  line-height: 44px;\n  min-width: 44px;\n  mix-blend-mode: difference;\n  padding: 0 10px;\n  pointer-events: none;\n  text-align: center;\n  top: 0;\n  -webkit-touch-callout: none;\n  -webkit-user-select: none;\n  -moz-user-select: none;\n  -ms-user-select: none;\n  user-select: none; }\n\n.fancybox-toolbar {\n  right: 0;\n  top: 0; }\n\n.fancybox-stage {\n  direction: ltr;\n  overflow: visible;\n  -webkit-transform: translate3d(0, 0, 0);\n  z-index: 99994; }\n\n.fancybox-is-open .fancybox-stage {\n  overflow: hidden; }\n\n.fancybox-slide {\n  -webkit-backface-visibility: hidden;\n  backface-visibility: hidden;\n  display: none;\n  height: 100%;\n  left: 0;\n  outline: none;\n  overflow: auto;\n  -webkit-overflow-scrolling: touch;\n  padding: 44px;\n  position: absolute;\n  text-align: center;\n  top: 0;\n  transition-property: opacity, -webkit-transform;\n  transition-property: transform, opacity;\n  transition-property: transform, opacity, -webkit-transform;\n  white-space: normal;\n  width: 100%;\n  z-index: 99994; }\n\n.fancybox-slide::before {\n  content: '';\n  display: inline-block;\n  height: 100%;\n  margin-right: -.25em;\n  vertical-align: middle;\n  width: 0; }\n\n.fancybox-is-sliding .fancybox-slide,\n.fancybox-slide--previous,\n.fancybox-slide--current,\n.fancybox-slide--next {\n  display: block; }\n\n.fancybox-slide--next {\n  z-index: 99995; }\n\n.fancybox-slide--image {\n  overflow: visible;\n  padding: 44px 0; }\n\n.fancybox-slide--image::before {\n  display: none; }\n\n.fancybox-slide--html {\n  padding: 6px 6px 0 6px; }\n\n.fancybox-slide--iframe {\n  padding: 44px 44px 0; }\n\n.fancybox-content {\n  background: #fff;\n  display: inline-block;\n  margin: 0 0 6px 0;\n  max-width: 100%;\n  overflow: auto;\n  padding: 0;\n  padding: 24px;\n  position: relative;\n  text-align: left;\n  vertical-align: middle; }\n\n.fancybox-slide--image .fancybox-content {\n  -webkit-animation-timing-function: cubic-bezier(0.5, 0, 0.14, 1);\n  animation-timing-function: cubic-bezier(0.5, 0, 0.14, 1);\n  -webkit-backface-visibility: hidden;\n  backface-visibility: hidden;\n  background: transparent;\n  background-repeat: no-repeat;\n  background-size: 100% 100%;\n  left: 0;\n  margin: 0;\n  max-width: none;\n  overflow: visible;\n  padding: 0;\n  position: absolute;\n  top: 0;\n  -webkit-transform-origin: top left;\n  -ms-transform-origin: top left;\n  transform-origin: top left;\n  transition-property: opacity, -webkit-transform;\n  transition-property: transform, opacity;\n  transition-property: transform, opacity, -webkit-transform;\n  -webkit-user-select: none;\n  -moz-user-select: none;\n  -ms-user-select: none;\n  user-select: none;\n  z-index: 99995; }\n\n.fancybox-can-zoomOut .fancybox-content {\n  cursor: -webkit-zoom-out;\n  cursor: zoom-out; }\n\n.fancybox-can-zoomIn .fancybox-content {\n  cursor: -webkit-zoom-in;\n  cursor: zoom-in; }\n\n.fancybox-can-drag .fancybox-content {\n  cursor: -webkit-grab;\n  cursor: grab; }\n\n.fancybox-is-dragging .fancybox-content {\n  cursor: -webkit-grabbing;\n  cursor: grabbing; }\n\n.fancybox-container [data-selectable='true'] {\n  cursor: text; }\n\n.fancybox-image,\n.fancybox-spaceball {\n  background: transparent;\n  border: 0;\n  height: 100%;\n  left: 0;\n  margin: 0;\n  max-height: none;\n  max-width: none;\n  padding: 0;\n  position: absolute;\n  top: 0;\n  -webkit-user-select: none;\n  -moz-user-select: none;\n  -ms-user-select: none;\n  user-select: none;\n  width: 100%; }\n\n.fancybox-spaceball {\n  z-index: 1; }\n\n.fancybox-slide--html .fancybox-content {\n  margin-bottom: 6px; }\n\n.fancybox-slide--video .fancybox-content,\n.fancybox-slide--map .fancybox-content,\n.fancybox-slide--iframe .fancybox-content {\n  height: 100%;\n  margin: 0;\n  overflow: visible;\n  padding: 0;\n  width: 100%; }\n\n.fancybox-slide--video .fancybox-content {\n  background: #000; }\n\n.fancybox-slide--map .fancybox-content {\n  background: #e5e3df; }\n\n.fancybox-slide--iframe .fancybox-content {\n  background: #fff;\n  height: calc(100% - 44px);\n  margin-bottom: 44px; }\n\n.fancybox-video,\n.fancybox-iframe {\n  background: transparent;\n  border: 0;\n  height: 100%;\n  margin: 0;\n  overflow: hidden;\n  padding: 0;\n  width: 100%; }\n\n.fancybox-iframe {\n  vertical-align: top; }\n\n.fancybox-error {\n  background: #fff;\n  cursor: default;\n  max-width: 400px;\n  padding: 40px;\n  width: 100%; }\n\n.fancybox-error p {\n  color: #444;\n  font-size: 16px;\n  line-height: 20px;\n  margin: 0;\n  padding: 0; }\n\n/* Buttons */\n.fancybox-button {\n  background: rgba(30, 30, 30, 0.6);\n  border: 0;\n  border-radius: 0;\n  cursor: pointer;\n  display: inline-block;\n  height: 44px;\n  margin: 0;\n  outline: none;\n  padding: 10px;\n  transition: color .2s;\n  vertical-align: top;\n  width: 44px; }\n\n.fancybox-button,\n.fancybox-button:visited,\n.fancybox-button:link {\n  color: #ccc; }\n\n.fancybox-button:focus,\n.fancybox-button:hover {\n  color: #fff; }\n\n.fancybox-button.disabled,\n.fancybox-button.disabled:hover,\n.fancybox-button[disabled],\n.fancybox-button[disabled]:hover {\n  color: #888;\n  cursor: default; }\n\n.fancybox-button svg {\n  display: block;\n  overflow: visible;\n  position: relative;\n  shape-rendering: geometricPrecision; }\n\n.fancybox-button svg path {\n  fill: transparent;\n  stroke: currentColor;\n  stroke-linejoin: round;\n  stroke-width: 3; }\n\n.fancybox-button--play svg path:nth-child(2) {\n  display: none; }\n\n.fancybox-button--pause svg path:nth-child(1) {\n  display: none; }\n\n.fancybox-button--play svg path,\n.fancybox-button--share svg path,\n.fancybox-button--thumbs svg path {\n  fill: currentColor; }\n\n.fancybox-button--share svg path {\n  stroke-width: 1; }\n\n/* Navigation arrows */\n.fancybox-navigation .fancybox-button {\n  height: 38px;\n  opacity: 0;\n  padding: 6px;\n  position: absolute;\n  top: 50%;\n  width: 38px; }\n\n.fancybox-show-nav .fancybox-navigation .fancybox-button {\n  transition: opacity .25s, visibility 0s, color .25s; }\n\n.fancybox-navigation .fancybox-button::after {\n  content: '';\n  left: -25px;\n  padding: 50px;\n  position: absolute;\n  top: -25px; }\n\n.fancybox-navigation .fancybox-button--arrow_left {\n  left: 6px; }\n\n.fancybox-navigation .fancybox-button--arrow_right {\n  right: 6px; }\n\n/* Close button on the top right corner of html content */\n.fancybox-close-small {\n  background: transparent;\n  border: 0;\n  border-radius: 0;\n  color: #555;\n  cursor: pointer;\n  height: 44px;\n  margin: 0;\n  padding: 6px;\n  position: absolute;\n  right: 0;\n  top: 0;\n  width: 44px;\n  z-index: 10; }\n\n.fancybox-close-small svg {\n  fill: transparent;\n  opacity: .8;\n  stroke: currentColor;\n  stroke-width: 1.5;\n  transition: stroke .1s; }\n\n.fancybox-close-small:focus {\n  outline: none; }\n\n.fancybox-close-small:hover svg {\n  opacity: 1; }\n\n.fancybox-slide--image .fancybox-close-small,\n.fancybox-slide--video .fancybox-close-small,\n.fancybox-slide--iframe .fancybox-close-small {\n  color: #ccc;\n  padding: 5px;\n  right: -12px;\n  top: -44px; }\n\n.fancybox-slide--image .fancybox-close-small:hover svg,\n.fancybox-slide--video .fancybox-close-small:hover svg,\n.fancybox-slide--iframe .fancybox-close-small:hover svg {\n  background: transparent;\n  color: #fff; }\n\n.fancybox-is-scaling .fancybox-close-small,\n.fancybox-is-zoomable.fancybox-can-drag .fancybox-close-small {\n  display: none; }\n\n/* Caption */\n.fancybox-caption {\n  bottom: 0;\n  color: #fff;\n  font-size: 14px;\n  font-weight: 400;\n  left: 0;\n  line-height: 1.5;\n  padding: 25px 44px 25px 44px;\n  right: 0; }\n\n.fancybox-caption::before {\n  background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAEtCAQAAABjBcL7AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAHRJREFUKM+Vk8EOgDAIQ0vj/3+xBw8qIZZueFnIKC90MCAI8DlrkHGeqqGIU6lVigrBtpCWqeRWoHDNqs0F7VNVBVxmHRlvoVqjaYkdnDIaivH2HqZ5+oZj3JUzWB+cOz4G48Bg+tsJ/tqu4dLC/4Xb+0GcF5BwBC0AA53qAAAAAElFTkSuQmCC);\n  background-repeat: repeat-x;\n  background-size: contain;\n  bottom: 0;\n  content: '';\n  display: block;\n  left: 0;\n  pointer-events: none;\n  position: absolute;\n  right: 0;\n  top: -25px;\n  z-index: -1; }\n\n.fancybox-caption::after {\n  border-bottom: 1px solid rgba(255, 255, 255, 0.3);\n  content: '';\n  display: block;\n  left: 44px;\n  position: absolute;\n  right: 44px;\n  top: 0; }\n\n.fancybox-caption a,\n.fancybox-caption a:link,\n.fancybox-caption a:visited {\n  color: #ccc;\n  text-decoration: none; }\n\n.fancybox-caption a:hover {\n  color: #fff;\n  text-decoration: underline; }\n\n/* Loading indicator */\n.fancybox-loading {\n  -webkit-animation: fancybox-rotate .8s infinite linear;\n  animation: fancybox-rotate .8s infinite linear;\n  background: transparent;\n  border: 6px solid rgba(100, 100, 100, 0.5);\n  border-radius: 100%;\n  border-top-color: #fff;\n  height: 60px;\n  left: 50%;\n  margin: -30px 0 0 -30px;\n  opacity: .6;\n  padding: 0;\n  position: absolute;\n  top: 50%;\n  width: 60px;\n  z-index: 99999; }\n\n@-webkit-keyframes fancybox-rotate {\n  from {\n    -webkit-transform: rotate(0deg);\n    transform: rotate(0deg); }\n  to {\n    -webkit-transform: rotate(359deg);\n    transform: rotate(359deg); } }\n\n@keyframes fancybox-rotate {\n  from {\n    -webkit-transform: rotate(0deg);\n    transform: rotate(0deg); }\n  to {\n    -webkit-transform: rotate(359deg);\n    transform: rotate(359deg); } }\n\n/* Transition effects */\n.fancybox-animated {\n  transition-timing-function: cubic-bezier(0, 0, 0.25, 1); }\n\n/* transitionEffect: slide */\n.fancybox-fx-slide.fancybox-slide--previous {\n  opacity: 0;\n  -webkit-transform: translate3d(-100%, 0, 0);\n  transform: translate3d(-100%, 0, 0); }\n\n.fancybox-fx-slide.fancybox-slide--next {\n  opacity: 0;\n  -webkit-transform: translate3d(100%, 0, 0);\n  transform: translate3d(100%, 0, 0); }\n\n.fancybox-fx-slide.fancybox-slide--current {\n  opacity: 1;\n  -webkit-transform: translate3d(0, 0, 0);\n  transform: translate3d(0, 0, 0); }\n\n/* transitionEffect: fade */\n.fancybox-fx-fade.fancybox-slide--previous,\n.fancybox-fx-fade.fancybox-slide--next {\n  opacity: 0;\n  transition-timing-function: cubic-bezier(0.19, 1, 0.22, 1); }\n\n.fancybox-fx-fade.fancybox-slide--current {\n  opacity: 1; }\n\n/* transitionEffect: zoom-in-out */\n.fancybox-fx-zoom-in-out.fancybox-slide--previous {\n  opacity: 0;\n  -webkit-transform: scale3d(1.5, 1.5, 1.5);\n  transform: scale3d(1.5, 1.5, 1.5); }\n\n.fancybox-fx-zoom-in-out.fancybox-slide--next {\n  opacity: 0;\n  -webkit-transform: scale3d(0.5, 0.5, 0.5);\n  transform: scale3d(0.5, 0.5, 0.5); }\n\n.fancybox-fx-zoom-in-out.fancybox-slide--current {\n  opacity: 1;\n  -webkit-transform: scale3d(1, 1, 1);\n  transform: scale3d(1, 1, 1); }\n\n/* transitionEffect: rotate */\n.fancybox-fx-rotate.fancybox-slide--previous {\n  opacity: 0;\n  -webkit-transform: rotate(-360deg);\n  -ms-transform: rotate(-360deg);\n  transform: rotate(-360deg); }\n\n.fancybox-fx-rotate.fancybox-slide--next {\n  opacity: 0;\n  -webkit-transform: rotate(360deg);\n  -ms-transform: rotate(360deg);\n  transform: rotate(360deg); }\n\n.fancybox-fx-rotate.fancybox-slide--current {\n  opacity: 1;\n  -webkit-transform: rotate(0deg);\n  -ms-transform: rotate(0deg);\n  transform: rotate(0deg); }\n\n/* transitionEffect: circular */\n.fancybox-fx-circular.fancybox-slide--previous {\n  opacity: 0;\n  -webkit-transform: scale3d(0, 0, 0) translate3d(-100%, 0, 0);\n  transform: scale3d(0, 0, 0) translate3d(-100%, 0, 0); }\n\n.fancybox-fx-circular.fancybox-slide--next {\n  opacity: 0;\n  -webkit-transform: scale3d(0, 0, 0) translate3d(100%, 0, 0);\n  transform: scale3d(0, 0, 0) translate3d(100%, 0, 0); }\n\n.fancybox-fx-circular.fancybox-slide--current {\n  opacity: 1;\n  -webkit-transform: scale3d(1, 1, 1) translate3d(0, 0, 0);\n  transform: scale3d(1, 1, 1) translate3d(0, 0, 0); }\n\n/* transitionEffect: tube */\n.fancybox-fx-tube.fancybox-slide--previous {\n  -webkit-transform: translate3d(-100%, 0, 0) scale(0.1) skew(-10deg);\n  transform: translate3d(-100%, 0, 0) scale(0.1) skew(-10deg); }\n\n.fancybox-fx-tube.fancybox-slide--next {\n  -webkit-transform: translate3d(100%, 0, 0) scale(0.1) skew(10deg);\n  transform: translate3d(100%, 0, 0) scale(0.1) skew(10deg); }\n\n.fancybox-fx-tube.fancybox-slide--current {\n  -webkit-transform: translate3d(0, 0, 0) scale(1);\n  transform: translate3d(0, 0, 0) scale(1); }\n\n/* Share */\n.fancybox-share {\n  background: #f4f4f4;\n  border-radius: 3px;\n  max-width: 90%;\n  padding: 30px;\n  text-align: center; }\n\n.fancybox-share h1 {\n  color: #222;\n  font-size: 35px;\n  font-weight: 700;\n  margin: 0 0 20px 0; }\n\n.fancybox-share p {\n  margin: 0;\n  padding: 0; }\n\n.fancybox-share__button {\n  border: 0;\n  border-radius: 3px;\n  display: inline-block;\n  font-size: 14px;\n  font-weight: 700;\n  line-height: 40px;\n  margin: 0 5px 10px 5px;\n  min-width: 130px;\n  padding: 0 15px;\n  text-decoration: none;\n  transition: all .2s;\n  -webkit-user-select: none;\n  -moz-user-select: none;\n  -ms-user-select: none;\n  user-select: none;\n  white-space: nowrap; }\n\n.fancybox-share__button:visited,\n.fancybox-share__button:link {\n  color: #fff; }\n\n.fancybox-share__button:hover {\n  text-decoration: none; }\n\n.fancybox-share__button--fb {\n  background: #3b5998; }\n\n.fancybox-share__button--fb:hover {\n  background: #344e86; }\n\n.fancybox-share__button--pt {\n  background: #bd081d; }\n\n.fancybox-share__button--pt:hover {\n  background: #aa0719; }\n\n.fancybox-share__button--tw {\n  background: #1da1f2; }\n\n.fancybox-share__button--tw:hover {\n  background: #0d95e8; }\n\n.fancybox-share__button svg {\n  height: 25px;\n  margin-right: 7px;\n  position: relative;\n  top: -1px;\n  vertical-align: middle;\n  width: 25px; }\n\n.fancybox-share__button svg path {\n  fill: #fff; }\n\n.fancybox-share__input {\n  background: transparent;\n  border: 0;\n  border-bottom: 1px solid #d7d7d7;\n  border-radius: 0;\n  color: #5d5b5b;\n  font-size: 14px;\n  margin: 10px 0 0 0;\n  outline: none;\n  padding: 10px 15px;\n  width: 100%; }\n\n/* Thumbs */\n.fancybox-thumbs {\n  background: #fff;\n  bottom: 0;\n  display: none;\n  margin: 0;\n  -webkit-overflow-scrolling: touch;\n  -ms-overflow-style: -ms-autohiding-scrollbar;\n  padding: 2px 2px 4px 2px;\n  position: absolute;\n  right: 0;\n  -webkit-tap-highlight-color: transparent;\n  top: 0;\n  width: 212px;\n  z-index: 99995; }\n\n.fancybox-thumbs-x {\n  overflow-x: auto;\n  overflow-y: hidden; }\n\n.fancybox-show-thumbs .fancybox-thumbs {\n  display: block; }\n\n.fancybox-show-thumbs .fancybox-inner {\n  right: 212px; }\n\n.fancybox-thumbs > ul {\n  font-size: 0;\n  height: 100%;\n  list-style: none;\n  margin: 0;\n  overflow-x: hidden;\n  overflow-y: auto;\n  padding: 0;\n  position: absolute;\n  position: relative;\n  white-space: nowrap;\n  width: 100%; }\n\n.fancybox-thumbs-x > ul {\n  overflow: hidden; }\n\n.fancybox-thumbs-y > ul::-webkit-scrollbar {\n  width: 7px; }\n\n.fancybox-thumbs-y > ul::-webkit-scrollbar-track {\n  background: #fff;\n  border-radius: 10px;\n  box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3); }\n\n.fancybox-thumbs-y > ul::-webkit-scrollbar-thumb {\n  background: #2a2a2a;\n  border-radius: 10px; }\n\n.fancybox-thumbs > ul > li {\n  -webkit-backface-visibility: hidden;\n  backface-visibility: hidden;\n  cursor: pointer;\n  float: left;\n  height: 75px;\n  margin: 2px;\n  max-height: calc(100% - 8px);\n  max-width: calc(50% - 4px);\n  outline: none;\n  overflow: hidden;\n  padding: 0;\n  position: relative;\n  -webkit-tap-highlight-color: transparent;\n  width: 100px; }\n\n.fancybox-thumbs-loading {\n  background: rgba(0, 0, 0, 0.1); }\n\n.fancybox-thumbs > ul > li {\n  background-position: center center;\n  background-repeat: no-repeat;\n  background-size: cover; }\n\n.fancybox-thumbs > ul > li:before {\n  border: 4px solid #4ea7f9;\n  bottom: 0;\n  content: '';\n  left: 0;\n  opacity: 0;\n  position: absolute;\n  right: 0;\n  top: 0;\n  transition: all 0.2s cubic-bezier(0.25, 0.46, 0.45, 0.94);\n  z-index: 99991; }\n\n.fancybox-thumbs .fancybox-thumbs-active:before {\n  opacity: 1; }\n\n/* Styling for Small-Screen Devices */\n@media all and (max-width: 800px) {\n  .fancybox-thumbs {\n    width: 110px; }\n  .fancybox-show-thumbs .fancybox-inner {\n    right: 110px; }\n  .fancybox-thumbs > ul > li {\n    max-width: calc(100% - 10px); } }\n"
  },
  {
    "path": "server/static/jquery.fancybox.js",
    "content": "// ==================================================\n// fancyBox v3.3.5\n//\n// Licensed GPLv3 for open source use\n// or fancyBox Commercial License for commercial use\n//\n// http://fancyapps.com/fancybox/\n// Copyright 2018 fancyApps\n//\n// ==================================================\n(function(window, document, $, undefined) {\n  \"use strict\";\n\n  window.console = window.console || {\n    info: function(stuff) {}\n  };\n\n  // If there's no jQuery, fancyBox can't work\n  // =========================================\n\n  if (!$) {\n    return;\n  }\n\n  // Check if fancyBox is already initialized\n  // ========================================\n\n  if ($.fn.fancybox) {\n    console.info(\"fancyBox already initialized\");\n\n    return;\n  }\n\n  // Private default settings\n  // ========================\n\n  var defaults = {\n    // Enable infinite gallery navigation\n    loop: false,\n\n    // Horizontal space between slides\n    gutter: 50,\n\n    // Enable keyboard navigation\n    keyboard: true,\n\n    // Should display navigation arrows at the screen edges\n    arrows: true,\n\n    // Should display counter at the top left corner\n    infobar: true,\n\n    // Should display close button (using `btnTpl.smallBtn` template) over the content\n    // Can be true, false, \"auto\"\n    // If \"auto\" - will be automatically enabled for \"html\", \"inline\" or \"ajax\" items\n    smallBtn: \"auto\",\n\n    // Should display toolbar (buttons at the top)\n    // Can be true, false, \"auto\"\n    // If \"auto\" - will be automatically hidden if \"smallBtn\" is enabled\n    toolbar: \"auto\",\n\n    // What buttons should appear in the top right corner.\n    // Buttons will be created using templates from `btnTpl` option\n    // and they will be placed into toolbar (class=\"fancybox-toolbar\"` element)\n    buttons: [\n      \"zoom\",\n      //\"share\",\n      //\"slideShow\",\n      //\"fullScreen\",\n      //\"download\",\n      \"thumbs\",\n      \"close\"\n    ],\n\n    // Detect \"idle\" time in seconds\n    idleTime: 3,\n\n    // Disable right-click and use simple image protection for images\n    protect: false,\n\n    // Shortcut to make content \"modal\" - disable keyboard navigtion, hide buttons, etc\n    modal: false,\n\n    image: {\n      // Wait for images to load before displaying\n      //   true  - wait for image to load and then display;\n      //   false - display thumbnail and load the full-sized image over top,\n      //           requires predefined image dimensions (`data-width` and `data-height` attributes)\n      preload: false\n    },\n\n    ajax: {\n      // Object containing settings for ajax request\n      settings: {\n        // This helps to indicate that request comes from the modal\n        // Feel free to change naming\n        data: {\n          fancybox: true\n        }\n      }\n    },\n\n    iframe: {\n      // Iframe template\n      tpl:\n        '<iframe id=\"fancybox-frame{rnd}\" name=\"fancybox-frame{rnd}\" class=\"fancybox-iframe\" frameborder=\"0\" vspace=\"0\" hspace=\"0\" webkitAllowFullScreen mozallowfullscreen allowFullScreen allowtransparency=\"true\" src=\"\"></iframe>',\n\n      // Preload iframe before displaying it\n      // This allows to calculate iframe content width and height\n      // (note: Due to \"Same Origin Policy\", you can't get cross domain data).\n      preload: true,\n\n      // Custom CSS styling for iframe wrapping element\n      // You can use this to set custom iframe dimensions\n      css: {},\n\n      // Iframe tag attributes\n      attr: {\n        scrolling: \"auto\"\n      }\n    },\n\n    // Default content type if cannot be detected automatically\n    defaultType: \"image\",\n\n    // Open/close animation type\n    // Possible values:\n    //   false            - disable\n    //   \"zoom\"           - zoom images from/to thumbnail\n    //   \"fade\"\n    //   \"zoom-in-out\"\n    //\n    animationEffect: \"zoom\",\n\n    // Duration in ms for open/close animation\n    animationDuration: 366,\n\n    // Should image change opacity while zooming\n    // If opacity is \"auto\", then opacity will be changed if image and thumbnail have different aspect ratios\n    zoomOpacity: \"auto\",\n\n    // Transition effect between slides\n    //\n    // Possible values:\n    //   false            - disable\n    //   \"fade'\n    //   \"slide'\n    //   \"circular'\n    //   \"tube'\n    //   \"zoom-in-out'\n    //   \"rotate'\n    //\n    transitionEffect: \"fade\",\n\n    // Duration in ms for transition animation\n    transitionDuration: 366,\n\n    // Custom CSS class for slide element\n    slideClass: \"\",\n\n    // Custom CSS class for layout\n    baseClass: \"\",\n\n    // Base template for layout\n    baseTpl:\n      '<div class=\"fancybox-container\" role=\"dialog\" tabindex=\"-1\">' +\n      '<div class=\"fancybox-bg\"></div>' +\n      '<div class=\"fancybox-inner\">' +\n      '<div class=\"fancybox-infobar\">' +\n      \"<span data-fancybox-index></span>&nbsp;/&nbsp;<span data-fancybox-count></span>\" +\n      \"</div>\" +\n      '<div class=\"fancybox-toolbar\">{{buttons}}</div>' +\n      '<div class=\"fancybox-navigation\">{{arrows}}</div>' +\n      '<div class=\"fancybox-stage\"></div>' +\n      '<div class=\"fancybox-caption\"></div>' +\n      \"</div>\" +\n      \"</div>\",\n\n    // Loading indicator template\n    spinnerTpl: '<div class=\"fancybox-loading\"></div>',\n\n    // Error message template\n    errorTpl: '<div class=\"fancybox-error\"><p>{{ERROR}}</p></div>',\n\n    btnTpl: {\n      download:\n        '<a download data-fancybox-download class=\"fancybox-button fancybox-button--download\" title=\"{{DOWNLOAD}}\" href=\"javascript:;\">' +\n        '<svg viewBox=\"0 0 40 40\">' +\n        '<path d=\"M13,16 L20,23 L27,16 M20,7 L20,23 M10,24 L10,28 L30,28 L30,24\" />' +\n        \"</svg>\" +\n        \"</a>\",\n\n      zoom:\n        '<button data-fancybox-zoom class=\"fancybox-button fancybox-button--zoom\" title=\"{{ZOOM}}\">' +\n        '<svg viewBox=\"0 0 40 40\">' +\n        '<path d=\"M18,17 m-8,0 a8,8 0 1,0 16,0 a8,8 0 1,0 -16,0 M24,22 L31,29\" />' +\n        \"</svg>\" +\n        \"</button>\",\n\n      close:\n        '<button data-fancybox-close class=\"fancybox-button fancybox-button--close\" title=\"{{CLOSE}}\">' +\n        '<svg viewBox=\"0 0 40 40\">' +\n        '<path d=\"M10,10 L30,30 M30,10 L10,30\" />' +\n        \"</svg>\" +\n        \"</button>\",\n\n      // This small close button will be appended to your html/inline/ajax content by default,\n      // if \"smallBtn\" option is not set to false\n      smallBtn:\n        '<button data-fancybox-close class=\"fancybox-close-small\" title=\"{{CLOSE}}\"><svg viewBox=\"0 0 32 32\"><path d=\"M10,10 L22,22 M22,10 L10,22\"></path></svg></button>',\n\n      // Arrows\n      arrowLeft:\n        '<a data-fancybox-prev class=\"fancybox-button fancybox-button--arrow_left\" title=\"{{PREV}}\" href=\"javascript:;\">' +\n        '<svg viewBox=\"0 0 40 40\">' +\n        '<path d=\"M18,12 L10,20 L18,28 M10,20 L30,20\"></path>' +\n        \"</svg>\" +\n        \"</a>\",\n\n      arrowRight:\n        '<a data-fancybox-next class=\"fancybox-button fancybox-button--arrow_right\" title=\"{{NEXT}}\" href=\"javascript:;\">' +\n        '<svg viewBox=\"0 0 40 40\">' +\n        '<path d=\"M10,20 L30,20 M22,12 L30,20 L22,28\"></path>' +\n        \"</svg>\" +\n        \"</a>\"\n    },\n\n    // Container is injected into this element\n    parentEl: \"body\",\n\n    // Focus handling\n    // ==============\n\n    // Try to focus on the first focusable element after opening\n    autoFocus: false,\n\n    // Put focus back to active element after closing\n    backFocus: true,\n\n    // Do not let user to focus on element outside modal content\n    trapFocus: true,\n\n    // Module specific options\n    // =======================\n\n    fullScreen: {\n      autoStart: false\n    },\n\n    // Set `touch: false` to disable dragging/swiping\n    touch: {\n      vertical: true, // Allow to drag content vertically\n      momentum: true // Continue movement after releasing mouse/touch when panning\n    },\n\n    // Hash value when initializing manually,\n    // set `false` to disable hash change\n    hash: null,\n\n    // Customize or add new media types\n    // Example:\n    /*\n        media : {\n            youtube : {\n                params : {\n                    autoplay : 0\n                }\n            }\n        }\n        */\n    media: {},\n\n    slideShow: {\n      autoStart: false,\n      speed: 4000\n    },\n\n    thumbs: {\n      autoStart: false, // Display thumbnails on opening\n      hideOnClose: true, // Hide thumbnail grid when closing animation starts\n      parentEl: \".fancybox-container\", // Container is injected into this element\n      axis: \"y\" // Vertical (y) or horizontal (x) scrolling\n    },\n\n    // Use mousewheel to navigate gallery\n    // If 'auto' - enabled for images only\n    wheel: \"auto\",\n\n    // Callbacks\n    //==========\n\n    // See Documentation/API/Events for more information\n    // Example:\n    /*\n\t\tafterShow: function( instance, current ) {\n\t\t\tconsole.info( 'Clicked element:' );\n\t\t\tconsole.info( current.opts.$orig );\n\t\t}\n\t*/\n\n    onInit: $.noop, // When instance has been initialized\n\n    beforeLoad: $.noop, // Before the content of a slide is being loaded\n    afterLoad: $.noop, // When the content of a slide is done loading\n\n    beforeShow: $.noop, // Before open animation starts\n    afterShow: $.noop, // When content is done loading and animating\n\n    beforeClose: $.noop, // Before the instance attempts to close. Return false to cancel the close.\n    afterClose: $.noop, // After instance has been closed\n\n    onActivate: $.noop, // When instance is brought to front\n    onDeactivate: $.noop, // When other instance has been activated\n\n    // Interaction\n    // ===========\n\n    // Use options below to customize taken action when user clicks or double clicks on the fancyBox area,\n    // each option can be string or method that returns value.\n    //\n    // Possible values:\n    //   \"close\"           - close instance\n    //   \"next\"            - move to next gallery item\n    //   \"nextOrClose\"     - move to next gallery item or close if gallery has only one item\n    //   \"toggleControls\"  - show/hide controls\n    //   \"zoom\"            - zoom image (if loaded)\n    //   false             - do nothing\n\n    // Clicked on the content\n    clickContent: function(current, event) {\n      return current.type === \"image\" ? \"zoom\" : false;\n    },\n\n    // Clicked on the slide\n    clickSlide: \"close\",\n\n    // Clicked on the background (backdrop) element;\n    // if you have not changed the layout, then most likely you need to use `clickSlide` option\n    clickOutside: \"close\",\n\n    // Same as previous two, but for double click\n    dblclickContent: false,\n    dblclickSlide: false,\n    dblclickOutside: false,\n\n    // Custom options when mobile device is detected\n    // =============================================\n\n    mobile: {\n      idleTime: false,\n      clickContent: function(current, event) {\n        return current.type === \"image\" ? \"toggleControls\" : false;\n      },\n      clickSlide: function(current, event) {\n        return current.type === \"image\" ? \"toggleControls\" : \"close\";\n      },\n      dblclickContent: function(current, event) {\n        return current.type === \"image\" ? \"zoom\" : false;\n      },\n      dblclickSlide: function(current, event) {\n        return current.type === \"image\" ? \"zoom\" : false;\n      }\n    },\n\n    // Internationalization\n    // ====================\n\n    lang: \"en\",\n    i18n: {\n      en: {\n        CLOSE: \"Close\",\n        NEXT: \"Next\",\n        PREV: \"Previous\",\n        ERROR: \"The requested content cannot be loaded. <br/> Please try again later.\",\n        PLAY_START: \"Start slideshow\",\n        PLAY_STOP: \"Pause slideshow\",\n        FULL_SCREEN: \"Full screen\",\n        THUMBS: \"Thumbnails\",\n        DOWNLOAD: \"Download\",\n        SHARE: \"Share\",\n        ZOOM: \"Zoom\"\n      },\n      de: {\n        CLOSE: \"Schliessen\",\n        NEXT: \"Weiter\",\n        PREV: \"Zurück\",\n        ERROR: \"Die angeforderten Daten konnten nicht geladen werden. <br/> Bitte versuchen Sie es später nochmal.\",\n        PLAY_START: \"Diaschau starten\",\n        PLAY_STOP: \"Diaschau beenden\",\n        FULL_SCREEN: \"Vollbild\",\n        THUMBS: \"Vorschaubilder\",\n        DOWNLOAD: \"Herunterladen\",\n        SHARE: \"Teilen\",\n        ZOOM: \"Maßstab\"\n      }\n    }\n  };\n\n  // Few useful variables and methods\n  // ================================\n\n  var $W = $(window);\n  var $D = $(document);\n\n  var called = 0;\n\n  // Check if an object is a jQuery object and not a native JavaScript object\n  // ========================================================================\n  var isQuery = function(obj) {\n    return obj && obj.hasOwnProperty && obj instanceof $;\n  };\n\n  // Handle multiple browsers for \"requestAnimationFrame\" and \"cancelAnimationFrame\"\n  // ===============================================================================\n  var requestAFrame = (function() {\n    return (\n      window.requestAnimationFrame ||\n      window.webkitRequestAnimationFrame ||\n      window.mozRequestAnimationFrame ||\n      window.oRequestAnimationFrame ||\n      // if all else fails, use setTimeout\n      function(callback) {\n        return window.setTimeout(callback, 1000 / 60);\n      }\n    );\n  })();\n\n  // Detect the supported transition-end event property name\n  // =======================================================\n  var transitionEnd = (function() {\n    var el = document.createElement(\"fakeelement\"),\n      t;\n\n    var transitions = {\n      transition: \"transitionend\",\n      OTransition: \"oTransitionEnd\",\n      MozTransition: \"transitionend\",\n      WebkitTransition: \"webkitTransitionEnd\"\n    };\n\n    for (t in transitions) {\n      if (el.style[t] !== undefined) {\n        return transitions[t];\n      }\n    }\n\n    return \"transitionend\";\n  })();\n\n  // Force redraw on an element.\n  // This helps in cases where the browser doesn't redraw an updated element properly\n  // ================================================================================\n  var forceRedraw = function($el) {\n    return $el && $el.length && $el[0].offsetHeight;\n  };\n\n  // Exclude array (`buttons`) options from deep merging\n  // ===================================================\n  var mergeOpts = function(opts1, opts2) {\n    var rez = $.extend(true, {}, opts1, opts2);\n\n    $.each(opts2, function(key, value) {\n      if ($.isArray(value)) {\n        rez[key] = value;\n      }\n    });\n\n    return rez;\n  };\n\n  // Class definition\n  // ================\n\n  var FancyBox = function(content, opts, index) {\n    var self = this;\n\n    self.opts = mergeOpts({index: index}, $.fancybox.defaults);\n\n    if ($.isPlainObject(opts)) {\n      self.opts = mergeOpts(self.opts, opts);\n    }\n\n    if ($.fancybox.isMobile) {\n      self.opts = mergeOpts(self.opts, self.opts.mobile);\n    }\n\n    self.id = self.opts.id || ++called;\n\n    self.currIndex = parseInt(self.opts.index, 10) || 0;\n    self.prevIndex = null;\n\n    self.prevPos = null;\n    self.currPos = 0;\n\n    self.firstRun = true;\n\n    // All group items\n    self.group = [];\n\n    // Existing slides (for current, next and previous gallery items)\n    self.slides = {};\n\n    // Create group elements\n    self.addContent(content);\n\n    if (!self.group.length) {\n      return;\n    }\n\n    // Save last active element\n    self.$lastFocus = $(document.activeElement).trigger(\"blur\");\n\n    self.init();\n  };\n\n  $.extend(FancyBox.prototype, {\n    // Create DOM structure\n    // ====================\n\n    init: function() {\n      var self = this,\n        firstItem = self.group[self.currIndex],\n        firstItemOpts = firstItem.opts,\n        scrollbarWidth = $.fancybox.scrollbarWidth,\n        $scrollDiv,\n        $container,\n        buttonStr;\n\n      // Hide scrollbars\n      // ===============\n\n      if (!$.fancybox.getInstance() && firstItemOpts.hideScrollbar !== false) {\n        $(\"body\").addClass(\"fancybox-active\");\n\n        if (!$.fancybox.isMobile && document.body.scrollHeight > window.innerHeight) {\n          if (scrollbarWidth === undefined) {\n            $scrollDiv = $('<div style=\"width:100px;height:100px;overflow:scroll;\" />').appendTo(\"body\");\n\n            scrollbarWidth = $.fancybox.scrollbarWidth = $scrollDiv[0].offsetWidth - $scrollDiv[0].clientWidth;\n\n            $scrollDiv.remove();\n          }\n\n          $(\"head\").append(\n            '<style id=\"fancybox-style-noscroll\" type=\"text/css\">.compensate-for-scrollbar { margin-right: ' +\n              scrollbarWidth +\n              \"px; }</style>\"\n          );\n\n          $(\"body\").addClass(\"compensate-for-scrollbar\");\n        }\n      }\n\n      // Build html markup and set references\n      // ====================================\n\n      // Build html code for buttons and insert into main template\n      buttonStr = \"\";\n\n      $.each(firstItemOpts.buttons, function(index, value) {\n        buttonStr += firstItemOpts.btnTpl[value] || \"\";\n      });\n\n      // Create markup from base template, it will be initially hidden to\n      // avoid unnecessary work like painting while initializing is not complete\n      $container = $(\n        self.translate(\n          self,\n          firstItemOpts.baseTpl\n            .replace(\"{{buttons}}\", buttonStr)\n            .replace(\"{{arrows}}\", firstItemOpts.btnTpl.arrowLeft + firstItemOpts.btnTpl.arrowRight)\n        )\n      )\n        .attr(\"id\", \"fancybox-container-\" + self.id)\n        .addClass(\"fancybox-is-hidden\")\n        .addClass(firstItemOpts.baseClass)\n        .data(\"FancyBox\", self)\n        .appendTo(firstItemOpts.parentEl);\n\n      // Create object holding references to jQuery wrapped nodes\n      self.$refs = {\n        container: $container\n      };\n\n      [\"bg\", \"inner\", \"infobar\", \"toolbar\", \"stage\", \"caption\", \"navigation\"].forEach(function(item) {\n        self.$refs[item] = $container.find(\".fancybox-\" + item);\n      });\n\n      self.trigger(\"onInit\");\n\n      // Enable events, deactive previous instances\n      self.activate();\n\n      // Build slides, load and reveal content\n      self.jumpTo(self.currIndex);\n    },\n\n    // Simple i18n support - replaces object keys found in template\n    // with corresponding values\n    // ============================================================\n\n    translate: function(obj, str) {\n      var arr = obj.opts.i18n[obj.opts.lang];\n\n      return str.replace(/\\{\\{(\\w+)\\}\\}/g, function(match, n) {\n        var value = arr[n];\n\n        if (value === undefined) {\n          return match;\n        }\n\n        return value;\n      });\n    },\n\n    // Populate current group with fresh content\n    // Check if each object has valid type and content\n    // ===============================================\n\n    addContent: function(content) {\n      var self = this,\n        items = $.makeArray(content),\n        thumbs;\n\n      $.each(items, function(i, item) {\n        var obj = {},\n          opts = {},\n          $item,\n          type,\n          found,\n          src,\n          srcParts;\n\n        // Step 1 - Make sure we have an object\n        // ====================================\n\n        if ($.isPlainObject(item)) {\n          // We probably have manual usage here, something like\n          // $.fancybox.open( [ { src : \"image.jpg\", type : \"image\" } ] )\n\n          obj = item;\n          opts = item.opts || item;\n        } else if ($.type(item) === \"object\" && $(item).length) {\n          // Here we probably have jQuery collection returned by some selector\n          $item = $(item);\n\n          // Support attributes like `data-options='{\"touch\" : false}'` and `data-touch='false'`\n          opts = $item.data() || {};\n          opts = $.extend(true, {}, opts, opts.options);\n\n          // Here we store clicked element\n          opts.$orig = $item;\n\n          obj.src = self.opts.src || opts.src || $item.attr(\"href\");\n\n          // Assume that simple syntax is used, for example:\n          //   `$.fancybox.open( $(\"#test\"), {} );`\n          if (!obj.type && !obj.src) {\n            obj.type = \"inline\";\n            obj.src = item;\n          }\n        } else {\n          // Assume we have a simple html code, for example:\n          //   $.fancybox.open( '<div><h1>Hi!</h1></div>' );\n          obj = {\n            type: \"html\",\n            src: item + \"\"\n          };\n        }\n\n        // Each gallery object has full collection of options\n        obj.opts = $.extend(true, {}, self.opts, opts);\n\n        // Do not merge buttons array\n        if ($.isArray(opts.buttons)) {\n          obj.opts.buttons = opts.buttons;\n        }\n\n        // Step 2 - Make sure we have content type, if not - try to guess\n        // ==============================================================\n\n        type = obj.type || obj.opts.type;\n        src = obj.src || \"\";\n\n        if (!type && src) {\n          if ((found = src.match(/\\.(mp4|mov|ogv)((\\?|#).*)?$/i))) {\n            type = \"video\";\n\n            if (!obj.opts.videoFormat) {\n              obj.opts.videoFormat = \"video/\" + (found[1] === \"ogv\" ? \"ogg\" : found[1]);\n            }\n          } else if (src.match(/(^data:image\\/[a-z0-9+\\/=]*,)|(\\.(jp(e|g|eg)|gif|png|bmp|webp|svg|ico)((\\?|#).*)?$)/i)) {\n            type = \"image\";\n          } else if (src.match(/\\.(pdf)((\\?|#).*)?$/i)) {\n            type = \"iframe\";\n          } else if (src.charAt(0) === \"#\") {\n            type = \"inline\";\n          }\n        }\n\n        if (type) {\n          obj.type = type;\n        } else {\n          self.trigger(\"objectNeedsType\", obj);\n        }\n\n        if (!obj.contentType) {\n          obj.contentType = $.inArray(obj.type, [\"html\", \"inline\", \"ajax\"]) > -1 ? \"html\" : obj.type;\n        }\n\n        // Step 3 - Some adjustments\n        // =========================\n\n        obj.index = self.group.length;\n\n        if (obj.opts.smallBtn == \"auto\") {\n          obj.opts.smallBtn = $.inArray(obj.type, [\"html\", \"inline\", \"ajax\"]) > -1;\n        }\n\n        if (obj.opts.toolbar === \"auto\") {\n          obj.opts.toolbar = !obj.opts.smallBtn;\n        }\n\n        // Find thumbnail image\n        if (obj.opts.$trigger && obj.index === self.opts.index) {\n          obj.opts.$thumb = obj.opts.$trigger.find(\"img:first\");\n        }\n\n        if ((!obj.opts.$thumb || !obj.opts.$thumb.length) && obj.opts.$orig) {\n          obj.opts.$thumb = obj.opts.$orig.find(\"img:first\");\n        }\n\n        // \"caption\" is a \"special\" option, it can be used to customize caption per gallery item ..\n        if ($.type(obj.opts.caption) === \"function\") {\n          obj.opts.caption = obj.opts.caption.apply(item, [self, obj]);\n        }\n\n        if ($.type(self.opts.caption) === \"function\") {\n          obj.opts.caption = self.opts.caption.apply(item, [self, obj]);\n        }\n\n        // Make sure we have caption as a string or jQuery object\n        if (!(obj.opts.caption instanceof $)) {\n          obj.opts.caption = obj.opts.caption === undefined ? \"\" : obj.opts.caption + \"\";\n        }\n\n        // Check if url contains \"filter\" used to filter the content\n        // Example: \"ajax.html #something\"\n        if (obj.type === \"ajax\") {\n          srcParts = src.split(/\\s+/, 2);\n\n          if (srcParts.length > 1) {\n            obj.src = srcParts.shift();\n\n            obj.opts.filter = srcParts.shift();\n          }\n        }\n\n        // Hide all buttons and disable interactivity for modal items\n        if (obj.opts.modal) {\n          obj.opts = $.extend(true, obj.opts, {\n            // Remove buttons\n            infobar: 0,\n            toolbar: 0,\n\n            smallBtn: 0,\n\n            // Disable keyboard navigation\n            keyboard: 0,\n\n            // Disable some modules\n            slideShow: 0,\n            fullScreen: 0,\n            thumbs: 0,\n            touch: 0,\n\n            // Disable click event handlers\n            clickContent: false,\n            clickSlide: false,\n            clickOutside: false,\n            dblclickContent: false,\n            dblclickSlide: false,\n            dblclickOutside: false\n          });\n        }\n\n        // Step 4 - Add processed object to group\n        // ======================================\n\n        self.group.push(obj);\n      });\n\n      // Update controls if gallery is already opened\n      if (Object.keys(self.slides).length) {\n        self.updateControls();\n\n        // Update thumbnails, if needed\n        thumbs = self.Thumbs;\n\n        if (thumbs && thumbs.isActive) {\n          thumbs.create();\n\n          thumbs.focus();\n        }\n      }\n    },\n\n    // Attach an event handler functions for:\n    //   - navigation buttons\n    //   - browser scrolling, resizing;\n    //   - focusing\n    //   - keyboard\n    //   - detect idle\n    // ======================================\n\n    addEvents: function() {\n      var self = this;\n\n      self.removeEvents();\n\n      // Make navigation elements clickable\n      self.$refs.container\n        .on(\"click.fb-close\", \"[data-fancybox-close]\", function(e) {\n          e.stopPropagation();\n          e.preventDefault();\n\n          self.close(e);\n        })\n        .on(\"touchstart.fb-prev click.fb-prev\", \"[data-fancybox-prev]\", function(e) {\n          e.stopPropagation();\n          e.preventDefault();\n\n          self.previous();\n        })\n        .on(\"touchstart.fb-next click.fb-next\", \"[data-fancybox-next]\", function(e) {\n          e.stopPropagation();\n          e.preventDefault();\n\n          self.next();\n        })\n        .on(\"click.fb\", \"[data-fancybox-zoom]\", function(e) {\n          // Click handler for zoom button\n          self[self.isScaledDown() ? \"scaleToActual\" : \"scaleToFit\"]();\n        });\n\n      // Handle page scrolling and browser resizing\n      $W.on(\"orientationchange.fb resize.fb\", function(e) {\n        if (e && e.originalEvent && e.originalEvent.type === \"resize\") {\n          requestAFrame(function() {\n            self.update();\n          });\n        } else {\n          self.$refs.stage.hide();\n\n          setTimeout(function() {\n            self.$refs.stage.show();\n\n            self.update();\n          }, $.fancybox.isMobile ? 600 : 250);\n        }\n      });\n\n      // Trap keyboard focus inside of the modal, so the user does not accidentally tab outside of the modal\n      // (a.k.a. \"escaping the modal\")\n      $D.on(\"focusin.fb\", function(e) {\n        var instance = $.fancybox ? $.fancybox.getInstance() : null;\n\n        if (\n          instance.isClosing ||\n          !instance.current ||\n          !instance.current.opts.trapFocus ||\n          $(e.target).hasClass(\"fancybox-container\") ||\n          $(e.target).is(document)\n        ) {\n          return;\n        }\n\n        if (instance && $(e.target).css(\"position\") !== \"fixed\" && !instance.$refs.container.has(e.target).length) {\n          e.stopPropagation();\n\n          instance.focus();\n        }\n      });\n\n      // Enable keyboard navigation\n      $D.on(\"keydown.fb\", function(e) {\n        var current = self.current,\n          keycode = e.keyCode || e.which;\n\n        if (!current || !current.opts.keyboard) {\n          return;\n        }\n\n        if (e.ctrlKey || e.altKey || e.shiftKey || $(e.target).is(\"input\") || $(e.target).is(\"textarea\")) {\n          return;\n        }\n\n        // Backspace and Esc keys\n        if (keycode === 8 || keycode === 27) {\n          e.preventDefault();\n\n          self.close(e);\n\n          return;\n        }\n\n        // Left arrow and Up arrow\n        if (keycode === 37 || keycode === 38) {\n          e.preventDefault();\n\n          self.previous();\n\n          return;\n        }\n\n        // Righ arrow and Down arrow\n        if (keycode === 39 || keycode === 40) {\n          e.preventDefault();\n\n          self.next();\n\n          return;\n        }\n\n        self.trigger(\"afterKeydown\", e, keycode);\n      });\n\n      // Hide controls after some inactivity period\n      if (self.group[self.currIndex].opts.idleTime) {\n        self.idleSecondsCounter = 0;\n\n        $D.on(\n          \"mousemove.fb-idle mouseleave.fb-idle mousedown.fb-idle touchstart.fb-idle touchmove.fb-idle scroll.fb-idle keydown.fb-idle\",\n          function(e) {\n            self.idleSecondsCounter = 0;\n\n            if (self.isIdle) {\n              self.showControls();\n            }\n\n            self.isIdle = false;\n          }\n        );\n\n        self.idleInterval = window.setInterval(function() {\n          self.idleSecondsCounter++;\n\n          if (self.idleSecondsCounter >= self.group[self.currIndex].opts.idleTime && !self.isDragging) {\n            self.isIdle = true;\n            self.idleSecondsCounter = 0;\n\n            self.hideControls();\n          }\n        }, 1000);\n      }\n    },\n\n    // Remove events added by the core\n    // ===============================\n\n    removeEvents: function() {\n      var self = this;\n\n      $W.off(\"orientationchange.fb resize.fb\");\n      $D.off(\"focusin.fb keydown.fb .fb-idle\");\n\n      this.$refs.container.off(\".fb-close .fb-prev .fb-next\");\n\n      if (self.idleInterval) {\n        window.clearInterval(self.idleInterval);\n\n        self.idleInterval = null;\n      }\n    },\n\n    // Change to previous gallery item\n    // ===============================\n\n    previous: function(duration) {\n      return this.jumpTo(this.currPos - 1, duration);\n    },\n\n    // Change to next gallery item\n    // ===========================\n\n    next: function(duration) {\n      return this.jumpTo(this.currPos + 1, duration);\n    },\n\n    // Switch to selected gallery item\n    // ===============================\n\n    jumpTo: function(pos, duration) {\n      var self = this,\n        groupLen = self.group.length,\n        firstRun,\n        loop,\n        current,\n        previous,\n        canvasWidth,\n        currentPos,\n        transitionProps;\n\n      if (self.isDragging || self.isClosing || (self.isAnimating && self.firstRun)) {\n        return;\n      }\n\n      pos = parseInt(pos, 10);\n\n      // Should loop?\n      loop = self.current ? self.current.opts.loop : self.opts.loop;\n\n      if (!loop && (pos < 0 || pos >= groupLen)) {\n        return false;\n      }\n\n      firstRun = self.firstRun = !Object.keys(self.slides).length;\n\n      if (groupLen < 2 && !firstRun && !!self.isDragging) {\n        return;\n      }\n\n      previous = self.current;\n\n      self.prevIndex = self.currIndex;\n      self.prevPos = self.currPos;\n\n      // Create slides\n      current = self.createSlide(pos);\n\n      if (groupLen > 1) {\n        if (loop || current.index > 0) {\n          self.createSlide(pos - 1);\n        }\n\n        if (loop || current.index < groupLen - 1) {\n          self.createSlide(pos + 1);\n        }\n      }\n\n      self.current = current;\n      self.currIndex = current.index;\n      self.currPos = current.pos;\n\n      self.trigger(\"beforeShow\", firstRun);\n\n      self.updateControls();\n\n      currentPos = $.fancybox.getTranslate(current.$slide);\n\n      current.isMoved = (currentPos.left !== 0 || currentPos.top !== 0) && !current.$slide.hasClass(\"fancybox-animated\");\n\n      // Validate duration length\n      current.forcedDuration = undefined;\n\n      if ($.isNumeric(duration)) {\n        current.forcedDuration = duration;\n      } else {\n        duration = current.opts[firstRun ? \"animationDuration\" : \"transitionDuration\"];\n      }\n\n      duration = parseInt(duration, 10);\n\n      // Fresh start - reveal container, current slide and start loading content\n      if (firstRun) {\n        if (current.opts.animationEffect && duration) {\n          self.$refs.container.css(\"transition-duration\", duration + \"ms\");\n        }\n\n        self.$refs.container.removeClass(\"fancybox-is-hidden\");\n\n        forceRedraw(self.$refs.container);\n\n        self.$refs.container.addClass(\"fancybox-is-open\");\n\n        forceRedraw(self.$refs.container);\n\n        // Make current slide visible\n        current.$slide.addClass(\"fancybox-slide--previous\");\n\n        // Attempt to load content into slide;\n        // at this point image would start loading, but inline/html content would load immediately\n        self.loadSlide(current);\n\n        current.$slide.removeClass(\"fancybox-slide--previous\").addClass(\"fancybox-slide--current\");\n\n        self.preload(\"image\");\n\n        return;\n      }\n\n      // Clean up\n      $.each(self.slides, function(index, slide) {\n        $.fancybox.stop(slide.$slide);\n      });\n\n      // Make current that slide is visible even if content is still loading\n      current.$slide.removeClass(\"fancybox-slide--next fancybox-slide--previous\").addClass(\"fancybox-slide--current\");\n\n      // If slides have been dragged, animate them to correct position\n      if (current.isMoved) {\n        canvasWidth = Math.round(current.$slide.width());\n\n        $.each(self.slides, function(index, slide) {\n          var pos = slide.pos - current.pos;\n\n          $.fancybox.animate(\n            slide.$slide,\n            {\n              top: 0,\n              left: pos * canvasWidth + pos * slide.opts.gutter\n            },\n            duration,\n            function() {\n              slide.$slide.removeAttr(\"style\").removeClass(\"fancybox-slide--next fancybox-slide--previous\");\n\n              if (slide.pos === self.currPos) {\n                current.isMoved = false;\n\n                self.complete();\n              }\n            }\n          );\n        });\n      } else {\n        self.$refs.stage.children().removeAttr(\"style\");\n      }\n\n      // Start transition that reveals current content\n      // or wait when it will be loaded\n\n      if (current.isLoaded) {\n        self.revealContent(current);\n      } else {\n        self.loadSlide(current);\n      }\n\n      self.preload(\"image\");\n\n      if (previous.pos === current.pos) {\n        return;\n      }\n\n      // Handle previous slide\n      // =====================\n\n      transitionProps = \"fancybox-slide--\" + (previous.pos > current.pos ? \"next\" : \"previous\");\n\n      previous.$slide.removeClass(\"fancybox-slide--complete fancybox-slide--current fancybox-slide--next fancybox-slide--previous\");\n\n      previous.isComplete = false;\n\n      if (!duration || (!current.isMoved && !current.opts.transitionEffect)) {\n        return;\n      }\n\n      if (current.isMoved) {\n        previous.$slide.addClass(transitionProps);\n      } else {\n        transitionProps = \"fancybox-animated \" + transitionProps + \" fancybox-fx-\" + current.opts.transitionEffect;\n\n        $.fancybox.animate(previous.$slide, transitionProps, duration, function() {\n          previous.$slide.removeClass(transitionProps).removeAttr(\"style\");\n        });\n      }\n    },\n\n    // Create new \"slide\" element\n    // These are gallery items  that are actually added to DOM\n    // =======================================================\n\n    createSlide: function(pos) {\n      var self = this,\n        $slide,\n        index;\n\n      index = pos % self.group.length;\n      index = index < 0 ? self.group.length + index : index;\n\n      if (!self.slides[pos] && self.group[index]) {\n        $slide = $('<div class=\"fancybox-slide\"></div>').appendTo(self.$refs.stage);\n\n        self.slides[pos] = $.extend(true, {}, self.group[index], {\n          pos: pos,\n          $slide: $slide,\n          isLoaded: false\n        });\n\n        self.updateSlide(self.slides[pos]);\n      }\n\n      return self.slides[pos];\n    },\n\n    // Scale image to the actual size of the image;\n    // x and y values should be relative to the slide\n    // ==============================================\n\n    scaleToActual: function(x, y, duration) {\n      var self = this,\n        current = self.current,\n        $content = current.$content,\n        canvasWidth = $.fancybox.getTranslate(current.$slide).width,\n        canvasHeight = $.fancybox.getTranslate(current.$slide).height,\n        newImgWidth = current.width,\n        newImgHeight = current.height,\n        imgPos,\n        posX,\n        posY,\n        scaleX,\n        scaleY;\n\n      if (self.isAnimating || !$content || !(current.type == \"image\" && current.isLoaded && !current.hasError)) {\n        return;\n      }\n\n      $.fancybox.stop($content);\n\n      self.isAnimating = true;\n\n      x = x === undefined ? canvasWidth * 0.5 : x;\n      y = y === undefined ? canvasHeight * 0.5 : y;\n\n      imgPos = $.fancybox.getTranslate($content);\n\n      imgPos.top -= $.fancybox.getTranslate(current.$slide).top;\n      imgPos.left -= $.fancybox.getTranslate(current.$slide).left;\n\n      scaleX = newImgWidth / imgPos.width;\n      scaleY = newImgHeight / imgPos.height;\n\n      // Get center position for original image\n      posX = canvasWidth * 0.5 - newImgWidth * 0.5;\n      posY = canvasHeight * 0.5 - newImgHeight * 0.5;\n\n      // Make sure image does not move away from edges\n      if (newImgWidth > canvasWidth) {\n        posX = imgPos.left * scaleX - (x * scaleX - x);\n\n        if (posX > 0) {\n          posX = 0;\n        }\n\n        if (posX < canvasWidth - newImgWidth) {\n          posX = canvasWidth - newImgWidth;\n        }\n      }\n\n      if (newImgHeight > canvasHeight) {\n        posY = imgPos.top * scaleY - (y * scaleY - y);\n\n        if (posY > 0) {\n          posY = 0;\n        }\n\n        if (posY < canvasHeight - newImgHeight) {\n          posY = canvasHeight - newImgHeight;\n        }\n      }\n\n      self.updateCursor(newImgWidth, newImgHeight);\n\n      $.fancybox.animate(\n        $content,\n        {\n          top: posY,\n          left: posX,\n          scaleX: scaleX,\n          scaleY: scaleY\n        },\n        duration || 330,\n        function() {\n          self.isAnimating = false;\n        }\n      );\n\n      // Stop slideshow\n      if (self.SlideShow && self.SlideShow.isActive) {\n        self.SlideShow.stop();\n      }\n    },\n\n    // Scale image to fit inside parent element\n    // ========================================\n\n    scaleToFit: function(duration) {\n      var self = this,\n        current = self.current,\n        $content = current.$content,\n        end;\n\n      if (self.isAnimating || !$content || !(current.type == \"image\" && current.isLoaded && !current.hasError)) {\n        return;\n      }\n\n      $.fancybox.stop($content);\n\n      self.isAnimating = true;\n\n      end = self.getFitPos(current);\n\n      self.updateCursor(end.width, end.height);\n\n      $.fancybox.animate(\n        $content,\n        {\n          top: end.top,\n          left: end.left,\n          scaleX: end.width / $content.width(),\n          scaleY: end.height / $content.height()\n        },\n        duration || 330,\n        function() {\n          self.isAnimating = false;\n        }\n      );\n    },\n\n    // Calculate image size to fit inside viewport\n    // ===========================================\n\n    getFitPos: function(slide) {\n      var self = this,\n        $content = slide.$content,\n        width = slide.width || slide.opts.width,\n        height = slide.height || slide.opts.height,\n        maxWidth,\n        maxHeight,\n        minRatio,\n        margin,\n        aspectRatio,\n        rez = {};\n\n      if (!slide.isLoaded || !$content || !$content.length) {\n        return false;\n      }\n\n      margin = {\n        top: parseInt(slide.$slide.css(\"paddingTop\"), 10),\n        right: parseInt(slide.$slide.css(\"paddingRight\"), 10),\n        bottom: parseInt(slide.$slide.css(\"paddingBottom\"), 10),\n        left: parseInt(slide.$slide.css(\"paddingLeft\"), 10)\n      };\n\n      // We can not use $slide width here, because it can have different diemensions while in transiton\n      maxWidth = parseInt(self.$refs.stage.width(), 10) - (margin.left + margin.right);\n      maxHeight = parseInt(self.$refs.stage.height(), 10) - (margin.top + margin.bottom);\n\n      if (!width || !height) {\n        width = maxWidth;\n        height = maxHeight;\n      }\n\n      minRatio = Math.min(1, maxWidth / width, maxHeight / height);\n\n      // Use floor rounding to make sure it really fits\n      width = Math.floor(minRatio * width);\n      height = Math.floor(minRatio * height);\n\n      if (slide.type === \"image\") {\n        rez.top = Math.floor((maxHeight - height) * 0.5) + margin.top;\n        rez.left = Math.floor((maxWidth - width) * 0.5) + margin.left;\n      } else if (slide.contentType === \"video\") {\n        // Force aspect ratio for the video\n        // \"I say the whole world must learn of our peaceful ways… by force!\"\n        aspectRatio = slide.opts.width && slide.opts.height ? width / height : slide.opts.ratio || 16 / 9;\n\n        if (height > width / aspectRatio) {\n          height = width / aspectRatio;\n        } else if (width > height * aspectRatio) {\n          width = height * aspectRatio;\n        }\n      }\n\n      rez.width = width;\n      rez.height = height;\n\n      return rez;\n    },\n\n    // Update content size and position for all slides\n    // ==============================================\n\n    update: function() {\n      var self = this;\n\n      $.each(self.slides, function(key, slide) {\n        self.updateSlide(slide);\n      });\n    },\n\n    // Update slide content position and size\n    // ======================================\n\n    updateSlide: function(slide, duration) {\n      var self = this,\n        $content = slide && slide.$content,\n        width = slide.width || slide.opts.width,\n        height = slide.height || slide.opts.height;\n\n      if ($content && (width || height || slide.contentType === \"video\") && !slide.hasError) {\n        $.fancybox.stop($content);\n\n        $.fancybox.setTranslate($content, self.getFitPos(slide));\n\n        if (slide.pos === self.currPos) {\n          self.isAnimating = false;\n\n          self.updateCursor();\n        }\n      }\n\n      slide.$slide.trigger(\"refresh\");\n\n      self.$refs.toolbar.toggleClass(\"compensate-for-scrollbar\", slide.$slide.get(0).scrollHeight > slide.$slide.get(0).clientHeight);\n\n      self.trigger(\"onUpdate\", slide);\n    },\n\n    // Horizontally center slide\n    // =========================\n\n    centerSlide: function(slide, duration) {\n      var self = this,\n        canvasWidth,\n        pos;\n\n      if (self.current) {\n        canvasWidth = Math.round(slide.$slide.width());\n        pos = slide.pos - self.current.pos;\n\n        $.fancybox.animate(\n          slide.$slide,\n          {\n            top: 0,\n            left: pos * canvasWidth + pos * slide.opts.gutter,\n            opacity: 1\n          },\n          duration === undefined ? 0 : duration,\n          null,\n          false\n        );\n      }\n    },\n\n    // Update cursor style depending if content can be zoomed\n    // ======================================================\n\n    updateCursor: function(nextWidth, nextHeight) {\n      var self = this,\n        current = self.current,\n        $container = self.$refs.container.removeClass(\"fancybox-is-zoomable fancybox-can-zoomIn fancybox-can-drag fancybox-can-zoomOut\"),\n        isZoomable;\n\n      if (!current || self.isClosing) {\n        return;\n      }\n\n      isZoomable = self.isZoomable();\n\n      $container.toggleClass(\"fancybox-is-zoomable\", isZoomable);\n\n      $(\"[data-fancybox-zoom]\").prop(\"disabled\", !isZoomable);\n\n      // Set cursor to zoom in/out if click event is 'zoom'\n      if (\n        isZoomable &&\n        (current.opts.clickContent === \"zoom\" || ($.isFunction(current.opts.clickContent) && current.opts.clickContent(current) === \"zoom\"))\n      ) {\n        if (self.isScaledDown(nextWidth, nextHeight)) {\n          // If image is scaled down, then, obviously, it can be zoomed to full size\n          $container.addClass(\"fancybox-can-zoomIn\");\n        } else {\n          if (current.opts.touch) {\n            // If image size ir largen than available available and touch module is not disable,\n            // then user can do panning\n            $container.addClass(\"fancybox-can-drag\");\n          } else {\n            $container.addClass(\"fancybox-can-zoomOut\");\n          }\n        }\n      } else if (current.opts.touch && current.contentType !== \"video\") {\n        $container.addClass(\"fancybox-can-drag\");\n      }\n    },\n\n    // Check if current slide is zoomable\n    // ==================================\n\n    isZoomable: function() {\n      var self = this,\n        current = self.current,\n        fitPos;\n\n      // Assume that slide is zoomable if:\n      //   - image is still loading\n      //   - actual size of the image is smaller than available area\n      if (current && !self.isClosing && current.type === \"image\" && !current.hasError) {\n        if (!current.isLoaded) {\n          return true;\n        }\n\n        fitPos = self.getFitPos(current);\n\n        if (current.width > fitPos.width || current.height > fitPos.height) {\n          return true;\n        }\n      }\n\n      return false;\n    },\n\n    // Check if current image dimensions are smaller than actual\n    // =========================================================\n\n    isScaledDown: function(nextWidth, nextHeight) {\n      var self = this,\n        rez = false,\n        current = self.current,\n        $content = current.$content;\n\n      if (nextWidth !== undefined && nextHeight !== undefined) {\n        rez = nextWidth < current.width && nextHeight < current.height;\n      } else if ($content) {\n        rez = $.fancybox.getTranslate($content);\n        rez = rez.width < current.width && rez.height < current.height;\n      }\n\n      return rez;\n    },\n\n    // Check if image dimensions exceed parent element\n    // ===============================================\n\n    canPan: function() {\n      var self = this,\n        rez = false,\n        current = self.current,\n        $content;\n\n      if (current.type === \"image\" && ($content = current.$content) && !current.hasError) {\n        rez = self.getFitPos(current);\n        rez = Math.abs($content.width() - rez.width) > 1 || Math.abs($content.height() - rez.height) > 1;\n      }\n\n      return rez;\n    },\n\n    // Load content into the slide\n    // ===========================\n\n    loadSlide: function(slide) {\n      var self = this,\n        type,\n        $slide,\n        ajaxLoad;\n\n      if (slide.isLoading || slide.isLoaded) {\n        return;\n      }\n\n      slide.isLoading = true;\n\n      self.trigger(\"beforeLoad\", slide);\n\n      type = slide.type;\n      $slide = slide.$slide;\n\n      $slide\n        .off(\"refresh\")\n        .trigger(\"onReset\")\n        .addClass(slide.opts.slideClass);\n\n      // Create content depending on the type\n      switch (type) {\n        case \"image\":\n          self.setImage(slide);\n\n          break;\n\n        case \"iframe\":\n          self.setIframe(slide);\n\n          break;\n\n        case \"html\":\n          self.setContent(slide, slide.src || slide.content);\n\n          break;\n\n        case \"video\":\n          self.setContent(\n            slide,\n            '<video class=\"fancybox-video\" controls controlsList=\"nodownload\">' +\n              '<source src=\"' +\n              slide.src +\n              '\" type=\"' +\n              slide.opts.videoFormat +\n              '\">' +\n              \"Your browser doesn't support HTML5 video\" +\n              \"</video\"\n          );\n\n          break;\n\n        case \"inline\":\n          if ($(slide.src).length) {\n            self.setContent(slide, $(slide.src));\n          } else {\n            self.setError(slide);\n          }\n\n          break;\n\n        case \"ajax\":\n          self.showLoading(slide);\n\n          ajaxLoad = $.ajax(\n            $.extend({}, slide.opts.ajax.settings, {\n              url: slide.src,\n              success: function(data, textStatus) {\n                if (textStatus === \"success\") {\n                  self.setContent(slide, data);\n                }\n              },\n              error: function(jqXHR, textStatus) {\n                if (jqXHR && textStatus !== \"abort\") {\n                  self.setError(slide);\n                }\n              }\n            })\n          );\n\n          $slide.one(\"onReset\", function() {\n            ajaxLoad.abort();\n          });\n\n          break;\n\n        default:\n          self.setError(slide);\n\n          break;\n      }\n\n      return true;\n    },\n\n    // Use thumbnail image, if possible\n    // ================================\n\n    setImage: function(slide) {\n      var self = this,\n        srcset = slide.opts.srcset || slide.opts.image.srcset,\n        thumbSrc,\n        found,\n        temp,\n        pxRatio,\n        windowWidth;\n\n      // Check if need to show loading icon\n      slide.timouts = setTimeout(function() {\n        var $img = slide.$image;\n\n        if (slide.isLoading && (!$img || !$img[0].complete) && !slide.hasError) {\n          self.showLoading(slide);\n        }\n      }, 350);\n\n      // If we have \"srcset\", then we need to find first matching \"src\" value.\n      // This is necessary, because when you set an src attribute, the browser will preload the image\n      // before any javascript or even CSS is applied.\n      if (srcset) {\n        pxRatio = window.devicePixelRatio || 1;\n        windowWidth = window.innerWidth * pxRatio;\n\n        temp = srcset.split(\",\").map(function(el) {\n          var ret = {};\n\n          el\n            .trim()\n            .split(/\\s+/)\n            .forEach(function(el, i) {\n              var value = parseInt(el.substring(0, el.length - 1), 10);\n\n              if (i === 0) {\n                return (ret.url = el);\n              }\n\n              if (value) {\n                ret.value = value;\n                ret.postfix = el[el.length - 1];\n              }\n            });\n\n          return ret;\n        });\n\n        // Sort by value\n        temp.sort(function(a, b) {\n          return a.value - b.value;\n        });\n\n        // Ok, now we have an array of all srcset values\n        for (var j = 0; j < temp.length; j++) {\n          var el = temp[j];\n\n          if ((el.postfix === \"w\" && el.value >= windowWidth) || (el.postfix === \"x\" && el.value >= pxRatio)) {\n            found = el;\n            break;\n          }\n        }\n\n        // If not found, take the last one\n        if (!found && temp.length) {\n          found = temp[temp.length - 1];\n        }\n\n        if (found) {\n          slide.src = found.url;\n\n          // If we have default width/height values, we can calculate height for matching source\n          if (slide.width && slide.height && found.postfix == \"w\") {\n            slide.height = slide.width / slide.height * found.value;\n            slide.width = found.value;\n          }\n\n          slide.opts.srcset = srcset;\n        }\n      }\n\n      // This will be wrapper containing both ghost and actual image\n      slide.$content = $('<div class=\"fancybox-content\"></div>')\n        .addClass(\"fancybox-is-hidden\")\n        .appendTo(slide.$slide.addClass(\"fancybox-slide--image\"));\n\n      // If we have a thumbnail, we can display it while actual image is loading\n      // Users will not stare at black screen and actual image will appear gradually\n      thumbSrc = slide.opts.thumb || (slide.opts.$thumb && slide.opts.$thumb.length ? slide.opts.$thumb.attr(\"src\") : false);\n\n      if (slide.opts.preload !== false && slide.opts.width && slide.opts.height && thumbSrc) {\n        slide.width = slide.opts.width;\n        slide.height = slide.opts.height;\n\n        slide.$ghost = $(\"<img />\")\n          .one(\"error\", function() {\n            $(this).remove();\n\n            slide.$ghost = null;\n          })\n          .one(\"load\", function() {\n            self.afterLoad(slide);\n          })\n          .addClass(\"fancybox-image\")\n          .appendTo(slide.$content)\n          .attr(\"src\", thumbSrc);\n      }\n\n      // Start loading actual image\n      self.setBigImage(slide);\n    },\n\n    // Create full-size image\n    // ======================\n\n    setBigImage: function(slide) {\n      var self = this,\n        $img = $(\"<img />\");\n\n      slide.$image = $img\n        .one(\"error\", function() {\n          self.setError(slide);\n        })\n        .one(\"load\", function() {\n          var sizes;\n\n          if (!slide.$ghost) {\n            self.resolveImageSlideSize(slide, this.naturalWidth, this.naturalHeight);\n\n            self.afterLoad(slide);\n          }\n\n          // Clear timeout that checks if loading icon needs to be displayed\n          if (slide.timouts) {\n            clearTimeout(slide.timouts);\n            slide.timouts = null;\n          }\n\n          if (self.isClosing) {\n            return;\n          }\n\n          if (slide.opts.srcset) {\n            sizes = slide.opts.sizes;\n\n            if (!sizes || sizes === \"auto\") {\n              sizes =\n                (slide.width / slide.height > 1 && $W.width() / $W.height() > 1 ? \"100\" : Math.round(slide.width / slide.height * 100)) +\n                \"vw\";\n            }\n\n            $img.attr(\"sizes\", sizes).attr(\"srcset\", slide.opts.srcset);\n          }\n\n          // Hide temporary image after some delay\n          if (slide.$ghost) {\n            setTimeout(function() {\n              if (slide.$ghost && !self.isClosing) {\n                slide.$ghost.hide();\n              }\n            }, Math.min(300, Math.max(1000, slide.height / 1600)));\n          }\n\n          self.hideLoading(slide);\n        })\n        .addClass(\"fancybox-image\")\n        .attr(\"src\", slide.src)\n        .appendTo(slide.$content);\n\n      if (($img[0].complete || $img[0].readyState == \"complete\") && $img[0].naturalWidth && $img[0].naturalHeight) {\n        $img.trigger(\"load\");\n      } else if ($img[0].error) {\n        $img.trigger(\"error\");\n      }\n    },\n\n    // Computes the slide size from image size and maxWidth/maxHeight\n    // ==============================================================\n\n    resolveImageSlideSize: function(slide, imgWidth, imgHeight) {\n      var maxWidth = parseInt(slide.opts.width, 10),\n        maxHeight = parseInt(slide.opts.height, 10);\n\n      // Sets the default values from the image\n      slide.width = imgWidth;\n      slide.height = imgHeight;\n\n      if (maxWidth > 0) {\n        slide.width = maxWidth;\n        slide.height = Math.floor(maxWidth * imgHeight / imgWidth);\n      }\n\n      if (maxHeight > 0) {\n        slide.width = Math.floor(maxHeight * imgWidth / imgHeight);\n        slide.height = maxHeight;\n      }\n    },\n\n    // Create iframe wrapper, iframe and bindings\n    // ==========================================\n\n    setIframe: function(slide) {\n      var self = this,\n        opts = slide.opts.iframe,\n        $slide = slide.$slide,\n        $iframe;\n\n      slide.$content = $('<div class=\"fancybox-content' + (opts.preload ? \" fancybox-is-hidden\" : \"\") + '\"></div>')\n        .css(opts.css)\n        .appendTo($slide);\n\n      $slide.addClass(\"fancybox-slide--\" + slide.contentType);\n\n      slide.$iframe = $iframe = $(opts.tpl.replace(/\\{rnd\\}/g, new Date().getTime()))\n        .attr(opts.attr)\n        .appendTo(slide.$content);\n\n      if (opts.preload) {\n        self.showLoading(slide);\n\n        // Unfortunately, it is not always possible to determine if iframe is successfully loaded\n        // (due to browser security policy)\n\n        $iframe.on(\"load.fb error.fb\", function(e) {\n          this.isReady = 1;\n\n          slide.$slide.trigger(\"refresh\");\n\n          self.afterLoad(slide);\n        });\n\n        // Recalculate iframe content size\n        // ===============================\n\n        $slide.on(\"refresh.fb\", function() {\n          var $content = slide.$content,\n            frameWidth = opts.css.width,\n            frameHeight = opts.css.height,\n            $contents,\n            $body;\n\n          if ($iframe[0].isReady !== 1) {\n            return;\n          }\n\n          try {\n            $contents = $iframe.contents();\n            $body = $contents.find(\"body\");\n          } catch (ignore) {}\n\n          // Calculate contnet dimensions if it is accessible\n          if ($body && $body.length && $body.children().length) {\n            $content.css({\n              width: \"\",\n              height: \"\"\n            });\n\n            if (frameWidth === undefined) {\n              frameWidth = Math.ceil(Math.max($body[0].clientWidth, $body.outerWidth(true)));\n            }\n\n            if (frameWidth) {\n              $content.width(frameWidth);\n            }\n\n            if (frameHeight === undefined) {\n              frameHeight = Math.ceil(Math.max($body[0].clientHeight, $body.outerHeight(true)));\n            }\n\n            if (frameHeight) {\n              $content.height(frameHeight);\n            }\n          }\n\n          $content.removeClass(\"fancybox-is-hidden\");\n        });\n      } else {\n        this.afterLoad(slide);\n      }\n\n      $iframe.attr(\"src\", slide.src);\n\n      // Remove iframe if closing or changing gallery item\n      $slide.one(\"onReset\", function() {\n        // This helps IE not to throw errors when closing\n        try {\n          $(this)\n            .find(\"iframe\")\n            .hide()\n            .unbind()\n            .attr(\"src\", \"//about:blank\");\n        } catch (ignore) {}\n\n        $(this)\n          .off(\"refresh.fb\")\n          .empty();\n\n        slide.isLoaded = false;\n      });\n    },\n\n    // Wrap and append content to the slide\n    // ======================================\n\n    setContent: function(slide, content) {\n      var self = this;\n\n      if (self.isClosing) {\n        return;\n      }\n\n      self.hideLoading(slide);\n\n      if (slide.$content) {\n        $.fancybox.stop(slide.$content);\n      }\n\n      slide.$slide.empty();\n\n      // If content is a jQuery object, then it will be moved to the slide.\n      // The placeholder is created so we will know where to put it back.\n      if (isQuery(content) && content.parent().length) {\n        // Make sure content is not already moved to fancyBox\n        content\n          .parent()\n          .parent(\".fancybox-slide--inline\")\n          .trigger(\"onReset\");\n\n        // Create temporary element marking original place of the content\n        slide.$placeholder = $(\"<div>\")\n          .hide()\n          .insertAfter(content);\n\n        // Make sure content is visible\n        content.css(\"display\", \"inline-block\");\n      } else if (!slide.hasError) {\n        // If content is just a plain text, try to convert it to html\n        if ($.type(content) === \"string\") {\n          content = $(\"<div>\")\n            .append($.trim(content))\n            .contents();\n\n          // If we have text node, then add wrapping element to make vertical alignment work\n          if (content[0].nodeType === 3) {\n            content = $(\"<div>\").html(content);\n          }\n        }\n\n        // If \"filter\" option is provided, then filter content\n        if (slide.opts.filter) {\n          content = $(\"<div>\")\n            .html(content)\n            .find(slide.opts.filter);\n        }\n      }\n\n      slide.$slide.one(\"onReset\", function() {\n        // Pause all html5 video/audio\n        $(this)\n          .find(\"video,audio\")\n          .trigger(\"pause\");\n\n        // Put content back\n        if (slide.$placeholder) {\n          slide.$placeholder.after(content.hide()).remove();\n\n          slide.$placeholder = null;\n        }\n\n        // Remove custom close button\n        if (slide.$smallBtn) {\n          slide.$smallBtn.remove();\n\n          slide.$smallBtn = null;\n        }\n\n        // Remove content and mark slide as not loaded\n        if (!slide.hasError) {\n          $(this).empty();\n\n          slide.isLoaded = false;\n        }\n      });\n\n      $(content).appendTo(slide.$slide);\n\n      if ($(content).is(\"video,audio\")) {\n        $(content).addClass(\"fancybox-video\");\n\n        $(content).wrap(\"<div></div>\");\n\n        slide.contentType = \"video\";\n\n        slide.opts.width = slide.opts.width || $(content).attr(\"width\");\n        slide.opts.height = slide.opts.height || $(content).attr(\"height\");\n      }\n\n      slide.$content = slide.$slide\n        .children()\n        .filter(\"div,form,main,video,audio\")\n        .first()\n        .addClass(\"fancybox-content\");\n\n      slide.$slide.addClass(\"fancybox-slide--\" + slide.contentType);\n\n      this.afterLoad(slide);\n    },\n\n    // Display error message\n    // =====================\n\n    setError: function(slide) {\n      slide.hasError = true;\n\n      slide.$slide\n        .trigger(\"onReset\")\n        .removeClass(\"fancybox-slide--\" + slide.contentType)\n        .addClass(\"fancybox-slide--error\");\n\n      slide.contentType = \"html\";\n\n      this.setContent(slide, this.translate(slide, slide.opts.errorTpl));\n\n      if (slide.pos === this.currPos) {\n        this.isAnimating = false;\n      }\n    },\n\n    // Show loading icon inside the slide\n    // ==================================\n\n    showLoading: function(slide) {\n      var self = this;\n\n      slide = slide || self.current;\n\n      if (slide && !slide.$spinner) {\n        slide.$spinner = $(self.translate(self, self.opts.spinnerTpl)).appendTo(slide.$slide);\n      }\n    },\n\n    // Remove loading icon from the slide\n    // ==================================\n\n    hideLoading: function(slide) {\n      var self = this;\n\n      slide = slide || self.current;\n\n      if (slide && slide.$spinner) {\n        slide.$spinner.remove();\n\n        delete slide.$spinner;\n      }\n    },\n\n    // Adjustments after slide content has been loaded\n    // ===============================================\n\n    afterLoad: function(slide) {\n      var self = this;\n\n      if (self.isClosing) {\n        return;\n      }\n\n      slide.isLoading = false;\n      slide.isLoaded = true;\n\n      self.trigger(\"afterLoad\", slide);\n\n      self.hideLoading(slide);\n\n      if (slide.pos === self.currPos) {\n        self.updateCursor();\n      }\n\n      if (slide.opts.smallBtn && (!slide.$smallBtn || !slide.$smallBtn.length)) {\n        slide.$smallBtn = $(self.translate(slide, slide.opts.btnTpl.smallBtn)).prependTo(slide.$content);\n      }\n\n      if (slide.opts.protect && slide.$content && !slide.hasError) {\n        // Disable right click\n        slide.$content.on(\"contextmenu.fb\", function(e) {\n          if (e.button == 2) {\n            e.preventDefault();\n          }\n\n          return true;\n        });\n\n        // Add fake element on top of the image\n        // This makes a bit harder for user to select image\n        if (slide.type === \"image\") {\n          $('<div class=\"fancybox-spaceball\"></div>').appendTo(slide.$content);\n        }\n      }\n\n      self.revealContent(slide);\n    },\n\n    // Make content visible\n    // This method is called right after content has been loaded or\n    // user navigates gallery and transition should start\n    // ============================================================\n\n    revealContent: function(slide) {\n      var self = this,\n        $slide = slide.$slide,\n        end = false,\n        start = false,\n        effect,\n        effectClassName,\n        duration,\n        opacity;\n\n      effect = slide.opts[self.firstRun ? \"animationEffect\" : \"transitionEffect\"];\n      duration = slide.opts[self.firstRun ? \"animationDuration\" : \"transitionDuration\"];\n\n      duration = parseInt(slide.forcedDuration === undefined ? duration : slide.forcedDuration, 10);\n\n      // Do not animate if revealing the same slide\n      if (slide.pos === self.currPos) {\n        if (slide.isComplete) {\n          effect = false;\n        } else {\n          self.isAnimating = true;\n        }\n      }\n\n      if (slide.isMoved || slide.pos !== self.currPos || !duration) {\n        effect = false;\n      }\n\n      // Check if can zoom\n      if (effect === \"zoom\") {\n        if (slide.pos === self.currPos && duration && slide.type === \"image\" && !slide.hasError && (start = self.getThumbPos(slide))) {\n          end = self.getFitPos(slide);\n        } else {\n          effect = \"fade\";\n        }\n      }\n\n      // Zoom animation\n      // ==============\n      if (effect === \"zoom\") {\n        end.scaleX = end.width / start.width;\n        end.scaleY = end.height / start.height;\n\n        // Check if we need to animate opacity\n        opacity = slide.opts.zoomOpacity;\n\n        if (opacity == \"auto\") {\n          opacity = Math.abs(slide.width / slide.height - start.width / start.height) > 0.1;\n        }\n\n        if (opacity) {\n          start.opacity = 0.1;\n          end.opacity = 1;\n        }\n\n        // Draw image at start position\n        $.fancybox.setTranslate(slide.$content.removeClass(\"fancybox-is-hidden\"), start);\n\n        forceRedraw(slide.$content);\n\n        // Start animation\n        $.fancybox.animate(slide.$content, end, duration, function() {\n          self.isAnimating = false;\n\n          self.complete();\n        });\n\n        return;\n      }\n\n      self.updateSlide(slide);\n\n      // Simply show content\n      // ===================\n\n      if (!effect) {\n        forceRedraw($slide);\n\n        slide.$content.removeClass(\"fancybox-is-hidden\");\n\n        if (slide.pos === self.currPos) {\n          self.complete();\n        }\n\n        return;\n      }\n\n      $.fancybox.stop($slide);\n\n      effectClassName = \"fancybox-animated fancybox-slide--\" + (slide.pos >= self.prevPos ? \"next\" : \"previous\") + \" fancybox-fx-\" + effect;\n\n      $slide\n        .removeAttr(\"style\")\n        .removeClass(\"fancybox-slide--current fancybox-slide--next fancybox-slide--previous\")\n        .addClass(effectClassName);\n\n      slide.$content.removeClass(\"fancybox-is-hidden\");\n\n      // Force reflow for CSS3 transitions\n      forceRedraw($slide);\n\n      $.fancybox.animate(\n        $slide,\n        \"fancybox-slide--current\",\n        duration,\n        function(e) {\n          $slide.removeClass(effectClassName).removeAttr(\"style\");\n\n          if (slide.pos === self.currPos) {\n            self.complete();\n          }\n        },\n        true\n      );\n    },\n\n    // Check if we can and have to zoom from thumbnail\n    //================================================\n\n    getThumbPos: function(slide) {\n      var self = this,\n        rez = false,\n        $thumb = slide.opts.$thumb,\n        thumbPos = $thumb && $thumb.length && $thumb[0].ownerDocument === document ? $thumb.offset() : 0,\n        slidePos;\n\n      // Check if element is inside the viewport by at least 1 pixel\n      var isElementVisible = function($el) {\n        var element = $el[0],\n          elementRect = element.getBoundingClientRect(),\n          parentRects = [],\n          visibleInAllParents;\n\n        while (element.parentElement !== null) {\n          if ($(element.parentElement).css(\"overflow\") === \"hidden\" || $(element.parentElement).css(\"overflow\") === \"auto\") {\n            parentRects.push(element.parentElement.getBoundingClientRect());\n          }\n\n          element = element.parentElement;\n        }\n\n        visibleInAllParents = parentRects.every(function(parentRect) {\n          var visiblePixelX = Math.min(elementRect.right, parentRect.right) - Math.max(elementRect.left, parentRect.left);\n          var visiblePixelY = Math.min(elementRect.bottom, parentRect.bottom) - Math.max(elementRect.top, parentRect.top);\n\n          return visiblePixelX > 0 && visiblePixelY > 0;\n        });\n\n        return (\n          visibleInAllParents &&\n          elementRect.bottom > 0 &&\n          elementRect.right > 0 &&\n          elementRect.left < $(window).width() &&\n          elementRect.top < $(window).height()\n        );\n      };\n\n      if (thumbPos && isElementVisible($thumb)) {\n        slidePos = self.$refs.stage.offset();\n\n        rez = {\n          top: thumbPos.top - slidePos.top + parseFloat($thumb.css(\"border-top-width\") || 0),\n          left: thumbPos.left - slidePos.left + parseFloat($thumb.css(\"border-left-width\") || 0),\n          width: $thumb.width(),\n          height: $thumb.height(),\n          scaleX: 1,\n          scaleY: 1\n        };\n      }\n\n      return rez;\n    },\n\n    // Final adjustments after current gallery item is moved to position\n    // and it`s content is loaded\n    // ==================================================================\n\n    complete: function() {\n      var self = this,\n        current = self.current,\n        slides = {};\n\n      if (current.isMoved || !current.isLoaded) {\n        return;\n      }\n\n      if (!current.isComplete) {\n        current.isComplete = true;\n\n        current.$slide.siblings().trigger(\"onReset\");\n\n        self.preload(\"inline\");\n\n        // Trigger any CSS3 transiton inside the slide\n        forceRedraw(current.$slide);\n\n        current.$slide.addClass(\"fancybox-slide--complete\");\n\n        // Remove unnecessary slides\n        $.each(self.slides, function(key, slide) {\n          if (slide.pos >= self.currPos - 1 && slide.pos <= self.currPos + 1) {\n            slides[slide.pos] = slide;\n          } else if (slide) {\n            $.fancybox.stop(slide.$slide);\n\n            slide.$slide.off().remove();\n          }\n        });\n\n        self.slides = slides;\n      }\n\n      self.isAnimating = false;\n\n      self.updateCursor();\n\n      self.trigger(\"afterShow\");\n\n      // Play first html5 video/audio\n      current.$slide\n        .find(\"video,audio\")\n        .filter(\":visible:first\")\n        .trigger(\"play\");\n\n      // Try to focus on the first focusable element\n      if (\n        $(document.activeElement).is(\"[disabled]\") ||\n        (current.opts.autoFocus && !(current.type == \"image\" || current.type === \"iframe\"))\n      ) {\n        self.focus();\n      }\n    },\n\n    // Preload next and previous slides\n    // ================================\n\n    preload: function(type) {\n      var self = this,\n        next = self.slides[self.currPos + 1],\n        prev = self.slides[self.currPos - 1];\n\n      if (next && next.type === type) {\n        self.loadSlide(next);\n      }\n\n      if (prev && prev.type === type) {\n        self.loadSlide(prev);\n      }\n    },\n\n    // Try to find and focus on the first focusable element\n    // ====================================================\n\n    focus: function() {\n      var current = this.current,\n        $el;\n\n      if (this.isClosing) {\n        return;\n      }\n\n      if (current && current.isComplete && current.$content) {\n        // Look for first input with autofocus attribute\n        $el = current.$content.find(\"input[autofocus]:enabled:visible:first\");\n\n        if (!$el.length) {\n          $el = current.$content.find(\"button,:input,[tabindex],a\").filter(\":enabled:visible:first\");\n        }\n\n        $el = $el && $el.length ? $el : current.$content;\n\n        $el.trigger(\"focus\");\n      }\n    },\n\n    // Activates current instance - brings container to the front and enables keyboard,\n    // notifies other instances about deactivating\n    // =================================================================================\n\n    activate: function() {\n      var self = this;\n\n      // Deactivate all instances\n      $(\".fancybox-container\").each(function() {\n        var instance = $(this).data(\"FancyBox\");\n\n        // Skip self and closing instances\n        if (instance && instance.id !== self.id && !instance.isClosing) {\n          instance.trigger(\"onDeactivate\");\n\n          instance.removeEvents();\n\n          instance.isVisible = false;\n        }\n      });\n\n      self.isVisible = true;\n\n      if (self.current || self.isIdle) {\n        self.update();\n\n        self.updateControls();\n      }\n\n      self.trigger(\"onActivate\");\n\n      self.addEvents();\n    },\n\n    // Start closing procedure\n    // This will start \"zoom-out\" animation if needed and clean everything up afterwards\n    // =================================================================================\n\n    close: function(e, d) {\n      var self = this,\n        current = self.current,\n        effect,\n        duration,\n        $content,\n        domRect,\n        opacity,\n        start,\n        end;\n\n      var done = function() {\n        self.cleanUp(e);\n      };\n\n      if (self.isClosing) {\n        return false;\n      }\n\n      self.isClosing = true;\n\n      // If beforeClose callback prevents closing, make sure content is centered\n      if (self.trigger(\"beforeClose\", e) === false) {\n        self.isClosing = false;\n\n        requestAFrame(function() {\n          self.update();\n        });\n\n        return false;\n      }\n\n      // Remove all events\n      // If there are multiple instances, they will be set again by \"activate\" method\n      self.removeEvents();\n\n      if (current.timouts) {\n        clearTimeout(current.timouts);\n      }\n\n      $content = current.$content;\n      effect = current.opts.animationEffect;\n      duration = $.isNumeric(d) ? d : effect ? current.opts.animationDuration : 0;\n\n      // Remove other slides\n      current.$slide\n        .off(transitionEnd)\n        .removeClass(\"fancybox-slide--complete fancybox-slide--next fancybox-slide--previous fancybox-animated\");\n\n      current.$slide\n        .siblings()\n        .trigger(\"onReset\")\n        .remove();\n\n      // Trigger animations\n      if (duration) {\n        self.$refs.container.removeClass(\"fancybox-is-open\").addClass(\"fancybox-is-closing\");\n      }\n\n      // Clean up\n      self.hideLoading(current);\n\n      self.hideControls();\n\n      self.updateCursor();\n\n      // Check if possible to zoom-out\n      if (\n        effect === \"zoom\" &&\n        !(e !== true && $content && duration && current.type === \"image\" && !current.hasError && (end = self.getThumbPos(current)))\n      ) {\n        effect = \"fade\";\n      }\n\n      if (effect === \"zoom\") {\n        $.fancybox.stop($content);\n\n        domRect = $.fancybox.getTranslate($content);\n\n        start = {\n          top: domRect.top,\n          left: domRect.left,\n          scaleX: domRect.width / end.width,\n          scaleY: domRect.height / end.height,\n          width: end.width,\n          height: end.height\n        };\n\n        // Check if we need to animate opacity\n        opacity = current.opts.zoomOpacity;\n\n        if (opacity == \"auto\") {\n          opacity = Math.abs(current.width / current.height - end.width / end.height) > 0.1;\n        }\n\n        if (opacity) {\n          end.opacity = 0;\n        }\n\n        $.fancybox.setTranslate($content, start);\n\n        forceRedraw($content);\n\n        $.fancybox.animate($content, end, duration, done);\n\n        return true;\n      }\n\n      if (effect && duration) {\n        // If skip animation\n        if (e === true) {\n          setTimeout(done, duration);\n        } else {\n          $.fancybox.animate(\n            current.$slide.removeClass(\"fancybox-slide--current\"),\n            \"fancybox-animated fancybox-slide--previous fancybox-fx-\" + effect,\n            duration,\n            done\n          );\n        }\n      } else {\n        done();\n      }\n\n      return true;\n    },\n\n    // Final adjustments after removing the instance\n    // =============================================\n\n    cleanUp: function(e) {\n      var self = this,\n        $body = $(\"body\"),\n        instance,\n        scrollTop;\n\n      self.current.$slide.trigger(\"onReset\");\n\n      self.$refs.container.empty().remove();\n\n      self.trigger(\"afterClose\", e);\n\n      // Place back focus\n      if (self.$lastFocus && !!self.current.opts.backFocus) {\n        self.$lastFocus.trigger(\"focus\");\n      }\n\n      self.current = null;\n\n      // Check if there are other instances\n      instance = $.fancybox.getInstance();\n\n      if (instance) {\n        instance.activate();\n      } else {\n        $body.removeClass(\"fancybox-active compensate-for-scrollbar\");\n\n        $(\"#fancybox-style-noscroll\").remove();\n      }\n    },\n\n    // Call callback and trigger an event\n    // ==================================\n\n    trigger: function(name, slide) {\n      var args = Array.prototype.slice.call(arguments, 1),\n        self = this,\n        obj = slide && slide.opts ? slide : self.current,\n        rez;\n\n      if (obj) {\n        args.unshift(obj);\n      } else {\n        obj = self;\n      }\n\n      args.unshift(self);\n\n      if ($.isFunction(obj.opts[name])) {\n        rez = obj.opts[name].apply(obj, args);\n      }\n\n      if (rez === false) {\n        return rez;\n      }\n\n      if (name === \"afterClose\" || !self.$refs) {\n        $D.trigger(name + \".fb\", args);\n      } else {\n        self.$refs.container.trigger(name + \".fb\", args);\n      }\n    },\n\n    // Update infobar values, navigation button states and reveal caption\n    // ==================================================================\n\n    updateControls: function(force) {\n      var self = this,\n        current = self.current,\n        index = current.index,\n        caption = current.opts.caption,\n        $container = self.$refs.container,\n        $caption = self.$refs.caption;\n\n      // Recalculate content dimensions\n      current.$slide.trigger(\"refresh\");\n\n      self.$caption = caption && caption.length ? $caption.html(caption) : null;\n\n      if (!self.isHiddenControls && !self.isIdle) {\n        self.showControls();\n      }\n\n      // Update info and navigation elements\n      $container.find(\"[data-fancybox-count]\").html(self.group.length);\n      $container.find(\"[data-fancybox-index]\").html(index + 1);\n\n      $container.find(\"[data-fancybox-prev]\").toggleClass(\"disabled\", !current.opts.loop && index <= 0);\n      $container.find(\"[data-fancybox-next]\").toggleClass(\"disabled\", !current.opts.loop && index >= self.group.length - 1);\n\n      if (current.type === \"image\") {\n        // Re-enable buttons; update download button source\n        $container\n          .find(\"[data-fancybox-zoom]\")\n          .show()\n          .end()\n          .find(\"[data-fancybox-download]\")\n          .attr(\"href\", current.opts.image.src || current.src)\n          .show();\n      } else if (current.opts.toolbar) {\n        $container.find(\"[data-fancybox-download],[data-fancybox-zoom]\").hide();\n      }\n    },\n\n    // Hide toolbar and caption\n    // ========================\n\n    hideControls: function() {\n      this.isHiddenControls = true;\n\n      this.$refs.container.removeClass(\"fancybox-show-infobar fancybox-show-toolbar fancybox-show-caption fancybox-show-nav\");\n    },\n\n    showControls: function() {\n      var self = this,\n        opts = self.current ? self.current.opts : self.opts,\n        $container = self.$refs.container;\n\n      self.isHiddenControls = false;\n      self.idleSecondsCounter = 0;\n\n      $container\n        .toggleClass(\"fancybox-show-toolbar\", !!(opts.toolbar && opts.buttons))\n        .toggleClass(\"fancybox-show-infobar\", !!(opts.infobar && self.group.length > 1))\n        .toggleClass(\"fancybox-show-nav\", !!(opts.arrows && self.group.length > 1))\n        .toggleClass(\"fancybox-is-modal\", !!opts.modal);\n\n      if (self.$caption) {\n        $container.addClass(\"fancybox-show-caption \");\n      } else {\n        $container.removeClass(\"fancybox-show-caption\");\n      }\n    },\n\n    // Toggle toolbar and caption\n    // ==========================\n\n    toggleControls: function() {\n      if (this.isHiddenControls) {\n        this.showControls();\n      } else {\n        this.hideControls();\n      }\n    }\n  });\n\n  $.fancybox = {\n    version: \"3.3.5\",\n    defaults: defaults,\n\n    // Get current instance and execute a command.\n    //\n    // Examples of usage:\n    //\n    //   $instance = $.fancybox.getInstance();\n    //   $.fancybox.getInstance().jumpTo( 1 );\n    //   $.fancybox.getInstance( 'jumpTo', 1 );\n    //   $.fancybox.getInstance( function() {\n    //       console.info( this.currIndex );\n    //   });\n    // ======================================================\n\n    getInstance: function(command) {\n      var instance = $('.fancybox-container:not(\".fancybox-is-closing\"):last').data(\"FancyBox\"),\n        args = Array.prototype.slice.call(arguments, 1);\n\n      if (instance instanceof FancyBox) {\n        if ($.type(command) === \"string\") {\n          instance[command].apply(instance, args);\n        } else if ($.type(command) === \"function\") {\n          command.apply(instance, args);\n        }\n\n        return instance;\n      }\n\n      return false;\n    },\n\n    // Create new instance\n    // ===================\n\n    open: function(items, opts, index) {\n      return new FancyBox(items, opts, index);\n    },\n\n    // Close current or all instances\n    // ==============================\n\n    close: function(all) {\n      var instance = this.getInstance();\n\n      if (instance) {\n        instance.close();\n\n        // Try to find and close next instance\n\n        if (all === true) {\n          this.close();\n        }\n      }\n    },\n\n    // Close all instances and unbind all events\n    // =========================================\n\n    destroy: function() {\n      this.close(true);\n\n      $D.add(\"body\").off(\"click.fb-start\", \"**\");\n    },\n\n    // Try to detect mobile devices\n    // ============================\n\n    isMobile:\n      document.createTouch !== undefined && /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent),\n\n    // Detect if 'translate3d' support is available\n    // ============================================\n\n    use3d: (function() {\n      var div = document.createElement(\"div\");\n\n      return (\n        window.getComputedStyle &&\n        window.getComputedStyle(div) &&\n        window.getComputedStyle(div).getPropertyValue(\"transform\") &&\n        !(document.documentMode && document.documentMode < 11)\n      );\n    })(),\n\n    // Helper function to get current visual state of an element\n    // returns array[ top, left, horizontal-scale, vertical-scale, opacity ]\n    // =====================================================================\n\n    getTranslate: function($el) {\n      var domRect;\n\n      if (!$el || !$el.length) {\n        return false;\n      }\n\n      domRect = $el[0].getBoundingClientRect();\n\n      return {\n        top: domRect.top || 0,\n        left: domRect.left || 0,\n        width: domRect.width,\n        height: domRect.height,\n        opacity: parseFloat($el.css(\"opacity\"))\n      };\n    },\n\n    // Shortcut for setting \"translate3d\" properties for element\n    // Can set be used to set opacity, too\n    // ========================================================\n\n    setTranslate: function($el, props) {\n      var str = \"\",\n        css = {};\n\n      if (!$el || !props) {\n        return;\n      }\n\n      if (props.left !== undefined || props.top !== undefined) {\n        str =\n          (props.left === undefined ? $el.position().left : props.left) +\n          \"px, \" +\n          (props.top === undefined ? $el.position().top : props.top) +\n          \"px\";\n\n        if (this.use3d) {\n          str = \"translate3d(\" + str + \", 0px)\";\n        } else {\n          str = \"translate(\" + str + \")\";\n        }\n      }\n\n      if (props.scaleX !== undefined && props.scaleY !== undefined) {\n        str = (str.length ? str + \" \" : \"\") + \"scale(\" + props.scaleX + \", \" + props.scaleY + \")\";\n      }\n\n      if (str.length) {\n        css.transform = str;\n      }\n\n      if (props.opacity !== undefined) {\n        css.opacity = props.opacity;\n      }\n\n      if (props.width !== undefined) {\n        css.width = props.width;\n      }\n\n      if (props.height !== undefined) {\n        css.height = props.height;\n      }\n\n      return $el.css(css);\n    },\n\n    // Simple CSS transition handler\n    // =============================\n\n    animate: function($el, to, duration, callback, leaveAnimationName) {\n      var final = false;\n\n      if ($.isFunction(duration)) {\n        callback = duration;\n        duration = null;\n      }\n\n      if (!$.isPlainObject(to)) {\n        $el.removeAttr(\"style\");\n      }\n\n      $.fancybox.stop($el);\n\n      $el.on(transitionEnd, function(e) {\n        // Skip events from child elements and z-index change\n        if (e && e.originalEvent && (!$el.is(e.originalEvent.target) || e.originalEvent.propertyName == \"z-index\")) {\n          return;\n        }\n\n        $.fancybox.stop($el);\n\n        if (final) {\n          $.fancybox.setTranslate($el, final);\n        }\n\n        if ($.isPlainObject(to)) {\n          if (leaveAnimationName === false) {\n            $el.removeAttr(\"style\");\n          }\n        } else if (leaveAnimationName !== true) {\n          $el.removeClass(to);\n        }\n\n        if ($.isFunction(callback)) {\n          callback(e);\n        }\n      });\n\n      if ($.isNumeric(duration)) {\n        $el.css(\"transition-duration\", duration + \"ms\");\n      }\n\n      // Start animation by changing CSS properties or class name\n      if ($.isPlainObject(to)) {\n        if (to.scaleX !== undefined && to.scaleY !== undefined) {\n          final = $.extend({}, to, {\n            width: $el.width() * to.scaleX,\n            height: $el.height() * to.scaleY,\n            scaleX: 1,\n            scaleY: 1\n          });\n\n          delete to.width;\n          delete to.height;\n\n          if ($el.parent().hasClass(\"fancybox-slide--image\")) {\n            $el.parent().addClass(\"fancybox-is-scaling\");\n          }\n        }\n\n        $.fancybox.setTranslate($el, to);\n      } else {\n        $el.addClass(to);\n      }\n\n      // Make sure that `transitionend` callback gets fired\n      $el.data(\n        \"timer\",\n        setTimeout(function() {\n          $el.trigger(\"transitionend\");\n        }, duration + 16)\n      );\n    },\n\n    stop: function($el) {\n      if ($el && $el.length) {\n        clearTimeout($el.data(\"timer\"));\n\n        $el.off(\"transitionend\").css(\"transition-duration\", \"\");\n\n        $el.parent().removeClass(\"fancybox-is-scaling\");\n      }\n    }\n  };\n\n  // Default click handler for \"fancyboxed\" links\n  // ============================================\n\n  function _run(e, opts) {\n    var items = [],\n      index = 0,\n      $target,\n      value;\n\n    // Avoid opening multiple times\n    if (e && e.isDefaultPrevented()) {\n      return;\n    }\n\n    e.preventDefault();\n\n    opts = e && e.data ? e.data.options : opts || {};\n\n    $target = opts.$target || $(e.currentTarget);\n    value = $target.attr(\"data-fancybox\") || \"\";\n\n    // Get all related items and find index for clicked one\n    if (value) {\n      items = opts.selector ? $(opts.selector) : e.data ? e.data.items : [];\n      items = items.length ? items.filter('[data-fancybox=\"' + value + '\"]') : $('[data-fancybox=\"' + value + '\"]');\n\n      index = items.index($target);\n\n      // Sometimes current item can not be found (for example, if some script clones items)\n      if (index < 0) {\n        index = 0;\n      }\n    } else {\n      items = [$target];\n    }\n\n    $.fancybox.open(items, opts, index);\n  }\n\n  // Create a jQuery plugin\n  // ======================\n\n  $.fn.fancybox = function(options) {\n    var selector;\n\n    options = options || {};\n    selector = options.selector || false;\n\n    if (selector) {\n      // Use body element instead of document so it executes first\n      $(\"body\")\n        .off(\"click.fb-start\", selector)\n        .on(\"click.fb-start\", selector, {options: options}, _run);\n    } else {\n      this.off(\"click.fb-start\").on(\n        \"click.fb-start\",\n        {\n          items: this,\n          options: options\n        },\n        _run\n      );\n    }\n\n    return this;\n  };\n\n  // Self initializing plugin for all elements having `data-fancybox` attribute\n  // ==========================================================================\n\n  $D.on(\"click.fb-start\", \"[data-fancybox]\", _run);\n\n  // Enable \"trigger elements\"\n  // =========================\n\n  $D.on(\"click.fb-start\", \"[data-trigger]\", function(e) {\n    _run(e, {\n      $target: $('[data-fancybox=\"' + $(e.currentTarget).attr(\"data-trigger\") + '\"]').eq($(e.currentTarget).attr(\"data-index\") || 0),\n      $trigger: $(this)\n    });\n  });\n})(window, document, window.jQuery || jQuery);\n\n// ==========================================================================\n//\n// Media\n// Adds additional media type support\n//\n// ==========================================================================\n(function($) {\n  \"use strict\";\n\n  // Formats matching url to final form\n\n  var format = function(url, rez, params) {\n    if (!url) {\n      return;\n    }\n\n    params = params || \"\";\n\n    if ($.type(params) === \"object\") {\n      params = $.param(params, true);\n    }\n\n    $.each(rez, function(key, value) {\n      url = url.replace(\"$\" + key, value || \"\");\n    });\n\n    if (params.length) {\n      url += (url.indexOf(\"?\") > 0 ? \"&\" : \"?\") + params;\n    }\n\n    return url;\n  };\n\n  // Object containing properties for each media type\n\n  var defaults = {\n    youtube: {\n      matcher: /(youtube\\.com|youtu\\.be|youtube\\-nocookie\\.com)\\/(watch\\?(.*&)?v=|v\\/|u\\/|embed\\/?)?(videoseries\\?list=(.*)|[\\w-]{11}|\\?listType=(.*)&list=(.*))(.*)/i,\n      params: {\n        autoplay: 1,\n        autohide: 1,\n        fs: 1,\n        rel: 0,\n        hd: 1,\n        wmode: \"transparent\",\n        enablejsapi: 1,\n        html5: 1\n      },\n      paramPlace: 8,\n      type: \"iframe\",\n      url: \"//www.youtube.com/embed/$4\",\n      thumb: \"//img.youtube.com/vi/$4/hqdefault.jpg\"\n    },\n\n    vimeo: {\n      matcher: /^.+vimeo.com\\/(.*\\/)?([\\d]+)(.*)?/,\n      params: {\n        autoplay: 1,\n        hd: 1,\n        show_title: 1,\n        show_byline: 1,\n        show_portrait: 0,\n        fullscreen: 1,\n        api: 1\n      },\n      paramPlace: 3,\n      type: \"iframe\",\n      url: \"//player.vimeo.com/video/$2\"\n    },\n\n    instagram: {\n      matcher: /(instagr\\.am|instagram\\.com)\\/p\\/([a-zA-Z0-9_\\-]+)\\/?/i,\n      type: \"image\",\n      url: \"//$1/p/$2/media/?size=l\"\n    },\n\n    // Examples:\n    // http://maps.google.com/?ll=48.857995,2.294297&spn=0.007666,0.021136&t=m&z=16\n    // https://www.google.com/maps/@37.7852006,-122.4146355,14.65z\n    // https://www.google.com/maps/@52.2111123,2.9237542,6.61z?hl=en\n    // https://www.google.com/maps/place/Googleplex/@37.4220041,-122.0833494,17z/data=!4m5!3m4!1s0x0:0x6c296c66619367e0!8m2!3d37.4219998!4d-122.0840572\n    gmap_place: {\n      matcher: /(maps\\.)?google\\.([a-z]{2,3}(\\.[a-z]{2})?)\\/(((maps\\/(place\\/(.*)\\/)?\\@(.*),(\\d+.?\\d+?)z))|(\\?ll=))(.*)?/i,\n      type: \"iframe\",\n      url: function(rez) {\n        return (\n          \"//maps.google.\" +\n          rez[2] +\n          \"/?ll=\" +\n          (rez[9] ? rez[9] + \"&z=\" + Math.floor(rez[10]) + (rez[12] ? rez[12].replace(/^\\//, \"&\") : \"\") : rez[12] + \"\").replace(/\\?/, \"&\") +\n          \"&output=\" +\n          (rez[12] && rez[12].indexOf(\"layer=c\") > 0 ? \"svembed\" : \"embed\")\n        );\n      }\n    },\n\n    // Examples:\n    // https://www.google.com/maps/search/Empire+State+Building/\n    // https://www.google.com/maps/search/?api=1&query=centurylink+field\n    // https://www.google.com/maps/search/?api=1&query=47.5951518,-122.3316393\n    gmap_search: {\n      matcher: /(maps\\.)?google\\.([a-z]{2,3}(\\.[a-z]{2})?)\\/(maps\\/search\\/)(.*)/i,\n      type: \"iframe\",\n      url: function(rez) {\n        return \"//maps.google.\" + rez[2] + \"/maps?q=\" + rez[5].replace(\"query=\", \"q=\").replace(\"api=1\", \"\") + \"&output=embed\";\n      }\n    }\n  };\n\n  $(document).on(\"objectNeedsType.fb\", function(e, instance, item) {\n    var url = item.src || \"\",\n      type = false,\n      media,\n      thumb,\n      rez,\n      params,\n      urlParams,\n      paramObj,\n      provider;\n\n    media = $.extend(true, {}, defaults, item.opts.media);\n\n    // Look for any matching media type\n    $.each(media, function(providerName, providerOpts) {\n      rez = url.match(providerOpts.matcher);\n\n      if (!rez) {\n        return;\n      }\n\n      type = providerOpts.type;\n      provider = providerName;\n      paramObj = {};\n\n      if (providerOpts.paramPlace && rez[providerOpts.paramPlace]) {\n        urlParams = rez[providerOpts.paramPlace];\n\n        if (urlParams[0] == \"?\") {\n          urlParams = urlParams.substring(1);\n        }\n\n        urlParams = urlParams.split(\"&\");\n\n        for (var m = 0; m < urlParams.length; ++m) {\n          var p = urlParams[m].split(\"=\", 2);\n\n          if (p.length == 2) {\n            paramObj[p[0]] = decodeURIComponent(p[1].replace(/\\+/g, \" \"));\n          }\n        }\n      }\n\n      params = $.extend(true, {}, providerOpts.params, item.opts[providerName], paramObj);\n\n      url =\n        $.type(providerOpts.url) === \"function\" ? providerOpts.url.call(this, rez, params, item) : format(providerOpts.url, rez, params);\n\n      thumb =\n        $.type(providerOpts.thumb) === \"function\" ? providerOpts.thumb.call(this, rez, params, item) : format(providerOpts.thumb, rez);\n\n      if (providerName === \"youtube\") {\n        url = url.replace(/&t=((\\d+)m)?(\\d+)s/, function(match, p1, m, s) {\n          return \"&start=\" + ((m ? parseInt(m, 10) * 60 : 0) + parseInt(s, 10));\n        });\n      } else if (providerName === \"vimeo\") {\n        url = url.replace(\"&%23\", \"#\");\n      }\n\n      return false;\n    });\n\n    // If it is found, then change content type and update the url\n\n    if (type) {\n      if (!item.opts.thumb && !(item.opts.$thumb && item.opts.$thumb.length)) {\n        item.opts.thumb = thumb;\n      }\n\n      if (type === \"iframe\") {\n        item.opts = $.extend(true, item.opts, {\n          iframe: {\n            preload: false,\n            attr: {\n              scrolling: \"no\"\n            }\n          }\n        });\n      }\n\n      $.extend(item, {\n        type: type,\n        src: url,\n        origSrc: item.src,\n        contentSource: provider,\n        contentType: type === \"image\" ? \"image\" : provider == \"gmap_place\" || provider == \"gmap_search\" ? \"map\" : \"video\"\n      });\n    } else if (url) {\n      item.type = item.opts.defaultType;\n    }\n  });\n})(window.jQuery || jQuery);\n\n// ==========================================================================\n//\n// Guestures\n// Adds touch guestures, handles click and tap events\n//\n// ==========================================================================\n(function(window, document, $) {\n  \"use strict\";\n\n  var requestAFrame = (function() {\n    return (\n      window.requestAnimationFrame ||\n      window.webkitRequestAnimationFrame ||\n      window.mozRequestAnimationFrame ||\n      window.oRequestAnimationFrame ||\n      // if all else fails, use setTimeout\n      function(callback) {\n        return window.setTimeout(callback, 1000 / 60);\n      }\n    );\n  })();\n\n  var cancelAFrame = (function() {\n    return (\n      window.cancelAnimationFrame ||\n      window.webkitCancelAnimationFrame ||\n      window.mozCancelAnimationFrame ||\n      window.oCancelAnimationFrame ||\n      function(id) {\n        window.clearTimeout(id);\n      }\n    );\n  })();\n\n  var getPointerXY = function(e) {\n    var result = [];\n\n    e = e.originalEvent || e || window.e;\n    e = e.touches && e.touches.length ? e.touches : e.changedTouches && e.changedTouches.length ? e.changedTouches : [e];\n\n    for (var key in e) {\n      if (e[key].pageX) {\n        result.push({\n          x: e[key].pageX,\n          y: e[key].pageY\n        });\n      } else if (e[key].clientX) {\n        result.push({\n          x: e[key].clientX,\n          y: e[key].clientY\n        });\n      }\n    }\n\n    return result;\n  };\n\n  var distance = function(point2, point1, what) {\n    if (!point1 || !point2) {\n      return 0;\n    }\n\n    if (what === \"x\") {\n      return point2.x - point1.x;\n    } else if (what === \"y\") {\n      return point2.y - point1.y;\n    }\n\n    return Math.sqrt(Math.pow(point2.x - point1.x, 2) + Math.pow(point2.y - point1.y, 2));\n  };\n\n  var isClickable = function($el) {\n    if (\n      $el.is('a,area,button,[role=\"button\"],input,label,select,summary,textarea,video,audio') ||\n      $.isFunction($el.get(0).onclick) ||\n      $el.data(\"selectable\")\n    ) {\n      return true;\n    }\n\n    // Check for attributes like data-fancybox-next or data-fancybox-close\n    for (var i = 0, atts = $el[0].attributes, n = atts.length; i < n; i++) {\n      if (atts[i].nodeName.substr(0, 14) === \"data-fancybox-\") {\n        return true;\n      }\n    }\n\n    return false;\n  };\n\n  var hasScrollbars = function(el) {\n    var overflowY = window.getComputedStyle(el)[\"overflow-y\"],\n      overflowX = window.getComputedStyle(el)[\"overflow-x\"],\n      vertical = (overflowY === \"scroll\" || overflowY === \"auto\") && el.scrollHeight > el.clientHeight,\n      horizontal = (overflowX === \"scroll\" || overflowX === \"auto\") && el.scrollWidth > el.clientWidth;\n\n    return vertical || horizontal;\n  };\n\n  var isScrollable = function($el) {\n    var rez = false;\n\n    while (true) {\n      rez = hasScrollbars($el.get(0));\n\n      if (rez) {\n        break;\n      }\n\n      $el = $el.parent();\n\n      if (!$el.length || $el.hasClass(\"fancybox-stage\") || $el.is(\"body\")) {\n        break;\n      }\n    }\n\n    return rez;\n  };\n\n  var Guestures = function(instance) {\n    var self = this;\n\n    self.instance = instance;\n\n    self.$bg = instance.$refs.bg;\n    self.$stage = instance.$refs.stage;\n    self.$container = instance.$refs.container;\n\n    self.destroy();\n\n    self.$container.on(\"touchstart.fb.touch mousedown.fb.touch\", $.proxy(self, \"ontouchstart\"));\n  };\n\n  Guestures.prototype.destroy = function() {\n    this.$container.off(\".fb.touch\");\n  };\n\n  Guestures.prototype.ontouchstart = function(e) {\n    var self = this,\n      $target = $(e.target),\n      instance = self.instance,\n      current = instance.current,\n      $content = current.$content,\n      isTouchDevice = e.type == \"touchstart\";\n\n    // Do not respond to both (touch and mouse) events\n    if (isTouchDevice) {\n      self.$container.off(\"mousedown.fb.touch\");\n    }\n\n    // Ignore right click\n    if (e.originalEvent && e.originalEvent.button == 2) {\n      return;\n    }\n\n    // Ignore taping on links, buttons, input elements\n    if (!$target.length || isClickable($target) || isClickable($target.parent())) {\n      return;\n    }\n\n    // Ignore clicks on the scrollbar\n    if (!$target.is(\"img\") && e.originalEvent.clientX > $target[0].clientWidth + $target.offset().left) {\n      return;\n    }\n\n    // Ignore clicks while zooming or closing\n    if (!current || instance.isAnimating || instance.isClosing) {\n      e.stopPropagation();\n      e.preventDefault();\n\n      return;\n    }\n\n    self.realPoints = self.startPoints = getPointerXY(e);\n\n    if (!self.startPoints.length) {\n      return;\n    }\n\n    e.stopPropagation();\n\n    self.startEvent = e;\n\n    self.canTap = true;\n    self.$target = $target;\n    self.$content = $content;\n    self.opts = current.opts.touch;\n\n    self.isPanning = false;\n    self.isSwiping = false;\n    self.isZooming = false;\n    self.isScrolling = false;\n\n    self.startTime = new Date().getTime();\n    self.distanceX = self.distanceY = self.distance = 0;\n\n    self.canvasWidth = Math.round(current.$slide[0].clientWidth);\n    self.canvasHeight = Math.round(current.$slide[0].clientHeight);\n\n    self.contentLastPos = null;\n    self.contentStartPos = $.fancybox.getTranslate(self.$content) || {top: 0, left: 0};\n    self.sliderStartPos = self.sliderLastPos || $.fancybox.getTranslate(current.$slide);\n\n    // Since position will be absolute, but we need to make it relative to the stage\n    self.stagePos = $.fancybox.getTranslate(instance.$refs.stage);\n\n    self.sliderStartPos.top -= self.stagePos.top;\n    self.sliderStartPos.left -= self.stagePos.left;\n\n    self.contentStartPos.top -= self.stagePos.top;\n    self.contentStartPos.left -= self.stagePos.left;\n\n    $(document)\n      .off(\".fb.touch\")\n      .on(isTouchDevice ? \"touchend.fb.touch touchcancel.fb.touch\" : \"mouseup.fb.touch mouseleave.fb.touch\", $.proxy(self, \"ontouchend\"))\n      .on(isTouchDevice ? \"touchmove.fb.touch\" : \"mousemove.fb.touch\", $.proxy(self, \"ontouchmove\"));\n\n    if ($.fancybox.isMobile) {\n      document.addEventListener(\"scroll\", self.onscroll, true);\n    }\n\n    if (!(self.opts || instance.canPan()) || !($target.is(self.$stage) || self.$stage.find($target).length)) {\n      if ($target.is(\".fancybox-image\")) {\n        e.preventDefault();\n      }\n\n      return;\n    }\n\n    if (!($.fancybox.isMobile && (isScrollable($target) || isScrollable($target.parent())))) {\n      e.preventDefault();\n    }\n\n    if (self.startPoints.length === 1 || current.hasError) {\n      if (self.instance.canPan()) {\n        $.fancybox.stop(self.$content);\n\n        self.$content.css(\"transition-duration\", \"\");\n\n        self.isPanning = true;\n      } else {\n        self.isSwiping = true;\n      }\n\n      self.$container.addClass(\"fancybox-controls--isGrabbing\");\n    }\n\n    if (self.startPoints.length === 2 && current.type === \"image\" && (current.isLoaded || current.$ghost)) {\n      self.canTap = false;\n      self.isSwiping = false;\n      self.isPanning = false;\n\n      self.isZooming = true;\n\n      $.fancybox.stop(self.$content);\n\n      self.$content.css(\"transition-duration\", \"\");\n\n      self.centerPointStartX = (self.startPoints[0].x + self.startPoints[1].x) * 0.5 - $(window).scrollLeft();\n      self.centerPointStartY = (self.startPoints[0].y + self.startPoints[1].y) * 0.5 - $(window).scrollTop();\n\n      self.percentageOfImageAtPinchPointX = (self.centerPointStartX - self.contentStartPos.left) / self.contentStartPos.width;\n      self.percentageOfImageAtPinchPointY = (self.centerPointStartY - self.contentStartPos.top) / self.contentStartPos.height;\n\n      self.startDistanceBetweenFingers = distance(self.startPoints[0], self.startPoints[1]);\n    }\n  };\n\n  Guestures.prototype.onscroll = function(e) {\n    var self = this;\n\n    self.isScrolling = true;\n\n    document.removeEventListener(\"scroll\", self.onscroll, true);\n  };\n\n  Guestures.prototype.ontouchmove = function(e) {\n    var self = this,\n      $target = $(e.target);\n\n    // Make sure user has not released over iframe or disabled element\n    if (e.originalEvent.buttons !== undefined && e.originalEvent.buttons === 0) {\n      self.ontouchend(e);\n      return;\n    }\n\n    if (self.isScrolling || !($target.is(self.$stage) || self.$stage.find($target).length)) {\n      self.canTap = false;\n\n      return;\n    }\n\n    self.newPoints = getPointerXY(e);\n\n    if (!(self.opts || self.instance.canPan()) || !self.newPoints.length || !self.newPoints.length) {\n      return;\n    }\n\n    if (!(self.isSwiping && self.isSwiping === true)) {\n      e.preventDefault();\n    }\n\n    self.distanceX = distance(self.newPoints[0], self.startPoints[0], \"x\");\n    self.distanceY = distance(self.newPoints[0], self.startPoints[0], \"y\");\n\n    self.distance = distance(self.newPoints[0], self.startPoints[0]);\n\n    // Skip false ontouchmove events (Chrome)\n    if (self.distance > 0) {\n      if (self.isSwiping) {\n        self.onSwipe(e);\n      } else if (self.isPanning) {\n        self.onPan();\n      } else if (self.isZooming) {\n        self.onZoom();\n      }\n    }\n  };\n\n  Guestures.prototype.onSwipe = function(e) {\n    var self = this,\n      swiping = self.isSwiping,\n      left = self.sliderStartPos.left || 0,\n      angle;\n\n    // If direction is not yet determined\n    if (swiping === true) {\n      // We need at least 10px distance to correctly calculate an angle\n      if (Math.abs(self.distance) > 10) {\n        self.canTap = false;\n\n        if (self.instance.group.length < 2 && self.opts.vertical) {\n          self.isSwiping = \"y\";\n        } else if (self.instance.isDragging || self.opts.vertical === false || (self.opts.vertical === \"auto\" && $(window).width() > 800)) {\n          self.isSwiping = \"x\";\n        } else {\n          angle = Math.abs(Math.atan2(self.distanceY, self.distanceX) * 180 / Math.PI);\n\n          self.isSwiping = angle > 45 && angle < 135 ? \"y\" : \"x\";\n        }\n\n        self.canTap = false;\n\n        if (self.isSwiping === \"y\" && $.fancybox.isMobile && (isScrollable(self.$target) || isScrollable(self.$target.parent()))) {\n          self.isScrolling = true;\n\n          return;\n        }\n\n        self.instance.isDragging = self.isSwiping;\n\n        // Reset points to avoid jumping, because we dropped first swipes to calculate the angle\n        self.startPoints = self.newPoints;\n\n        $.each(self.instance.slides, function(index, slide) {\n          $.fancybox.stop(slide.$slide);\n\n          slide.$slide.css(\"transition-duration\", \"\");\n\n          slide.inTransition = false;\n\n          if (slide.pos === self.instance.current.pos) {\n            self.sliderStartPos.left = $.fancybox.getTranslate(slide.$slide).left - $.fancybox.getTranslate(self.instance.$refs.stage).left;\n          }\n        });\n\n        // Stop slideshow\n        if (self.instance.SlideShow && self.instance.SlideShow.isActive) {\n          self.instance.SlideShow.stop();\n        }\n      }\n\n      return;\n    }\n\n    // Sticky edges\n    if (swiping == \"x\") {\n      if (\n        self.distanceX > 0 &&\n        (self.instance.group.length < 2 || (self.instance.current.index === 0 && !self.instance.current.opts.loop))\n      ) {\n        left = left + Math.pow(self.distanceX, 0.8);\n      } else if (\n        self.distanceX < 0 &&\n        (self.instance.group.length < 2 ||\n          (self.instance.current.index === self.instance.group.length - 1 && !self.instance.current.opts.loop))\n      ) {\n        left = left - Math.pow(-self.distanceX, 0.8);\n      } else {\n        left = left + self.distanceX;\n      }\n    }\n\n    self.sliderLastPos = {\n      top: swiping == \"x\" ? 0 : self.sliderStartPos.top + self.distanceY,\n      left: left\n    };\n\n    if (self.requestId) {\n      cancelAFrame(self.requestId);\n\n      self.requestId = null;\n    }\n\n    self.requestId = requestAFrame(function() {\n      if (self.sliderLastPos) {\n        $.each(self.instance.slides, function(index, slide) {\n          var pos = slide.pos - self.instance.currPos;\n\n          $.fancybox.setTranslate(slide.$slide, {\n            top: self.sliderLastPos.top,\n            left: self.sliderLastPos.left + pos * self.canvasWidth + pos * slide.opts.gutter\n          });\n        });\n\n        self.$container.addClass(\"fancybox-is-sliding\");\n      }\n    });\n  };\n\n  Guestures.prototype.onPan = function() {\n    var self = this;\n\n    // Prevent accidental movement (sometimes, when tapping casually, finger can move a bit)\n    if (distance(self.newPoints[0], self.realPoints[0]) < ($.fancybox.isMobile ? 10 : 5)) {\n      self.startPoints = self.newPoints;\n      return;\n    }\n\n    self.canTap = false;\n\n    self.contentLastPos = self.limitMovement();\n\n    if (self.requestId) {\n      cancelAFrame(self.requestId);\n\n      self.requestId = null;\n    }\n\n    self.requestId = requestAFrame(function() {\n      $.fancybox.setTranslate(self.$content, self.contentLastPos);\n    });\n  };\n\n  // Make panning sticky to the edges\n  Guestures.prototype.limitMovement = function() {\n    var self = this;\n\n    var canvasWidth = self.canvasWidth;\n    var canvasHeight = self.canvasHeight;\n\n    var distanceX = self.distanceX;\n    var distanceY = self.distanceY;\n\n    var contentStartPos = self.contentStartPos;\n\n    var currentOffsetX = contentStartPos.left;\n    var currentOffsetY = contentStartPos.top;\n\n    var currentWidth = contentStartPos.width;\n    var currentHeight = contentStartPos.height;\n\n    var minTranslateX, minTranslateY, maxTranslateX, maxTranslateY, newOffsetX, newOffsetY;\n\n    if (currentWidth > canvasWidth) {\n      newOffsetX = currentOffsetX + distanceX;\n    } else {\n      newOffsetX = currentOffsetX;\n    }\n\n    newOffsetY = currentOffsetY + distanceY;\n\n    // Slow down proportionally to traveled distance\n    minTranslateX = Math.max(0, canvasWidth * 0.5 - currentWidth * 0.5);\n    minTranslateY = Math.max(0, canvasHeight * 0.5 - currentHeight * 0.5);\n\n    maxTranslateX = Math.min(canvasWidth - currentWidth, canvasWidth * 0.5 - currentWidth * 0.5);\n    maxTranslateY = Math.min(canvasHeight - currentHeight, canvasHeight * 0.5 - currentHeight * 0.5);\n\n    //   ->\n    if (distanceX > 0 && newOffsetX > minTranslateX) {\n      newOffsetX = minTranslateX - 1 + Math.pow(-minTranslateX + currentOffsetX + distanceX, 0.8) || 0;\n    }\n\n    //    <-\n    if (distanceX < 0 && newOffsetX < maxTranslateX) {\n      newOffsetX = maxTranslateX + 1 - Math.pow(maxTranslateX - currentOffsetX - distanceX, 0.8) || 0;\n    }\n\n    //   \\/\n    if (distanceY > 0 && newOffsetY > minTranslateY) {\n      newOffsetY = minTranslateY - 1 + Math.pow(-minTranslateY + currentOffsetY + distanceY, 0.8) || 0;\n    }\n\n    //   /\\\n    if (distanceY < 0 && newOffsetY < maxTranslateY) {\n      newOffsetY = maxTranslateY + 1 - Math.pow(maxTranslateY - currentOffsetY - distanceY, 0.8) || 0;\n    }\n\n    return {\n      top: newOffsetY,\n      left: newOffsetX\n    };\n  };\n\n  Guestures.prototype.limitPosition = function(newOffsetX, newOffsetY, newWidth, newHeight) {\n    var self = this;\n\n    var canvasWidth = self.canvasWidth;\n    var canvasHeight = self.canvasHeight;\n\n    if (newWidth > canvasWidth) {\n      newOffsetX = newOffsetX > 0 ? 0 : newOffsetX;\n      newOffsetX = newOffsetX < canvasWidth - newWidth ? canvasWidth - newWidth : newOffsetX;\n    } else {\n      // Center horizontally\n      newOffsetX = Math.max(0, canvasWidth / 2 - newWidth / 2);\n    }\n\n    if (newHeight > canvasHeight) {\n      newOffsetY = newOffsetY > 0 ? 0 : newOffsetY;\n      newOffsetY = newOffsetY < canvasHeight - newHeight ? canvasHeight - newHeight : newOffsetY;\n    } else {\n      // Center vertically\n      newOffsetY = Math.max(0, canvasHeight / 2 - newHeight / 2);\n    }\n\n    return {\n      top: newOffsetY,\n      left: newOffsetX\n    };\n  };\n\n  Guestures.prototype.onZoom = function() {\n    var self = this;\n\n    // Calculate current distance between points to get pinch ratio and new width and height\n    var contentStartPos = self.contentStartPos;\n\n    var currentWidth = contentStartPos.width;\n    var currentHeight = contentStartPos.height;\n\n    var currentOffsetX = contentStartPos.left;\n    var currentOffsetY = contentStartPos.top;\n\n    var endDistanceBetweenFingers = distance(self.newPoints[0], self.newPoints[1]);\n\n    var pinchRatio = endDistanceBetweenFingers / self.startDistanceBetweenFingers;\n\n    var newWidth = Math.floor(currentWidth * pinchRatio);\n    var newHeight = Math.floor(currentHeight * pinchRatio);\n\n    // This is the translation due to pinch-zooming\n    var translateFromZoomingX = (currentWidth - newWidth) * self.percentageOfImageAtPinchPointX;\n    var translateFromZoomingY = (currentHeight - newHeight) * self.percentageOfImageAtPinchPointY;\n\n    // Point between the two touches\n    var centerPointEndX = (self.newPoints[0].x + self.newPoints[1].x) / 2 - $(window).scrollLeft();\n    var centerPointEndY = (self.newPoints[0].y + self.newPoints[1].y) / 2 - $(window).scrollTop();\n\n    // And this is the translation due to translation of the centerpoint\n    // between the two fingers\n    var translateFromTranslatingX = centerPointEndX - self.centerPointStartX;\n    var translateFromTranslatingY = centerPointEndY - self.centerPointStartY;\n\n    // The new offset is the old/current one plus the total translation\n    var newOffsetX = currentOffsetX + (translateFromZoomingX + translateFromTranslatingX);\n    var newOffsetY = currentOffsetY + (translateFromZoomingY + translateFromTranslatingY);\n\n    var newPos = {\n      top: newOffsetY,\n      left: newOffsetX,\n      scaleX: pinchRatio,\n      scaleY: pinchRatio\n    };\n\n    self.canTap = false;\n\n    self.newWidth = newWidth;\n    self.newHeight = newHeight;\n\n    self.contentLastPos = newPos;\n\n    if (self.requestId) {\n      cancelAFrame(self.requestId);\n\n      self.requestId = null;\n    }\n\n    self.requestId = requestAFrame(function() {\n      $.fancybox.setTranslate(self.$content, self.contentLastPos);\n    });\n  };\n\n  Guestures.prototype.ontouchend = function(e) {\n    var self = this;\n    var dMs = Math.max(new Date().getTime() - self.startTime, 1);\n\n    var swiping = self.isSwiping;\n    var panning = self.isPanning;\n    var zooming = self.isZooming;\n    var scrolling = self.isScrolling;\n\n    self.endPoints = getPointerXY(e);\n\n    self.$container.removeClass(\"fancybox-controls--isGrabbing\");\n\n    $(document).off(\".fb.touch\");\n\n    document.removeEventListener(\"scroll\", self.onscroll, true);\n\n    if (self.requestId) {\n      cancelAFrame(self.requestId);\n\n      self.requestId = null;\n    }\n\n    self.isSwiping = false;\n    self.isPanning = false;\n    self.isZooming = false;\n    self.isScrolling = false;\n\n    self.instance.isDragging = false;\n\n    if (self.canTap) {\n      return self.onTap(e);\n    }\n\n    self.speed = 366;\n\n    // Speed in px/ms\n    self.velocityX = self.distanceX / dMs * 0.5;\n    self.velocityY = self.distanceY / dMs * 0.5;\n\n    self.speedX = Math.max(self.speed * 0.5, Math.min(self.speed * 1.5, 1 / Math.abs(self.velocityX) * self.speed));\n\n    if (panning) {\n      self.endPanning();\n    } else if (zooming) {\n      self.endZooming();\n    } else {\n      self.endSwiping(swiping, scrolling);\n    }\n\n    return;\n  };\n\n  Guestures.prototype.endSwiping = function(swiping, scrolling) {\n    var self = this,\n      ret = false,\n      len = self.instance.group.length;\n\n    self.sliderLastPos = null;\n\n    // Close if swiped vertically / navigate if horizontally\n    if (swiping == \"y\" && !scrolling && Math.abs(self.distanceY) > 50) {\n      // Continue vertical movement\n      $.fancybox.animate(\n        self.instance.current.$slide,\n        {\n          top: self.sliderStartPos.top + self.distanceY + self.velocityY * 150,\n          opacity: 0\n        },\n        200\n      );\n\n      ret = self.instance.close(true, 200);\n    } else if (swiping == \"x\" && self.distanceX > 50 && len > 1) {\n      ret = self.instance.previous(self.speedX);\n    } else if (swiping == \"x\" && self.distanceX < -50 && len > 1) {\n      ret = self.instance.next(self.speedX);\n    }\n\n    if (ret === false && (swiping == \"x\" || swiping == \"y\")) {\n      if (scrolling || len < 2) {\n        self.instance.centerSlide(self.instance.current, 150);\n      } else {\n        self.instance.jumpTo(self.instance.current.index);\n      }\n    }\n\n    self.$container.removeClass(\"fancybox-is-sliding\");\n  };\n\n  // Limit panning from edges\n  // ========================\n  Guestures.prototype.endPanning = function() {\n    var self = this;\n    var newOffsetX, newOffsetY, newPos;\n\n    if (!self.contentLastPos) {\n      return;\n    }\n\n    if (self.opts.momentum === false) {\n      newOffsetX = self.contentLastPos.left;\n      newOffsetY = self.contentLastPos.top;\n    } else {\n      // Continue movement\n      newOffsetX = self.contentLastPos.left + self.velocityX * self.speed;\n      newOffsetY = self.contentLastPos.top + self.velocityY * self.speed;\n    }\n\n    newPos = self.limitPosition(newOffsetX, newOffsetY, self.contentStartPos.width, self.contentStartPos.height);\n\n    newPos.width = self.contentStartPos.width;\n    newPos.height = self.contentStartPos.height;\n\n    $.fancybox.animate(self.$content, newPos, 330);\n  };\n\n  Guestures.prototype.endZooming = function() {\n    var self = this;\n\n    var current = self.instance.current;\n\n    var newOffsetX, newOffsetY, newPos, reset;\n\n    var newWidth = self.newWidth;\n    var newHeight = self.newHeight;\n\n    if (!self.contentLastPos) {\n      return;\n    }\n\n    newOffsetX = self.contentLastPos.left;\n    newOffsetY = self.contentLastPos.top;\n\n    reset = {\n      top: newOffsetY,\n      left: newOffsetX,\n      width: newWidth,\n      height: newHeight,\n      scaleX: 1,\n      scaleY: 1\n    };\n\n    // Reset scalex/scaleY values; this helps for perfomance and does not break animation\n    $.fancybox.setTranslate(self.$content, reset);\n\n    if (newWidth < self.canvasWidth && newHeight < self.canvasHeight) {\n      self.instance.scaleToFit(150);\n    } else if (newWidth > current.width || newHeight > current.height) {\n      self.instance.scaleToActual(self.centerPointStartX, self.centerPointStartY, 150);\n    } else {\n      newPos = self.limitPosition(newOffsetX, newOffsetY, newWidth, newHeight);\n\n      // Switch from scale() to width/height or animation will not work correctly\n      $.fancybox.setTranslate(self.$content, $.fancybox.getTranslate(self.$content));\n\n      $.fancybox.animate(self.$content, newPos, 150);\n    }\n  };\n\n  Guestures.prototype.onTap = function(e) {\n    var self = this;\n    var $target = $(e.target);\n\n    var instance = self.instance;\n    var current = instance.current;\n\n    var endPoints = (e && getPointerXY(e)) || self.startPoints;\n\n    var tapX = endPoints[0] ? endPoints[0].x - $(window).scrollLeft() - self.stagePos.left : 0;\n    var tapY = endPoints[0] ? endPoints[0].y - $(window).scrollTop() - self.stagePos.top : 0;\n\n    var where;\n\n    var process = function(prefix) {\n      var action = current.opts[prefix];\n\n      if ($.isFunction(action)) {\n        action = action.apply(instance, [current, e]);\n      }\n\n      if (!action) {\n        return;\n      }\n\n      switch (action) {\n        case \"close\":\n          instance.close(self.startEvent);\n\n          break;\n\n        case \"toggleControls\":\n          instance.toggleControls(true);\n\n          break;\n\n        case \"next\":\n          instance.next();\n\n          break;\n\n        case \"nextOrClose\":\n          if (instance.group.length > 1) {\n            instance.next();\n          } else {\n            instance.close(self.startEvent);\n          }\n\n          break;\n\n        case \"zoom\":\n          if (current.type == \"image\" && (current.isLoaded || current.$ghost)) {\n            if (instance.canPan()) {\n              instance.scaleToFit();\n            } else if (instance.isScaledDown()) {\n              instance.scaleToActual(tapX, tapY);\n            } else if (instance.group.length < 2) {\n              instance.close(self.startEvent);\n            }\n          }\n\n          break;\n      }\n    };\n\n    // Ignore right click\n    if (e.originalEvent && e.originalEvent.button == 2) {\n      return;\n    }\n\n    // Skip if clicked on the scrollbar\n    if (!$target.is(\"img\") && tapX > $target[0].clientWidth + $target.offset().left) {\n      return;\n    }\n\n    // Check where is clicked\n    if ($target.is(\".fancybox-bg,.fancybox-inner,.fancybox-outer,.fancybox-container\")) {\n      where = \"Outside\";\n    } else if ($target.is(\".fancybox-slide\")) {\n      where = \"Slide\";\n    } else if (\n      instance.current.$content &&\n      instance.current.$content\n        .find($target)\n        .addBack()\n        .filter($target).length\n    ) {\n      where = \"Content\";\n    } else {\n      return;\n    }\n\n    // Check if this is a double tap\n    if (self.tapped) {\n      // Stop previously created single tap\n      clearTimeout(self.tapped);\n      self.tapped = null;\n\n      // Skip if distance between taps is too big\n      if (Math.abs(tapX - self.tapX) > 50 || Math.abs(tapY - self.tapY) > 50) {\n        return this;\n      }\n\n      // OK, now we assume that this is a double-tap\n      process(\"dblclick\" + where);\n    } else {\n      // Single tap will be processed if user has not clicked second time within 300ms\n      // or there is no need to wait for double-tap\n      self.tapX = tapX;\n      self.tapY = tapY;\n\n      if (current.opts[\"dblclick\" + where] && current.opts[\"dblclick\" + where] !== current.opts[\"click\" + where]) {\n        self.tapped = setTimeout(function() {\n          self.tapped = null;\n\n          process(\"click\" + where);\n        }, 500);\n      } else {\n        process(\"click\" + where);\n      }\n    }\n\n    return this;\n  };\n\n  $(document).on(\"onActivate.fb\", function(e, instance) {\n    if (instance && !instance.Guestures) {\n      instance.Guestures = new Guestures(instance);\n    }\n  });\n})(window, document, window.jQuery || jQuery);\n\n// ==========================================================================\n//\n// SlideShow\n// Enables slideshow functionality\n//\n// Example of usage:\n// $.fancybox.getInstance().SlideShow.start()\n//\n// ==========================================================================\n(function(document, $) {\n  \"use strict\";\n\n  $.extend(true, $.fancybox.defaults, {\n    btnTpl: {\n      slideShow:\n        '<button data-fancybox-play class=\"fancybox-button fancybox-button--play\" title=\"{{PLAY_START}}\">' +\n        '<svg viewBox=\"0 0 40 40\">' +\n        '<path d=\"M13,12 L27,20 L13,27 Z\" />' +\n        '<path d=\"M15,10 v19 M23,10 v19\" />' +\n        \"</svg>\" +\n        \"</button>\"\n    },\n    slideShow: {\n      autoStart: false,\n      speed: 3000\n    }\n  });\n\n  var SlideShow = function(instance) {\n    this.instance = instance;\n    this.init();\n  };\n\n  $.extend(SlideShow.prototype, {\n    timer: null,\n    isActive: false,\n    $button: null,\n\n    init: function() {\n      var self = this;\n\n      self.$button = self.instance.$refs.toolbar.find(\"[data-fancybox-play]\").on(\"click\", function() {\n        self.toggle();\n      });\n\n      if (self.instance.group.length < 2 || !self.instance.group[self.instance.currIndex].opts.slideShow) {\n        self.$button.hide();\n      }\n    },\n\n    set: function(force) {\n      var self = this;\n\n      // Check if reached last element\n      if (\n        self.instance &&\n        self.instance.current &&\n        (force === true || self.instance.current.opts.loop || self.instance.currIndex < self.instance.group.length - 1)\n      ) {\n        self.timer = setTimeout(function() {\n          if (self.isActive) {\n            self.instance.jumpTo((self.instance.currIndex + 1) % self.instance.group.length);\n          }\n        }, self.instance.current.opts.slideShow.speed);\n      } else {\n        self.stop();\n        self.instance.idleSecondsCounter = 0;\n        self.instance.showControls();\n      }\n    },\n\n    clear: function() {\n      var self = this;\n\n      clearTimeout(self.timer);\n\n      self.timer = null;\n    },\n\n    start: function() {\n      var self = this;\n      var current = self.instance.current;\n\n      if (current) {\n        self.isActive = true;\n\n        self.$button\n          .attr(\"title\", current.opts.i18n[current.opts.lang].PLAY_STOP)\n          .removeClass(\"fancybox-button--play\")\n          .addClass(\"fancybox-button--pause\");\n\n        self.set(true);\n      }\n    },\n\n    stop: function() {\n      var self = this;\n      var current = self.instance.current;\n\n      self.clear();\n\n      self.$button\n        .attr(\"title\", current.opts.i18n[current.opts.lang].PLAY_START)\n        .removeClass(\"fancybox-button--pause\")\n        .addClass(\"fancybox-button--play\");\n\n      self.isActive = false;\n    },\n\n    toggle: function() {\n      var self = this;\n\n      if (self.isActive) {\n        self.stop();\n      } else {\n        self.start();\n      }\n    }\n  });\n\n  $(document).on({\n    \"onInit.fb\": function(e, instance) {\n      if (instance && !instance.SlideShow) {\n        instance.SlideShow = new SlideShow(instance);\n      }\n    },\n\n    \"beforeShow.fb\": function(e, instance, current, firstRun) {\n      var SlideShow = instance && instance.SlideShow;\n\n      if (firstRun) {\n        if (SlideShow && current.opts.slideShow.autoStart) {\n          SlideShow.start();\n        }\n      } else if (SlideShow && SlideShow.isActive) {\n        SlideShow.clear();\n      }\n    },\n\n    \"afterShow.fb\": function(e, instance, current) {\n      var SlideShow = instance && instance.SlideShow;\n\n      if (SlideShow && SlideShow.isActive) {\n        SlideShow.set();\n      }\n    },\n\n    \"afterKeydown.fb\": function(e, instance, current, keypress, keycode) {\n      var SlideShow = instance && instance.SlideShow;\n\n      // \"P\" or Spacebar\n      if (SlideShow && current.opts.slideShow && (keycode === 80 || keycode === 32) && !$(document.activeElement).is(\"button,a,input\")) {\n        keypress.preventDefault();\n\n        SlideShow.toggle();\n      }\n    },\n\n    \"beforeClose.fb onDeactivate.fb\": function(e, instance) {\n      var SlideShow = instance && instance.SlideShow;\n\n      if (SlideShow) {\n        SlideShow.stop();\n      }\n    }\n  });\n\n  // Page Visibility API to pause slideshow when window is not active\n  $(document).on(\"visibilitychange\", function() {\n    var instance = $.fancybox.getInstance();\n    var SlideShow = instance && instance.SlideShow;\n\n    if (SlideShow && SlideShow.isActive) {\n      if (document.hidden) {\n        SlideShow.clear();\n      } else {\n        SlideShow.set();\n      }\n    }\n  });\n})(document, window.jQuery || jQuery);\n\n// ==========================================================================\n//\n// FullScreen\n// Adds fullscreen functionality\n//\n// ==========================================================================\n(function(document, $) {\n  \"use strict\";\n\n  // Collection of methods supported by user browser\n  var fn = (function() {\n    var fnMap = [\n      [\"requestFullscreen\", \"exitFullscreen\", \"fullscreenElement\", \"fullscreenEnabled\", \"fullscreenchange\", \"fullscreenerror\"],\n      // new WebKit\n      [\n        \"webkitRequestFullscreen\",\n        \"webkitExitFullscreen\",\n        \"webkitFullscreenElement\",\n        \"webkitFullscreenEnabled\",\n        \"webkitfullscreenchange\",\n        \"webkitfullscreenerror\"\n      ],\n      // old WebKit (Safari 5.1)\n      [\n        \"webkitRequestFullScreen\",\n        \"webkitCancelFullScreen\",\n        \"webkitCurrentFullScreenElement\",\n        \"webkitCancelFullScreen\",\n        \"webkitfullscreenchange\",\n        \"webkitfullscreenerror\"\n      ],\n      [\n        \"mozRequestFullScreen\",\n        \"mozCancelFullScreen\",\n        \"mozFullScreenElement\",\n        \"mozFullScreenEnabled\",\n        \"mozfullscreenchange\",\n        \"mozfullscreenerror\"\n      ],\n      [\"msRequestFullscreen\", \"msExitFullscreen\", \"msFullscreenElement\", \"msFullscreenEnabled\", \"MSFullscreenChange\", \"MSFullscreenError\"]\n    ];\n\n    var ret = {};\n\n    for (var i = 0; i < fnMap.length; i++) {\n      var val = fnMap[i];\n\n      if (val && val[1] in document) {\n        for (var j = 0; j < val.length; j++) {\n          ret[fnMap[0][j]] = val[j];\n        }\n\n        return ret;\n      }\n    }\n\n    return false;\n  })();\n\n  // If browser does not have Full Screen API, then simply unset default button template and stop\n  if (!fn) {\n    if ($ && $.fancybox) {\n      $.fancybox.defaults.btnTpl.fullScreen = false;\n    }\n\n    return;\n  }\n\n  var FullScreen = {\n    request: function(elem) {\n      elem = elem || document.documentElement;\n\n      elem[fn.requestFullscreen](elem.ALLOW_KEYBOARD_INPUT);\n    },\n    exit: function() {\n      document[fn.exitFullscreen]();\n    },\n    toggle: function(elem) {\n      elem = elem || document.documentElement;\n\n      if (this.isFullscreen()) {\n        this.exit();\n      } else {\n        this.request(elem);\n      }\n    },\n    isFullscreen: function() {\n      return Boolean(document[fn.fullscreenElement]);\n    },\n    enabled: function() {\n      return Boolean(document[fn.fullscreenEnabled]);\n    }\n  };\n\n  $.extend(true, $.fancybox.defaults, {\n    btnTpl: {\n      fullScreen:\n        '<button data-fancybox-fullscreen class=\"fancybox-button fancybox-button--fullscreen\" title=\"{{FULL_SCREEN}}\">' +\n        '<svg viewBox=\"0 0 40 40\">' +\n        '<path d=\"M9,12 v16 h22 v-16 h-22 v8\" />' +\n        \"</svg>\" +\n        \"</button>\"\n    },\n    fullScreen: {\n      autoStart: false\n    }\n  });\n\n  $(document).on({\n    \"onInit.fb\": function(e, instance) {\n      var $container;\n\n      if (instance && instance.group[instance.currIndex].opts.fullScreen) {\n        $container = instance.$refs.container;\n\n        $container.on(\"click.fb-fullscreen\", \"[data-fancybox-fullscreen]\", function(e) {\n          e.stopPropagation();\n          e.preventDefault();\n\n          FullScreen.toggle();\n        });\n\n        if (instance.opts.fullScreen && instance.opts.fullScreen.autoStart === true) {\n          FullScreen.request();\n        }\n\n        // Expose API\n        instance.FullScreen = FullScreen;\n      } else if (instance) {\n        instance.$refs.toolbar.find(\"[data-fancybox-fullscreen]\").hide();\n      }\n    },\n\n    \"afterKeydown.fb\": function(e, instance, current, keypress, keycode) {\n      // \"F\"\n      if (instance && instance.FullScreen && keycode === 70) {\n        keypress.preventDefault();\n\n        instance.FullScreen.toggle();\n      }\n    },\n\n    \"beforeClose.fb\": function(e, instance) {\n      if (instance && instance.FullScreen && instance.$refs.container.hasClass(\"fancybox-is-fullscreen\")) {\n        FullScreen.exit();\n      }\n    }\n  });\n\n  $(document).on(fn.fullscreenchange, function() {\n    var isFullscreen = FullScreen.isFullscreen(),\n      instance = $.fancybox.getInstance();\n\n    if (instance) {\n      // If image is zooming, then force to stop and reposition properly\n      if (instance.current && instance.current.type === \"image\" && instance.isAnimating) {\n        instance.current.$content.css(\"transition\", \"none\");\n\n        instance.isAnimating = false;\n\n        instance.update(true, true, 0);\n      }\n\n      instance.trigger(\"onFullscreenChange\", isFullscreen);\n\n      instance.$refs.container.toggleClass(\"fancybox-is-fullscreen\", isFullscreen);\n    }\n  });\n})(document, window.jQuery || jQuery);\n\n// ==========================================================================\n//\n// Thumbs\n// Displays thumbnails in a grid\n//\n// ==========================================================================\n(function(document, $) {\n  \"use strict\";\n\n  var CLASS = \"fancybox-thumbs\",\n    CLASS_ACTIVE = CLASS + \"-active\",\n    CLASS_LOAD = CLASS + \"-loading\";\n\n  // Make sure there are default values\n  $.fancybox.defaults = $.extend(\n    true,\n    {\n      btnTpl: {\n        thumbs:\n          '<button data-fancybox-thumbs class=\"fancybox-button fancybox-button--thumbs\" title=\"{{THUMBS}}\">' +\n          '<svg viewBox=\"0 0 120 120\">' +\n          '<path d=\"M30,30 h14 v14 h-14 Z M50,30 h14 v14 h-14 Z M70,30 h14 v14 h-14 Z M30,50 h14 v14 h-14 Z M50,50 h14 v14 h-14 Z M70,50 h14 v14 h-14 Z M30,70 h14 v14 h-14 Z M50,70 h14 v14 h-14 Z M70,70 h14 v14 h-14 Z\" />' +\n          \"</svg>\" +\n          \"</button>\"\n      },\n      thumbs: {\n        autoStart: false, // Display thumbnails on opening\n        hideOnClose: true, // Hide thumbnail grid when closing animation starts\n        parentEl: \".fancybox-container\", // Container is injected into this element\n        axis: \"y\" // Vertical (y) or horizontal (x) scrolling\n      }\n    },\n    $.fancybox.defaults\n  );\n\n  var FancyThumbs = function(instance) {\n    this.init(instance);\n  };\n\n  $.extend(FancyThumbs.prototype, {\n    $button: null,\n    $grid: null,\n    $list: null,\n    isVisible: false,\n    isActive: false,\n\n    init: function(instance) {\n      var self = this,\n        first,\n        second;\n\n      self.instance = instance;\n\n      instance.Thumbs = self;\n\n      self.opts = instance.group[instance.currIndex].opts.thumbs;\n\n      // Enable thumbs if at least two group items have thumbnails\n      first = instance.group[0];\n      first = first.opts.thumb || (first.opts.$thumb && first.opts.$thumb.length ? first.opts.$thumb.attr(\"src\") : false);\n\n      if (instance.group.length > 1) {\n        second = instance.group[1];\n        second = second.opts.thumb || (second.opts.$thumb && second.opts.$thumb.length ? second.opts.$thumb.attr(\"src\") : false);\n      }\n\n      self.$button = instance.$refs.toolbar.find(\"[data-fancybox-thumbs]\");\n\n      if (self.opts && first && second && first && second) {\n        self.$button.show().on(\"click\", function() {\n          self.toggle();\n        });\n\n        self.isActive = true;\n      } else {\n        self.$button.hide();\n      }\n    },\n\n    create: function() {\n      var self = this,\n        instance = self.instance,\n        parentEl = self.opts.parentEl,\n        list = [],\n        src;\n\n      if (!self.$grid) {\n        // Create main element\n        self.$grid = $('<div class=\"' + CLASS + \" \" + CLASS + \"-\" + self.opts.axis + '\"></div>').appendTo(\n          instance.$refs.container\n            .find(parentEl)\n            .addBack()\n            .filter(parentEl)\n        );\n\n        // Add \"click\" event that performs gallery navigation\n        self.$grid.on(\"click\", \"li\", function() {\n          instance.jumpTo($(this).attr(\"data-index\"));\n        });\n      }\n\n      // Build the list\n      if (!self.$list) {\n        self.$list = $(\"<ul>\").appendTo(self.$grid);\n      }\n\n      $.each(instance.group, function(i, item) {\n        src = item.opts.thumb || (item.opts.$thumb ? item.opts.$thumb.attr(\"src\") : null);\n\n        if (!src && item.type === \"image\") {\n          src = item.src;\n        }\n\n        list.push(\n          '<li data-index=\"' +\n            i +\n            '\" tabindex=\"0\" class=\"' +\n            CLASS_LOAD +\n            '\"' +\n            (src && src.length ? ' style=\"background-image:url(' + src + ')\" />' : \"\") +\n            \"></li>\"\n        );\n      });\n\n      self.$list[0].innerHTML = list.join(\"\");\n\n      if (self.opts.axis === \"x\") {\n        // Set fixed width for list element to enable horizontal scrolling\n        self.$list.width(\n          parseInt(self.$grid.css(\"padding-right\"), 10) +\n            instance.group.length *\n              self.$list\n                .children()\n                .eq(0)\n                .outerWidth(true)\n        );\n      }\n    },\n\n    focus: function(duration) {\n      var self = this,\n        $list = self.$list,\n        $grid = self.$grid,\n        thumb,\n        thumbPos;\n\n      if (!self.instance.current) {\n        return;\n      }\n\n      thumb = $list\n        .children()\n        .removeClass(CLASS_ACTIVE)\n        .filter('[data-index=\"' + self.instance.current.index + '\"]')\n        .addClass(CLASS_ACTIVE);\n\n      thumbPos = thumb.position();\n\n      // Check if need to scroll to make current thumb visible\n      if (self.opts.axis === \"y\" && (thumbPos.top < 0 || thumbPos.top > $list.height() - thumb.outerHeight())) {\n        $list.stop().animate(\n          {\n            scrollTop: $list.scrollTop() + thumbPos.top\n          },\n          duration\n        );\n      } else if (\n        self.opts.axis === \"x\" &&\n        (thumbPos.left < $grid.scrollLeft() || thumbPos.left > $grid.scrollLeft() + ($grid.width() - thumb.outerWidth()))\n      ) {\n        $list\n          .parent()\n          .stop()\n          .animate(\n            {\n              scrollLeft: thumbPos.left\n            },\n            duration\n          );\n      }\n    },\n\n    update: function() {\n      var that = this;\n      that.instance.$refs.container.toggleClass(\"fancybox-show-thumbs\", this.isVisible);\n\n      if (that.isVisible) {\n        if (!that.$grid) {\n          that.create();\n        }\n\n        that.instance.trigger(\"onThumbsShow\");\n\n        that.focus(0);\n      } else if (that.$grid) {\n        that.instance.trigger(\"onThumbsHide\");\n      }\n\n      // Update content position\n      that.instance.update();\n    },\n\n    hide: function() {\n      this.isVisible = false;\n      this.update();\n    },\n\n    show: function() {\n      this.isVisible = true;\n      this.update();\n    },\n\n    toggle: function() {\n      this.isVisible = !this.isVisible;\n      this.update();\n    }\n  });\n\n  $(document).on({\n    \"onInit.fb\": function(e, instance) {\n      var Thumbs;\n\n      if (instance && !instance.Thumbs) {\n        Thumbs = new FancyThumbs(instance);\n\n        if (Thumbs.isActive && Thumbs.opts.autoStart === true) {\n          Thumbs.show();\n        }\n      }\n    },\n\n    \"beforeShow.fb\": function(e, instance, item, firstRun) {\n      var Thumbs = instance && instance.Thumbs;\n\n      if (Thumbs && Thumbs.isVisible) {\n        Thumbs.focus(firstRun ? 0 : 250);\n      }\n    },\n\n    \"afterKeydown.fb\": function(e, instance, current, keypress, keycode) {\n      var Thumbs = instance && instance.Thumbs;\n\n      // \"G\"\n      if (Thumbs && Thumbs.isActive && keycode === 71) {\n        keypress.preventDefault();\n\n        Thumbs.toggle();\n      }\n    },\n\n    \"beforeClose.fb\": function(e, instance) {\n      var Thumbs = instance && instance.Thumbs;\n\n      if (Thumbs && Thumbs.isVisible && Thumbs.opts.hideOnClose !== false) {\n        Thumbs.$grid.hide();\n      }\n    }\n  });\n})(document, window.jQuery || jQuery);\n\n//// ==========================================================================\n//\n// Share\n// Displays simple form for sharing current url\n//\n// ==========================================================================\n(function(document, $) {\n  \"use strict\";\n\n  $.extend(true, $.fancybox.defaults, {\n    btnTpl: {\n      share:\n        '<button data-fancybox-share class=\"fancybox-button fancybox-button--share\" title=\"{{SHARE}}\">' +\n        '<svg viewBox=\"0 0 40 40\">' +\n        '<path d=\"M6,30 C8,18 19,16 23,16 L23,16 L23,10 L33,20 L23,29 L23,24 C19,24 8,27 6,30 Z\">' +\n        \"</svg>\" +\n        \"</button>\"\n    },\n    share: {\n      url: function(instance, item) {\n        return (\n          (!instance.currentHash && !(item.type === \"inline\" || item.type === \"html\") ? item.origSrc || item.src : false) || window.location\n        );\n      },\n      tpl:\n        '<div class=\"fancybox-share\">' +\n        \"<h1>{{SHARE}}</h1>\" +\n        \"<p>\" +\n        '<a class=\"fancybox-share__button fancybox-share__button--fb\" href=\"https://www.facebook.com/sharer/sharer.php?u={{url}}\">' +\n        '<svg viewBox=\"0 0 512 512\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"m287 456v-299c0-21 6-35 35-35h38v-63c-7-1-29-3-55-3-54 0-91 33-91 94v306m143-254h-205v72h196\" /></svg>' +\n        \"<span>Facebook</span>\" +\n        \"</a>\" +\n        '<a class=\"fancybox-share__button fancybox-share__button--tw\" href=\"https://twitter.com/intent/tweet?url={{url}}&text={{descr}}\">' +\n        '<svg viewBox=\"0 0 512 512\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"m456 133c-14 7-31 11-47 13 17-10 30-27 37-46-15 10-34 16-52 20-61-62-157-7-141 75-68-3-129-35-169-85-22 37-11 86 26 109-13 0-26-4-37-9 0 39 28 72 65 80-12 3-25 4-37 2 10 33 41 57 77 57-42 30-77 38-122 34 170 111 378-32 359-208 16-11 30-25 41-42z\" /></svg>' +\n        \"<span>Twitter</span>\" +\n        \"</a>\" +\n        '<a class=\"fancybox-share__button fancybox-share__button--pt\" href=\"https://www.pinterest.com/pin/create/button/?url={{url}}&description={{descr}}&media={{media}}\">' +\n        '<svg viewBox=\"0 0 512 512\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"m265 56c-109 0-164 78-164 144 0 39 15 74 47 87 5 2 10 0 12-5l4-19c2-6 1-8-3-13-9-11-15-25-15-45 0-58 43-110 113-110 62 0 96 38 96 88 0 67-30 122-73 122-24 0-42-19-36-44 6-29 20-60 20-81 0-19-10-35-31-35-25 0-44 26-44 60 0 21 7 36 7 36l-30 125c-8 37-1 83 0 87 0 3 4 4 5 2 2-3 32-39 42-75l16-64c8 16 31 29 56 29 74 0 124-67 124-157 0-69-58-132-146-132z\" fill=\"#fff\"/></svg>' +\n        \"<span>Pinterest</span>\" +\n        \"</a>\" +\n        \"</p>\" +\n        '<p><input class=\"fancybox-share__input\" type=\"text\" value=\"{{url_raw}}\" /></p>' +\n        \"</div>\"\n    }\n  });\n\n  function escapeHtml(string) {\n    var entityMap = {\n      \"&\": \"&amp;\",\n      \"<\": \"&lt;\",\n      \">\": \"&gt;\",\n      '\"': \"&quot;\",\n      \"'\": \"&#39;\",\n      \"/\": \"&#x2F;\",\n      \"`\": \"&#x60;\",\n      \"=\": \"&#x3D;\"\n    };\n\n    return String(string).replace(/[&<>\"'`=\\/]/g, function(s) {\n      return entityMap[s];\n    });\n  }\n\n  $(document).on(\"click\", \"[data-fancybox-share]\", function() {\n    var instance = $.fancybox.getInstance(),\n      current = instance.current || null,\n      url,\n      tpl;\n\n    if (!current) {\n      return;\n    }\n\n    if ($.type(current.opts.share.url) === \"function\") {\n      url = current.opts.share.url.apply(current, [instance, current]);\n    }\n\n    tpl = current.opts.share.tpl\n      .replace(/\\{\\{media\\}\\}/g, current.type === \"image\" ? encodeURIComponent(current.src) : \"\")\n      .replace(/\\{\\{url\\}\\}/g, encodeURIComponent(url))\n      .replace(/\\{\\{url_raw\\}\\}/g, escapeHtml(url))\n      .replace(/\\{\\{descr\\}\\}/g, instance.$caption ? encodeURIComponent(instance.$caption.text()) : \"\");\n\n    $.fancybox.open({\n      src: instance.translate(instance, tpl),\n      type: \"html\",\n      opts: {\n        animationEffect: false,\n        afterLoad: function(shareInstance, shareCurrent) {\n          // Close self if parent instance is closing\n          instance.$refs.container.one(\"beforeClose.fb\", function() {\n            shareInstance.close(null, 0);\n          });\n\n          // Opening links in a popup window\n          shareCurrent.$content.find(\".fancybox-share__links a\").click(function() {\n            window.open(this.href, \"Share\", \"width=550, height=450\");\n            return false;\n          });\n        }\n      }\n    });\n  });\n})(document, window.jQuery || jQuery);\n\n// ==========================================================================\n//\n// Hash\n// Enables linking to each modal\n//\n// ==========================================================================\n(function(document, window, $) {\n  \"use strict\";\n\n  // Simple $.escapeSelector polyfill (for jQuery prior v3)\n  if (!$.escapeSelector) {\n    $.escapeSelector = function(sel) {\n      var rcssescape = /([\\0-\\x1f\\x7f]|^-?\\d)|^-$|[^\\x80-\\uFFFF\\w-]/g;\n      var fcssescape = function(ch, asCodePoint) {\n        if (asCodePoint) {\n          // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER\n          if (ch === \"\\0\") {\n            return \"\\uFFFD\";\n          }\n\n          // Control characters and (dependent upon position) numbers get escaped as code points\n          return ch.slice(0, -1) + \"\\\\\" + ch.charCodeAt(ch.length - 1).toString(16) + \" \";\n        }\n\n        // Other potentially-special ASCII characters get backslash-escaped\n        return \"\\\\\" + ch;\n      };\n\n      return (sel + \"\").replace(rcssescape, fcssescape);\n    };\n  }\n\n  // Get info about gallery name and current index from url\n  function parseUrl() {\n    var hash = window.location.hash.substr(1),\n      rez = hash.split(\"-\"),\n      index = rez.length > 1 && /^\\+?\\d+$/.test(rez[rez.length - 1]) ? parseInt(rez.pop(-1), 10) || 1 : 1,\n      gallery = rez.join(\"-\");\n\n    return {\n      hash: hash,\n      /* Index is starting from 1 */\n      index: index < 1 ? 1 : index,\n      gallery: gallery\n    };\n  }\n\n  // Trigger click evnt on links to open new fancyBox instance\n  function triggerFromUrl(url) {\n    var $el;\n\n    if (url.gallery !== \"\") {\n      // If we can find element matching 'data-fancybox' atribute, then trigger click event for that.\n      // It should start fancyBox\n      $el = $(\"[data-fancybox='\" + $.escapeSelector(url.gallery) + \"']\")\n        .eq(url.index - 1)\n        .trigger(\"click.fb-start\");\n    }\n  }\n\n  // Get gallery name from current instance\n  function getGalleryID(instance) {\n    var opts, ret;\n\n    if (!instance) {\n      return false;\n    }\n\n    opts = instance.current ? instance.current.opts : instance.opts;\n    ret = opts.hash || (opts.$orig ? opts.$orig.data(\"fancybox\") : \"\");\n\n    return ret === \"\" ? false : ret;\n  }\n\n  // Start when DOM becomes ready\n  $(function() {\n    // Check if user has disabled this module\n    if ($.fancybox.defaults.hash === false) {\n      return;\n    }\n\n    // Update hash when opening/closing fancyBox\n    $(document).on({\n      \"onInit.fb\": function(e, instance) {\n        var url, gallery;\n\n        if (instance.group[instance.currIndex].opts.hash === false) {\n          return;\n        }\n\n        url = parseUrl();\n        gallery = getGalleryID(instance);\n\n        // Make sure gallery start index matches index from hash\n        if (gallery && url.gallery && gallery == url.gallery) {\n          instance.currIndex = url.index - 1;\n        }\n      },\n\n      \"beforeShow.fb\": function(e, instance, current, firstRun) {\n        var gallery;\n\n        if (!current || current.opts.hash === false) {\n          return;\n        }\n\n        // Check if need to update window hash\n        gallery = getGalleryID(instance);\n\n        if (!gallery) {\n          return;\n        }\n\n        // Variable containing last hash value set by fancyBox\n        // It will be used to determine if fancyBox needs to close after hash change is detected\n        instance.currentHash = gallery + (instance.group.length > 1 ? \"-\" + (current.index + 1) : \"\");\n\n        // If current hash is the same (this instance most likely is opened by hashchange), then do nothing\n        if (window.location.hash === \"#\" + instance.currentHash) {\n          return;\n        }\n\n        if (!instance.origHash) {\n          instance.origHash = window.location.hash;\n        }\n\n        if (instance.hashTimer) {\n          clearTimeout(instance.hashTimer);\n        }\n\n        // Update hash\n        instance.hashTimer = setTimeout(function() {\n          if (\"replaceState\" in window.history) {\n            window.history[firstRun ? \"pushState\" : \"replaceState\"](\n              {},\n              document.title,\n              window.location.pathname + window.location.search + \"#\" + instance.currentHash\n            );\n\n            if (firstRun) {\n              instance.hasCreatedHistory = true;\n            }\n          } else {\n            window.location.hash = instance.currentHash;\n          }\n\n          instance.hashTimer = null;\n        }, 300);\n      },\n\n      \"beforeClose.fb\": function(e, instance, current) {\n        var gallery;\n\n        if (current.opts.hash === false) {\n          return;\n        }\n\n        gallery = getGalleryID(instance);\n\n        // Goto previous history entry\n        if (instance.currentHash && instance.hasCreatedHistory) {\n          window.history.back();\n        } else if (instance.currentHash) {\n          if (\"replaceState\" in window.history) {\n            window.history.replaceState({}, document.title, window.location.pathname + window.location.search + (instance.origHash || \"\"));\n          } else {\n            window.location.hash = instance.origHash;\n          }\n        }\n\n        instance.currentHash = null;\n\n        clearTimeout(instance.hashTimer);\n      }\n    });\n\n    // Check if need to start/close after url has changed\n    $(window).on(\"hashchange.fb\", function() {\n      var url = parseUrl(),\n        fb;\n\n      // Find last fancyBox instance that has \"hash\"\n      $.each(\n        $(\".fancybox-container\")\n          .get()\n          .reverse(),\n        function(index, value) {\n          var tmp = $(value).data(\"FancyBox\");\n          //isClosing\n          if (tmp.currentHash) {\n            fb = tmp;\n            return false;\n          }\n        }\n      );\n\n      if (fb) {\n        // Now, compare hash values\n        if (fb.currentHash && fb.currentHash !== url.gallery + \"-\" + url.index && !(url.index === 1 && fb.currentHash == url.gallery)) {\n          fb.currentHash = null;\n\n          fb.close();\n        }\n      } else if (url.gallery !== \"\") {\n        triggerFromUrl(url);\n      }\n    });\n\n    // Check current hash and trigger click event on matching element to start fancyBox, if needed\n    setTimeout(function() {\n      if (!$.fancybox.getInstance()) {\n        triggerFromUrl(parseUrl());\n      }\n    }, 50);\n  });\n})(document, window, window.jQuery || jQuery);\n\n// ==========================================================================\n//\n// Wheel\n// Basic mouse weheel support for gallery navigation\n//\n// ==========================================================================\n(function(document, $) {\n  \"use strict\";\n\n  var prevTime = new Date().getTime();\n\n  $(document).on({\n    \"onInit.fb\": function(e, instance, current) {\n      instance.$refs.stage.on(\"mousewheel DOMMouseScroll wheel MozMousePixelScroll\", function(e) {\n        var current = instance.current,\n          currTime = new Date().getTime();\n\n        if (instance.group.length < 2 || current.opts.wheel === false || (current.opts.wheel === \"auto\" && current.type !== \"image\")) {\n          return;\n        }\n\n        e.preventDefault();\n        e.stopPropagation();\n\n        if (current.$slide.hasClass(\"fancybox-animated\")) {\n          return;\n        }\n\n        e = e.originalEvent || e;\n\n        if (currTime - prevTime < 250) {\n          return;\n        }\n\n        prevTime = currTime;\n\n        instance[(-e.deltaY || -e.deltaX || e.wheelDelta || -e.detail) < 0 ? \"next\" : \"previous\"]();\n      });\n    }\n  });\n})(document, window.jQuery || jQuery);\n"
  },
  {
    "path": "server/static/log.js",
    "content": "function refresh(msg) {\n    $.ajax({\n        url: '/getlog',\n        type: \"GET\",\n        data: $.param({'validate': getCookie('validation')}),\n        success: function(res) {\n            var data = JSON.parse(res);            \n            if (data.code == 0) {\n                let log = data.log;\n                $('#log-input').text(log);\n                var scrollHeight = $('#log-input').prop(\"scrollHeight\");\n                $('#log-input').scrollTop(scrollHeight, 200);\n                $('button#REFRESH').on('click', function(e) {\n                    refresh();\n                });\n            } else {\n                toastr.error(data.message, '日志读取失败');\n            }\n        },\n        error: function() {\n            toastr.error('服务器异常', '日志读取失败');\n        }\n    });   \n}\n\n$(function() {\n    refresh();\n});\n\n"
  },
  {
    "path": "server/static/main.js",
    "content": "var menu = document.getElementById('menu');\n\nfunction restart() {\n    $.ajax({\n        url: '/operate',\n        type: \"POST\",\n        data: {\"type\": \"restart\", \"validate\": getCookie(\"validation\")},\n        success: function(res) {\n            var data = JSON.parse(res);\n            if (data.code == 0) {\n                toastr.success('三秒后将重启');\n            } else {\n                toastr.error(data.message, '重启失败');\n            }\n        },\n        error: function() {\n            toastr.error('服务器异常', '重启失败');\n        }\n    });\n}\n\nfunction renderMenu() {\n\tmenu.style.display = 'none';\n\tsetTimeout(function() {\n\t    menu.style.display = 'block';\n\t    menu.className = 'mfb-component--br'; + 'mfb-zoomin';\n\t},1);\n};\n\n\nfunction getCookie(name)\n{\n    var arr,reg=new RegExp(\"(^| )\"+name+\"=([^;]*)(;|$)\");\n    if(arr=document.cookie.match(reg))\n        return unescape(arr[2]);\n    else\n        return null;\n}\n\n//写cookies\nfunction setCookie(name,value)\n{\n    var Days = 30;\n    var exp = new Date();\n    exp.setTime(exp.getTime() + Days*24*60*60*1000);\n    document.cookie = name + \"=\"+ escape (value) + \";expires=\" + exp.toGMTString();\n}\n\nfunction arrayBufferToBase64( buffer ) {\n    var binary = '';\n    var bytes = new Uint8Array( buffer );\n    var len = bytes.byteLength;\n    for (var i = 0; i < len; i++) {\n        binary += String.fromCharCode( bytes[ i ] );\n    }\n    return window.btoa( binary );\n}\n\nfunction showSpin() {\n    var opts = {        \n        lines: 11, // The number of lines to draw\n        length: 16, // The length of each line\n        width: 10, // The line thickness\n        radius: 43, // The radius of the inner circle\n        scale: 0.85, // Scales overall size of the spinner\n        corners: 1, // Corner roundness (0..1)\n        color: '#e4095e', // CSS color or array of colors\n        fadeColor: 'transparent', // CSS color or array of colors\n        speed: 1, // Rounds per second\n        rotate: 0, // The rotation offset\n        animation: 'spinner-line-fade-quick', // The CSS animation name for the lines\n        direction: 1, // 1: clockwise, -1: counterclockwise\n        zIndex: 2e9, // The z-index (defaults to 2000000000)\n        className: 'spinner', // The CSS class to assign to the spinner\n        top: '50%', // Top position relative to parent\n        left: '50%', // Left position relative to parent\n        shadow: '0 0 1px transparent', // Box-shadow for the lines\n        position: 'absolute' // Element positioning\n    };\n\n\n    var target = document.getElementById('recorder');\n    this.spinner = new Spinner(opts).spin(target);\n}\n\nfunction dismissSpin() {\n    this.spinner && this.spinner.stop();\n}\n\n$(function() {\n    var recorder = new Recorder({\n        monitorGain: 0,\n        recordingGain: 1,\n        numberOfChannels: 1,\n        wavBitDepth: 16,\n        encoderPath: \"./static/waveWorker.min.js\"\n    });\n\n    this.recording = false;\n    var start = $(\"a#start-record\");\n    var stop = $(\"a#stop-record\");\n\n    stop.on('click', (e) => {\n        if (!this.recording) return;\n        this.recording = false;\n        recorder.stop();\n    });\n\n    start.on('click', (e) => {\n        if (this.recording) return;\n        this.recording = true;\n        if (!Recorder.isRecordingSupported()) {\n            toastr.error(\"您的浏览器不支持录音\", '录音失败');\n            return;\n        }\n        recorder.start().catch(function(e){\n            toastr.error(e.message, '录音失败');\n        });\n\n        recorder.onstart = function(){\n          console.debug('Recorder is started');\n          start.disabled = true;\n          stop.disabled = false;\n\n            showSpin();\n        };\n\n        recorder.onstop = function(){\n          console.debug('Recorder is stopped');\n          start.disabled = false;\n            stop.disabled = true;\n\n            dismissSpin();\n        };\n\n        recorder.onstreamerror = function(e){\n          console.error('Error encountered: ' + e.message );\n        };\n\n        recorder.ondataavailable = function( typedArray ){\n            data = arrayBufferToBase64(typedArray);\n            $.ajax({\n                url: '/chat',\n                type: \"POST\",\n                data: {\"type\": \"voice\", \"voice\": data, \"validate\": getCookie(\"validation\")},\n                success: function(res) {\n                    var data = JSON.parse(res);\n                    if (data.code == 0) {\n                        toastr.success('指令发送成功');\n                    } else {\n                        toastr.error(data.message, '指令发送失败');\n                    }\n                },\n                error: function() {\n                    toastr.error('服务器异常', '指令发送失败');\n                }\n            });\n        };\n    });\n});\n\n\n///// spin.js ///////\nvar __assign = (this && this.__assign) || function () {\n    __assign = Object.assign || function(t) {\n        for (var s, i = 1, n = arguments.length; i < n; i++) {\n            s = arguments[i];\n            for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))\n                t[p] = s[p];\n        }\n        return t;\n    };\n    return __assign.apply(this, arguments);\n};\nvar defaults = {\n    lines: 12,\n    length: 7,\n    width: 5,\n    radius: 10,\n    scale: 1.0,\n    corners: 1,\n    color: '#000',\n    fadeColor: 'transparent',\n    animation: 'spinner-line-fade-default',\n    rotate: 0,\n    direction: 1,\n    speed: 1,\n    zIndex: 2e9,\n    className: 'spinner',\n    top: '50%',\n    left: '50%',\n    shadow: '0 0 1px transparent',\n    position: 'absolute',\n};\nvar Spinner = /** @class */ (function () {\n    function Spinner(opts) {\n        if (opts === void 0) { opts = {}; }\n        this.opts = __assign({}, defaults, opts);\n    }\n    /**\n     * Adds the spinner to the given target element. If this instance is already\n     * spinning, it is automatically removed from its previous target by calling\n     * stop() internally.\n     */\n    Spinner.prototype.spin = function (target) {\n        this.stop();\n        this.el = document.createElement('div');\n        this.el.className = this.opts.className;\n        this.el.setAttribute('role', 'progressbar');\n        css(this.el, {\n            position: this.opts.position,\n            width: 0,\n            zIndex: this.opts.zIndex,\n            left: this.opts.left,\n            top: this.opts.top,\n            transform: \"scale(\" + this.opts.scale + \")\",\n        });\n        if (target) {\n            target.insertBefore(this.el, target.firstChild || null);\n        }\n        drawLines(this.el, this.opts);\n        return this;\n    };\n    /**\n     * Stops and removes the Spinner.\n     * Stopped spinners may be reused by calling spin() again.\n     */\n    Spinner.prototype.stop = function () {\n        if (this.el) {\n            if (typeof requestAnimationFrame !== 'undefined') {\n                cancelAnimationFrame(this.animateId);\n            }\n            else {\n                clearTimeout(this.animateId);\n            }\n            if (this.el.parentNode) {\n                this.el.parentNode.removeChild(this.el);\n            }\n            this.el = undefined;\n        }\n        return this;\n    };\n    return Spinner;\n}());\n\n/**\n * Sets multiple style properties at once.\n */\nfunction css(el, props) {\n    for (var prop in props) {\n        el.style[prop] = props[prop];\n    }\n    return el;\n}\n/**\n * Returns the line color from the given string or array.\n */\nfunction getColor(color, idx) {\n    return typeof color == 'string' ? color : color[idx % color.length];\n}\n/**\n * Internal method that draws the individual lines.\n */\nfunction drawLines(el, opts) {\n    var borderRadius = (Math.round(opts.corners * opts.width * 500) / 1000) + 'px';\n    var shadow = 'none';\n    if (opts.shadow === true) {\n        shadow = '0 2px 4px #000'; // default shadow\n    }\n    else if (typeof opts.shadow === 'string') {\n        shadow = opts.shadow;\n    }\n    var shadows = parseBoxShadow(shadow);\n    for (var i = 0; i < opts.lines; i++) {\n        var degrees = ~~(360 / opts.lines * i + opts.rotate);\n        var backgroundLine = css(document.createElement('div'), {\n            position: 'absolute',\n            top: -opts.width / 2 + \"px\",\n            width: (opts.length + opts.width) + 'px',\n            height: opts.width + 'px',\n            background: getColor(opts.fadeColor, i),\n            borderRadius: borderRadius,\n            transformOrigin: 'left',\n            transform: \"rotate(\" + degrees + \"deg) translateX(\" + opts.radius + \"px)\",\n        });\n        var delay = i * opts.direction / opts.lines / opts.speed;\n        delay -= 1 / opts.speed; // so initial animation state will include trail\n        var line = css(document.createElement('div'), {\n            width: '100%',\n            height: '100%',\n            background: getColor(opts.color, i),\n            borderRadius: borderRadius,\n            boxShadow: normalizeShadow(shadows, degrees),\n            animation: 1 / opts.speed + \"s linear \" + delay + \"s infinite \" + opts.animation,\n        });\n        backgroundLine.appendChild(line);\n        el.appendChild(backgroundLine);\n    }\n}\nfunction parseBoxShadow(boxShadow) {\n    var regex = /^\\s*([a-zA-Z]+\\s+)?(-?\\d+(\\.\\d+)?)([a-zA-Z]*)\\s+(-?\\d+(\\.\\d+)?)([a-zA-Z]*)(.*)$/;\n    var shadows = [];\n    for (var _i = 0, _a = boxShadow.split(','); _i < _a.length; _i++) {\n        var shadow = _a[_i];\n        var matches = shadow.match(regex);\n        if (matches === null) {\n            continue; // invalid syntax\n        }\n        var x = +matches[2];\n        var y = +matches[5];\n        var xUnits = matches[4];\n        var yUnits = matches[7];\n        if (x === 0 && !xUnits) {\n            xUnits = yUnits;\n        }\n        if (y === 0 && !yUnits) {\n            yUnits = xUnits;\n        }\n        if (xUnits !== yUnits) {\n            continue; // units must match to use as coordinates\n        }\n        shadows.push({\n            prefix: matches[1] || '',\n            x: x,\n            y: y,\n            xUnits: xUnits,\n            yUnits: yUnits,\n            end: matches[8],\n        });\n    }\n    return shadows;\n}\n/**\n * Modify box-shadow x/y offsets to counteract rotation\n */\nfunction normalizeShadow(shadows, degrees) {\n    var normalized = [];\n    for (var _i = 0, shadows_1 = shadows; _i < shadows_1.length; _i++) {\n        var shadow = shadows_1[_i];\n        var xy = convertOffset(shadow.x, shadow.y, degrees);\n        normalized.push(shadow.prefix + xy[0] + shadow.xUnits + ' ' + xy[1] + shadow.yUnits + shadow.end);\n    }\n    return normalized.join(', ');\n}\nfunction convertOffset(x, y, degrees) {\n    var radians = degrees * Math.PI / 180;\n    var sin = Math.sin(radians);\n    var cos = Math.cos(radians);\n    return [\n        Math.round((x * cos + y * sin) * 1000) / 1000,\n        Math.round((-x * sin + y * cos) * 1000) / 1000,\n    ];\n}\n\n\n"
  },
  {
    "path": "server/static/modernizr.touch.js",
    "content": "/* Modernizr 2.8.3 (Custom Build) | MIT & BSD\n * Build: http://modernizr.com/download/#-touch-teststyles-prefixes\n */\n;window.Modernizr=function(a,b,c){function v(a){i.cssText=a}function w(a,b){return v(l.join(a+\";\")+(b||\"\"))}function x(a,b){return typeof a===b}function y(a,b){return!!~(\"\"+a).indexOf(b)}function z(a,b,d){for(var e in a){var f=b[a[e]];if(f!==c)return d===!1?a[e]:x(f,\"function\")?f.bind(d||b):f}return!1}var d=\"2.8.3\",e={},f=b.documentElement,g=\"modernizr\",h=b.createElement(g),i=h.style,j,k={}.toString,l=\" -webkit- -moz- -o- -ms- \".split(\" \"),m={},n={},o={},p=[],q=p.slice,r,s=function(a,c,d,e){var h,i,j,k,l=b.createElement(\"div\"),m=b.body,n=m||b.createElement(\"body\");if(parseInt(d,10))while(d--)j=b.createElement(\"div\"),j.id=e?e[d]:g+(d+1),l.appendChild(j);return h=[\"&#173;\",'<style id=\"s',g,'\">',a,\"</style>\"].join(\"\"),l.id=g,(m?l:n).innerHTML+=h,n.appendChild(l),m||(n.style.background=\"\",n.style.overflow=\"hidden\",k=f.style.overflow,f.style.overflow=\"hidden\",f.appendChild(n)),i=c(l,a),m?l.parentNode.removeChild(l):(n.parentNode.removeChild(n),f.style.overflow=k),!!i},t={}.hasOwnProperty,u;!x(t,\"undefined\")&&!x(t.call,\"undefined\")?u=function(a,b){return t.call(a,b)}:u=function(a,b){return b in a&&x(a.constructor.prototype[b],\"undefined\")},Function.prototype.bind||(Function.prototype.bind=function(b){var c=this;if(typeof c!=\"function\")throw new TypeError;var d=q.call(arguments,1),e=function(){if(this instanceof e){var a=function(){};a.prototype=c.prototype;var f=new a,g=c.apply(f,d.concat(q.call(arguments)));return Object(g)===g?g:f}return c.apply(b,d.concat(q.call(arguments)))};return e}),m.touch=function(){var c;return\"ontouchstart\"in a||a.DocumentTouch&&b instanceof DocumentTouch?c=!0:s([\"@media (\",l.join(\"touch-enabled),(\"),g,\")\",\"{#modernizr{top:9px;position:absolute}}\"].join(\"\"),function(a){c=a.offsetTop===9}),c};for(var A in m)u(m,A)&&(r=A.toLowerCase(),e[r]=m[A](),p.push((e[r]?\"\":\"no-\")+r));return e.addTest=function(a,b){if(typeof a==\"object\")for(var d in a)u(a,d)&&e.addTest(d,a[d]);else{a=a.toLowerCase();if(e[a]!==c)return e;b=typeof b==\"function\"?b():b,typeof enableClasses!=\"undefined\"&&enableClasses&&(f.className+=\" \"+(b?\"\":\"no-\")+a),e[a]=b}return e},v(\"\"),h=j=null,e._version=d,e._prefixes=l,e.testStyles=s,e}(this,this.document);"
  },
  {
    "path": "server/static/monokai-sublime.css",
    "content": "/*\n *\n * Monokai Sublime style. Derived from Monokai by noformnocontent http://nn.mit-license.org/\n *\n * */\n\n.hljs {\n  display: block;\n  overflow-x: auto;\n  padding: 0.5em;\n  background: #23241f;\n}\n\n.hljs,\n.hljs-tag,\n.hljs-subst {\n  color: #f8f8f2;\n}\n\n.hljs-strong,\n.hljs-emphasis {\n  color: #a8a8a2;\n}\n\n.hljs-bullet,\n.hljs-quote,\n.hljs-number,\n.hljs-regexp,\n.hljs-literal,\n.hljs-link {\n  color: #ae81ff;\n}\n\n.hljs-code,\n.hljs-title,\n.hljs-section,\n.hljs-selector-class {\n  color: #a6e22e;\n}\n\n.hljs-strong {\n  font-weight: bold;\n}\n\n.hljs-emphasis {\n  font-style: italic;\n}\n\n.hljs-keyword,\n.hljs-selector-tag,\n.hljs-name,\n.hljs-attr {\n  color: #f92672;\n}\n\n.hljs-symbol,\n.hljs-attribute {\n  color: #66d9ef;\n}\n\n.hljs-params,\n.hljs-class .hljs-title {\n  color: #f8f8f2;\n}\n\n.hljs-string,\n.hljs-type,\n.hljs-built_in,\n.hljs-builtin-name,\n.hljs-selector-id,\n.hljs-selector-attr,\n.hljs-selector-pseudo,\n.hljs-addition,\n.hljs-variable,\n.hljs-template-variable {\n  color: #e6db74;\n}\n\n.hljs-comment,\n.hljs-deletion,\n.hljs-meta {\n  color: #75715e;\n}\n"
  },
  {
    "path": "server/static/qa.js",
    "content": "function upload() {\n    $.ajax({\n        url: '/qa',\n        type: \"POST\",\n        data: {\"qa\": $('#qa-input').val(), 'validate': getCookie('validation')},\n        success: function(res) {\n            var data = JSON.parse(res);\n            if (data.code == 0) {\n                toastr.success('提交成功');\n            } else {\n                toastr.error(data.message, '提交失败');\n            }\n        },\n        error: function() {\n            toastr.error('服务器异常', '设置失败');\n        }\n    });\n}\n\n\n$(function() {\n    $('button#UPLOAD').on('click', function(e) {\n        upload();\n    });\n});\n\n\n$(document).delegate('#qa-input', 'keydown', function(e) {\n    var keyCode = e.keyCode || e.which;\n\n    if (keyCode == 9) {\n        e.preventDefault();\n        var start = this.selectionStart;\n        var end = this.selectionEnd;\n\n        // set textarea value to: text before caret + tab + text after caret\n        $(this).val($(this).val().substring(0, start)\n                    + \"\\t\"\n                    + $(this).val().substring(end));\n\n        // put caret at right position again\n        this.selectionStart =\n            this.selectionEnd = start + 1;\n    }\n});\n"
  },
  {
    "path": "server/static/signin.css",
    "content": "html,\nbody {\n    height: 100%;\n}\n\nbody {\n    display: -ms-flexbox;\n    display: flex;\n    -ms-flex-align: center;\n    align-items: center;\n    padding-top: 40px;\n    padding-bottom: 40px;\n    background-color: #f5f5f5;\n}\n\n.form-signin {\n    width: 100%;\n    max-width: 330px;\n    padding: 15px;\n    margin: auto;\n}\n.form-signin .checkbox {\n    font-weight: 400;\n}\n.form-signin .form-control {\n    position: relative;\n    box-sizing: border-box;\n    height: auto;\n    padding: 10px;\n    font-size: 16px;\n}\n.form-signin .form-control:focus {\n    z-index: 2;\n}\n.form-signin input[type=\"email\"] {\n    margin-bottom: -1px;\n    border-bottom-right-radius: 0;\n    border-bottom-left-radius: 0;\n}\n.form-signin input[type=\"password\"] {\n    margin-bottom: 10px;\n    border-top-left-radius: 0;\n    border-top-right-radius: 0;\n}\n\n.footer {\n    display: block;\n    width: 0;\n    height: 0;\n}\n"
  },
  {
    "path": "server/static/spin.css",
    "content": "@keyframes spinner-line-fade-more {\n  0%, 100% {\n    opacity: 0; /* minimum opacity */\n  }\n  1% {\n    opacity: 1;\n  }\n}\n\n@keyframes spinner-line-fade-quick {\n  0%, 39%, 100% {\n    opacity: 0.25; /* minimum opacity */\n  }\n  40% {\n    opacity: 1;\n  }\n}\n\n@keyframes spinner-line-fade-default {\n  0%, 100% {\n    opacity: 0.22; /* minimum opacity */\n  }\n  1% {\n    opacity: 1;\n  }\n}\n"
  },
  {
    "path": "server/static/starter-template.css",
    "content": "body {\n    padding-top: 3rem;\n}\n\n.starter-template {\n    padding-top: 3rem;    \n}\n\n.update-alert {\n    margin-left: 0;\n    margin-right: 0;\n}\n\n.container div.history {\n    background: #EAEAEA;\n    border: 1px solid #e1e4e8;\n    border-radius: 3px;\n    box-shadow: inset 0 0 10px rgba(27,31,35,.05);\n    padding-top: 32px;\n    padding-bottom: 30px;\n    padding-left: 32px;\n    max-height: 400px;\n    overflow-y:scroll;\n    overflow-x:hidden;\n}\n\n.container div.query-form {\n    margin-top: 2rem;\n}\n\n.container.log {\n    padding-top: 32px;\n}\n\n.container.config {\n    padding-top: 32px;\n}\n\n.container.api {\n    padding-top: 32px;    \n}\n\n.footer {\n    text-align: center;\n    margin-top: 10px;\n    padding-top: 10px;\n    margin-bottom: 10px;\n    padding-bottom: 10px;\n    min-height: 15px;\n}\n\n.bubble img {\n    width:auto;\n    max-width: 100%;\n}\n\n.divider {\n    margin: 5rem 0;\n}\n\n@media (min-width: 40em)\n.featurette-heading {\n    font-size: 50px;\n}\n\n.featurette-heading {\n    font-weight: 300;\n    line-height: 1;\n    letter-spacing: -.05rem;\n}\n\n.quote {\n    padding: 1rem;\n    font-family: Lora,Georgia,\"Times New Roman\",'楷体',STKaiti,serif;\n    font-style: italic;\n}\n\n.bubble .plugin{\n    float: right;\n}\n\n.hljs {\n    border-radius: 4.5px;\n}"
  },
  {
    "path": "server/static/static.js",
    "content": ""
  },
  {
    "path": "server/templates/api.html",
    "content": "{% extends \"layout.html\" %}\n{% block body %}\n<link rel=\"stylesheet\" href=\"{{static_url('starter-template.css')}}\" crossorigin=\"anonymous\">\n<link rel=\"stylesheet\" href=\"{{static_url('api.css')}}\" crossorigin=\"anonymous\">\n<nav class=\"navbar navbar-expand-md navbar-dark bg-dark fixed-top\">\n  <a class=\"navbar-brand\" href=\"/\">wukong-robot</a>\n  <button class=\"navbar-toggler\" type=\"button\" data-toggle=\"collapse\" data-target=\"#navbarsExampleDefault\" aria-controls=\"navbarsExampleDefault\" aria-expanded=\"false\" aria-label=\"Toggle navigation\">\n    <span class=\"navbar-toggler-icon\"></span>\n  </button>\n  <div class=\"collapse navbar-collapse\" id=\"navbarsExampleDefault\">\n    <ul class=\"navbar-nav mr-auto\">\n      <li class=\"nav-item\">\n        <a class=\"nav-link\" href=\"/\">会话</a>\n      </li>\n      <li class=\"nav-item\">\n        <a class=\"nav-link\" href=\"/configpage\">配置</a>\n      </li>\n      <li class=\"nav-item\">\n        <a class=\"nav-link\" href=\"/logpage\">日志</a>\n      </li>\n      <li class=\"nav-item\">\n        <a class=\"nav-link\" href=\"/qa\">QA集</a>\n      </li>\n      <li class=\"nav-item active\">\n        <a class=\"nav-link\" href=\"/api\">API</a>\n      </li>\n      <li class=\"nav-item\">\n        <a class=\"nav-link\" href=\"/donate\">捐赠</a>\n      </li>\n    </ul>\n    <div class=\"form-inline my-2 my-lg-0\">\n    <a class=\"btn btn-outline-success my-2 my-sm-0\" href=\"https://wukong.hahack.com\" target=\"_blank\">文档</a>\n    </div>\n  </div>\n</nav>\n\n<div class=\"container api\">\n  {% raw content %}\n</div>\n\n<ul id=\"recorder\" class=\"mfb-component--br mfb-zoomin\" data-mfb-toggle=\"hover\">\n      <li class=\"mfb-component__wrap\">\n        <a href=\"#\" id=\"record\" class=\"mfb-component__button--main\">\n          <i class=\"mfb-component__main-icon--resting fa fa-microphone\"></i>\n          <i class=\"mfb-component__main-icon--active fa fa-times\"></i>\n        </a>\n        <ul class=\"mfb-component__list\">\n          <li>\n            <a href=\"#\" id=\"stop-record\" data-mfb-label=\"停止录制语音指令\" class=\"mfb-component__button--child\">\n              <i class=\"mfb-component__child-icon fas fa-stop\"></i>\n            </a>\n          </li>\n          <li>\n            <a href=\"#\" id=\"start-record\" data-mfb-label=\"开始录制语音指令\" class=\"mfb-component__button--child \">\n              <i class=\"mfb-component__child-icon fas fa-circle\"></i>\n            </a>\n          </li>\n        </ul>\n      </li>\n</ul>\n\n\n<script src=\"{{static_url('main.js')}}\" crossorigin=\"anonymous\"></script>\n<script src=\"{{static_url('log.js')}}\" crossorigin=\"anonymous\"></script>\n<script src=\"./static/recorder.min.js\"></script>\n{% end %}\n"
  },
  {
    "path": "server/templates/api.md",
    "content": "# 后台 API\n\n[TOC]\n\n## 鉴权\n\n所有接口都需要带上 `validate` 参数，该参数值和配置文件中的 `server/validate` 参数值相同。示例：\n\n``` sh\n$ curl localhost:5001/history?validate=f4bde2a342c7c75aa276f78b26cfbd8a\n```\n\n接口返回：\n\n```\n{\"code\": 0, \"message\": \"ok\", \"history\": \"[{\\\"type\\\": 1, \\\"text\\\": \\\"\\\\u4f1f\\\\u6d32 \\\\u4f60\\\\u597d\\\\uff01\\\\u8bd5\\\\u8bd5\\\\u5bf9\\\\u6211\\\\u558a\\\\u5524\\\\u9192\\\\u8bcd\\\\u53eb\\\\u9192\\\\u6211\\\\u5427\\\", \\\"time\\\": \\\"2019-02-07 19:10:19\\\", \\\"uuid\\\": \\\"f464d430-2ac8-11e9-bd1e-8c8590caf9a5\\\"}, {\\\"type\\\": 0, \\\"text\\\": \\\"\\\\u4eca\\\\u5929\\\\u5929\\\\u6c14\\\\u600e\\\\u4e48\\\\u6837\\\", \\\"time\\\": \\\"2019-02-07 19:10:33\\\", \\\"uuid\\\": \\\"fca4c218-2ac8-11e9-bd1e-8c8590caf9a5\\\"}, {\\\"type\\\": 1, \\\"text\\\": \\\"[Weather] \\\\u6df1\\\\u5733\\\\u5929\\\\u6c14\\\\uff1a\\\\u4eca\\\\u5929\\\\uff1a\\\\u591a\\\\u4e91\\\\uff0c20\\\\u523028\\\\u6444\\\\u6c0f\\\\u5ea6\\\\u3002\\\\u4eca\\\\u5929\\\\u5929\\\\u6c14\\\\u4e0d\\\\u9519\\\\uff0c\\\\u7a7a\\\\u6c14\\\\u6e05\\\\u65b0\\\\uff0c\\\\u9002\\\\u5408\\\\u51fa\\\\u95e8\\\\u8fd0\\\\u52a8\\\\u54e6\\\", \\\"time\\\": \\\"2019-02-07 19:10:33\\\", \\\"uuid\\\": \\\"fceec836-2ac8-11e9-bd1e-8c8590caf9a5\\\"}, {\\\"type\\\": 0, \\\"text\\\": \\\"\\\\u73b0\\\\u5728\\\\u51e0\\\\u70b9\\\", \\\"time\\\": \\\"2019-02-07 19:33:34\\\", \\\"uuid\\\": \\\"chat58b0d6a2-8395-1453-6383-4e27c421ea89\\\"}, {\\\"type\\\": 1, \\\"text\\\": \\\"2019\\\\u5e7402\\\\u670807\\\\u65e5 \\\\u661f\\\\u671f\\\\u56db \\\\u4e0b\\\\u5348 7:33\\\", \\\"time\\\": \\\"2019-02-07 19:33:35\\\", \\\"uuid\\\": \\\"3445dcd6-2acc-11e9-bd1e-8c8590caf9a5\\\"}]\"}\n```\n\n## 管理\n\n用于管理 wukong-robot ，包括重启/打开勿扰模式/关闭勿扰模式。\n\n- url：/operate\n- method: POST\n- 参数：\n\n| 参数名 |  是否必须 | 说明  |\n| ---   | ------- | ----- |\n| validate | 是 | 参见 [鉴权](#_1) |\n| type  | 是 |  管理类型类型。详见 [管理类型取值](#管理类型取值) |\n\n### 管理类型取值\n\n| 取值 | 说明 |\n| ---- |  ---- |\n| 0    | 重启 wukong-robot |\n| 1    | 打开勿扰模式 |\n| 2    | 关闭勿扰模式 |\n\n- 示例：\n\n``` sh\n$ curl -X POST localhost:5001/operate -d \"type=restart&validate=f4bde2a342c7c75aa276f78b26cfbd8a\"\n```\n\n- 返回：\n\n| 字段名 |  说明  |\n| ---   | ----- |\n| code  | 返回码。0：成功；1：失败 |\n| message | 结果说明 |\n\n## 日志\n\n用于查看 wukong-robot 保存的日志。出于性能上的考虑，默认只返回最后 200 行的内容，相当于做了一次 `tail -n 200` 。\n\n- url：/log\n- method: GET\n- 参数：\n\n| 参数名 |  是否必须 | 说明  |\n| ---   | ------- | ----- |\n| validate | 是 | 参见 [鉴权](#_1) |\n| lines | 可选 | 最大读取的日志行数。默认值为 200  |\n\n- 示例：\n\n``` sh\n$ curl localhost:5001/log?validate=f4bde2a342c7c75aa276f78b26cfbd8a&lines=10\n```\n\n- 返回：\n\n| 字段名 |  说明  |\n| ---   | ----- |\n| code  | 返回码。0：成功；1：失败 |\n| message | 结果说明 |\n| log | 日志内容 |\n\n\n## 对话\n\n### 发起对话\n\n用于发起一次对话。\n\n- url：/chat\n- method: POST\n- 参数：\n\n| 参数名 |  是否必须 | 说明  |\n| ---   | ------- | ----- |\n| validate | 是 | 参见 [鉴权](#_1) |\n| type  | 是 |  query 类型。 \"text\": 文本型 query ； \"voice\"：语音型 query |\n| query | 仅当 type 为 \"text\" 时需要 |  发起对话的内容的 urlencode 后的值。例如 ”现在几点？“ 的 urlencode 结果 | \n| uuid  | 仅当 type 为 \"text\" 时需要 |  为这个文本 query 赋予的一个 uuid。例如可以使用随机字符+时间戳。|\n| voice | 仅当 type 为 \"voice\" 时需要  | 语音。需为 单通道，采样率为 16k 的 wav 格式语音的 base64 编码。 |\n\n- 示例：\n\n``` sh\n$ curl -X POST localhost:5001/chat -d \"type=text&query=%E7%8E%B0%E5%9C%A8%E5%87%A0%E7%82%B9&validate=f4bde2a342c7c75aa276f78b26cfbd8a&uuid=chated17be5d-0240-c9ba-2b2e-7eb98588cf34\"\n```\n\n- 返回：\n\n| 参数名 |  说明  |\n| ---   | ----- |\n| code  | 返回码。0：成功；1：失败 |\n| message | 结果说明 |\n\n### 对话历史\n\n用于查看 wukong-robot 启动到现在的所有会话记录。\n\n- url：/history\n- method: GET\n- 参数：\n\n| 参数名 |  是否必须 | 说明  |\n| ---   | ------- | ----- |\n| validate | 是 | 参见 [鉴权](#_1) |\n\n- 示例：\n\n``` sh\n$ curl localhost:5001/history?validate=f4bde2a342c7c75aa276f78b26cfbd8a\n```\n\n- 返回：\n\n| 字段名 |  说明  |\n| ---   | ----- |\n| code  | 返回码。0：成功；1：失败 |\n| message | 结果说明 |\n| history | 会话历史 |\n\n## 配置\n\n### 查看配置\n\n用于查看 wukong-robot 现有的配置。\n\n- url：/config\n- method: GET\n- 参数：\n\n| 参数名 |  是否必须 | 说明  |\n| ---   | ------- | ----- |\n| validate | 是 | 参见 [鉴权](#_1) |\n| key | 可选 | 某个配置的键值。例如：`robot_name_cn` 。如果要多级key的对应value，则使用 `/一级key/二级key/...` 的形式，例如 `/server/host` 可以取 `server` 的 `host` 配置。 |\n\n- 示例：\n\n``` sh\n$ curl localhost:5001/config?validate=f4bde2a342c7c75aa276f78b26cfbd8a\\&key=server\n```\n\n- 返回：\n\n| 字段名 |  说明  |\n| ---   | ----- |\n| code  | 返回码。0：成功；1：失败 |\n| message | 结果说明 |\n| config | 全部的配置，仅当不传 `key` 参数时提供 |\n| value | `key` 提供的配置，仅当传 `key` 参数时提供；如果找不到这个 `key`，则返回 `null` |\n\n### 修改配置\n\n用于配置 wukong-robot 。\n\n- url：/config\n- method: POST\n- 参数：\n\n| 参数名 |  是否必须 | 说明  |\n| ---   | ------- | ----- |\n| validate | 是 | 参见 [鉴权](#_1) |\n| config | 是 | 配置内容，必须为 yaml 可解析的文本经过 urlencode 后的值 |\n\n- 示例：\n\n``` sh\n$ curl -X localhost:5001/config -d \"config=robot_name_cn%3A+'%E5%AD%99%E6%82%9F%E7%A9%BA'%0Afirst_name%3A+'%E4%BC%9F%E6%B4%B2'%0Alast_name%3A+'%E6%BD%98'%0Atimezone%3A+HKT%0Alocation%3A+'%E6%B7%B1%E5%9C%B3'%0A%0A%23+%E5%90%8E%E5%8F%B0%E7%AE%A1%E7%90%86%E7%AB%AF%0Aserver%3A%0A++++enable%3A+true%0A++++host%3A+'0.0.0.0'++%23+ip+%E5%9C%B0%E5%9D%80%0A++++port%3A+'5001'+++++%23+%E7%AB%AF%E5%8F%A3%E5%8F%B7++++%0A++++username%3A+'wukong'...\"\n```\n\n- 返回：\n\n| 字段名 |  说明  |\n| ---   | ----- |\n| code  | 返回码。0：成功；1：失败 |\n| message | 结果说明 |\n\n\n"
  },
  {
    "path": "server/templates/config.html",
    "content": "{% extends \"layout.html\" %}\n{% block body %}\n<link rel=\"stylesheet\" href=\"{{static_url('starter-template.css')}}\" crossorigin=\"anonymous\">\n\n<nav class=\"navbar navbar-expand-md navbar-dark bg-dark fixed-top\">\n  <a class=\"navbar-brand\" href=\"/\">wukong-robot</a>\n  <button class=\"navbar-toggler\" type=\"button\" data-toggle=\"collapse\" data-target=\"#navbarsExampleDefault\" aria-controls=\"navbarsExampleDefault\" aria-expanded=\"false\" aria-label=\"Toggle navigation\">\n    <span class=\"navbar-toggler-icon\"></span>\n  </button>\n  <div class=\"collapse navbar-collapse\" id=\"navbarsExampleDefault\">\n    <ul class=\"navbar-nav mr-auto\">\n      <li class=\"nav-item\">\n        <a class=\"nav-link\" href=\"/\">会话</a>\n      </li>\n      <li class=\"nav-item active\">\n        <a class=\"nav-link\" href=\"/configpage\">配置</a>\n      </li>\n      <li class=\"nav-item\">\n        <a class=\"nav-link\" href=\"/logpage\">日志</a>\n      </li>\n      <li class=\"nav-item\">\n        <a class=\"nav-link\" href=\"/qa\">QA集</a>\n      </li>\n      <li class=\"nav-item\">\n        <a class=\"nav-link\" href=\"/api\">API</a>\n      </li>\n      <li class=\"nav-item\">\n        <a class=\"nav-link\" href=\"/donate\">捐赠</a>\n      </li>\n    </ul>\n    <div class=\"form-inline my-2 my-lg-0\">\n      <a class=\"btn btn-outline-success my-2 my-sm-0\" href=\"https://wukong.hahack.com\" target=\"_blank\">文档</a>\n    </div>\n  </div>\n</nav>\n\n<div class=\"container config\">\n  <div class=\"alert alert-info\" role=\"alert\">\n    <i class=\"fas fa-bell\"></i> 唤醒词和敏感度的修改需重启 wukong-robot 后才生效。\n  </div>\n  <label for=\"sensitivity\">离线唤醒敏感度：<span id=\"sensitivitiy-value\"></span> </label>\n  <input type=\"range\" class=\"custom-range\" min=\"0\" max=\"1\" step=\"0.1\" value=\"{{sensitivity}}\" id=\"sensitivity\">\n  <br/>\n  <label for=\"config-form\">配置文件</label>\n  <div id=\"config-placeholder\">\n  </div>\n</div>\n\n<ul id=\"recorder\" class=\"mfb-component--br mfb-zoomin\" data-mfb-toggle=\"hover\">\n      <li class=\"mfb-component__wrap\">\n        <a href=\"#\" id=\"record\" class=\"mfb-component__button--main\">\n          <i class=\"mfb-component__main-icon--resting fa fa-microphone\"></i>\n          <i class=\"mfb-component__main-icon--active fa fa-times\"></i>\n        </a>\n        <ul class=\"mfb-component__list\">\n          <li>\n            <a href=\"#\" id=\"stop-record\" data-mfb-label=\"停止录制语音指令\" class=\"mfb-component__button--child\">\n              <i class=\"mfb-component__child-icon fas fa-stop\"></i>\n            </a>\n          </li>\n          <li>\n            <a href=\"#\" id=\"start-record\" data-mfb-label=\"开始录制语音指令\" class=\"mfb-component__button--child \">\n              <i class=\"mfb-component__child-icon fas fa-circle\"></i>\n            </a>\n          </li>\n        </ul>\n      </li>\n</ul>\n\n<div class=\"modal fade\" id=\"restartModal\" tabindex=\"-1\" role=\"dialog\" aria-labelledby=\"restartModalLabel\" aria-hidden=\"true\">\n  <div class=\"modal-dialog\" role=\"document\">\n    <div class=\"modal-content\">\n      <div class=\"modal-header\">\n        <h5 class=\"modal-title\" id=\"restartModalLabel\">你确定吗？</h5>\n        <button type=\"button\" class=\"close\" data-dismiss=\"modal\" aria-label=\"Close\">\n          <span aria-hidden=\"true\">&times;</span>\n        </button>\n      </div>\n      <div class=\"modal-body\">\n        确定要重启 wukong-robot 吗？\n      </div>\n      <div class=\"modal-footer\">\n        <button type=\"button\" class=\"btn btn-secondary\" data-dismiss=\"modal\">只是手抖</button>\n        <button type=\"button\" class=\"btn btn-primary\" id=\"RESTART\" data-dismiss=\"modal\">确定</button>\n      </div>\n    </div>\n  </div>\n</div>\n\n\n<script src=\"{{static_url('main.js')}}\" crossorigin=\"anonymous\"></script>\n<script src=\"{{static_url('config.js')}}\" crossorigin=\"anonymous\"></script>\n<script src=\"{{static_url('bootbox.js')}}\" crossorigin=\"anonymous\"></script>\n<script src=\"./static/recorder.min.js\"></script>\n{% end %}\n"
  },
  {
    "path": "server/templates/donate.html",
    "content": "{% extends \"layout.html\" %}\n{% block body %}\n<link rel=\"stylesheet\" href=\"{{static_url('starter-template.css')}}\" crossorigin=\"anonymous\">\n<link rel=\"stylesheet\" href=\"{{static_url('api.css')}}\" crossorigin=\"anonymous\">\n<nav class=\"navbar navbar-expand-md navbar-dark bg-dark fixed-top\">\n  <a class=\"navbar-brand\" href=\"/\">wukong-robot</a>\n  <button class=\"navbar-toggler\" type=\"button\" data-toggle=\"collapse\" data-target=\"#navbarsExampleDefault\" aria-controls=\"navbarsExampleDefault\" aria-expanded=\"false\" aria-label=\"Toggle navigation\">\n    <span class=\"navbar-toggler-icon\"></span>\n  </button>\n  <div class=\"collapse navbar-collapse\" id=\"navbarsExampleDefault\">\n    <ul class=\"navbar-nav mr-auto\">\n      <li class=\"nav-item\">\n        <a class=\"nav-link\" href=\"/\">会话</a>\n      </li>\n      <li class=\"nav-item\">\n        <a class=\"nav-link\" href=\"/configpage\">配置</a>\n      </li>\n      <li class=\"nav-item\">\n        <a class=\"nav-link\" href=\"/logpage\">日志</a>\n      </li>\n      <li class=\"nav-item\">\n        <a class=\"nav-link\" href=\"/qa\">QA集</a>\n      </li>\n      <li class=\"nav-item\">\n        <a class=\"nav-link\" href=\"/api\">API</a>\n      </li>\n      <li class=\"nav-item active\">\n        <a class=\"nav-link\" href=\"/donate\">捐赠</a>\n      </li>\n    </ul>\n    <div class=\"form-inline my-2 my-lg-0\">\n    <a class=\"btn btn-outline-success my-2 my-sm-0\" href=\"https://wukong.hahack.com\" target=\"_blank\">文档</a>\n    </div>\n  </div>\n</nav>\n\n<div class=\"container api\">\n  {% raw content %}\n</div>\n\n<ul id=\"recorder\" class=\"mfb-component--br mfb-zoomin\" data-mfb-toggle=\"hover\">\n      <li class=\"mfb-component__wrap\">\n        <a href=\"#\" id=\"record\" class=\"mfb-component__button--main\">\n          <i class=\"mfb-component__main-icon--resting fa fa-microphone\"></i>\n          <i class=\"mfb-component__main-icon--active fa fa-times\"></i>\n        </a>\n        <ul class=\"mfb-component__list\">\n          <li>\n            <a href=\"#\" id=\"stop-record\" data-mfb-label=\"停止录制语音指令\" class=\"mfb-component__button--child\">\n              <i class=\"mfb-component__child-icon fas fa-stop\"></i>\n            </a>\n          </li>\n          <li>\n            <a href=\"#\" id=\"start-record\" data-mfb-label=\"开始录制语音指令\" class=\"mfb-component__button--child \">\n              <i class=\"mfb-component__child-icon fas fa-circle\"></i>\n            </a>\n          </li>\n        </ul>\n      </li>\n</ul>\n\n\n<script src=\"{{static_url('main.js')}}\" crossorigin=\"anonymous\"></script>\n<script src=\"{{static_url('log.js')}}\" crossorigin=\"anonymous\"></script>\n<script src=\"./static/recorder.min.js\"></script>\n{% end %}\n"
  },
  {
    "path": "server/templates/index.html",
    "content": "{% extends \"layout.html\" %}\n{% autoescape None %}\n{% block body %}\n<link rel=\"stylesheet\" href=\"{{static_url('starter-template.css')}}\" crossorigin=\"anonymous\">\n<link rel=\"stylesheet\" href=\"{{static_url('bubble.css')}}\" crossorigin=\"anonymous\">\n<link rel=\"stylesheet\" href=\"{{static_url('progressjs.min.css')}}\" crossorigin=\"anonymous\">\n<link rel=\"stylesheet\" href=\"{{static_url('default.min.css')}}\" crossorigin=\"anonymous\">\n<link rel=\"stylesheet\" href=\"{{static_url('monokai-sublime.css')}}\" crossorigin=\"anonymous\">\n<nav class=\"navbar navbar-expand-md navbar-dark bg-dark fixed-top\">\n  <a class=\"navbar-brand\" href=\"/\">wukong-robot</a>\n  <button class=\"navbar-toggler\" type=\"button\" data-toggle=\"collapse\" data-target=\"#navbarsExampleDefault\" aria-controls=\"navbarsExampleDefault\" aria-expanded=\"false\" aria-label=\"Toggle navigation\">\n    <span class=\"navbar-toggler-icon\"></span>\n  </button>\n  <div class=\"collapse navbar-collapse\" id=\"navbarsExampleDefault\">\n    <ul class=\"navbar-nav mr-auto\">\n      <li class=\"nav-item active\">\n        <a class=\"nav-link\" href=\"/\">会话</a>\n      </li>\n      <li class=\"nav-item\">\n        <a class=\"nav-link\" href=\"/configpage\">配置</a>\n      </li>\n      <li class=\"nav-item\">\n        <a class=\"nav-link\" href=\"/logpage\">日志</a>\n      </li>\n      <li class=\"nav-item\">\n        <a class=\"nav-link\" href=\"/qa\">QA集</a>\n      </li>\n      <li class=\"nav-item\">\n        <a class=\"nav-link\" href=\"/api\">API</a>\n      </li>\n      <li class=\"nav-item\">\n        <a class=\"nav-link\" href=\"/donate\">捐赠</a>\n      </li>\n    </ul>\n    <div class=\"form-inline my-2 my-lg-0\">\n      <a class=\"btn btn-outline-success my-2 my-sm-0\" href=\"https://wukong.hahack.com\" target=\"_blank\">文档</a>\n    </div>\n  </div>\n</nav>\n\n<div class=\"jumbotron\">\n  <h1 class=\"display-4\"><image src=\"./static/robot.png\" width=128px attr=\"wukong-robot\"/> wukong-robot</h1>\n  <p class=\"lead\">wukong-robot 是一个简单灵活的中文语音对话机器人。</p>\n  <hr class=\"my-4\">\n  <p><i class=\"fas fa-info-circle\"></i> 本站点是 wukong-robot 的后台管理端，仅供远程交互，不支持离线唤醒。</p>\n  {% if notices %}\n    {% for notice in notices %}\n      <p><i class=\"fas fa-bell\"></i> {{ linkify(notice) }}</p>\n    {% end %}\n  {% end %}\n</div>\n\n<div class=\"container\">\n{% if update_info and 'main' in update_info or 'contrib' in update_info %}\n<div class=\"alert update-alert alert-success alert-dismissible fade show\" role=\"alert\">\n  有新的更新可用，<a href=\"#\" id=\"check-update\" data-toggle=\"modal\" data-target=\"#updateModal\">快看看吧</a> 。\n  <button type=\"button\" class=\"close\" data-dismiss=\"alert\" aria-label=\"Close\">\n    <span aria-hidden=\"true\">&times;</span>\n  </button>\n</div>\n<!-- Modal -->\n<div class=\"modal fade\" id=\"updateModal\" tabindex=\"-1\" role=\"dialog\" aria-labelledby=\"updateModalLabel\" aria-hidden=\"true\">\n  <div class=\"modal-dialog\" role=\"document\">\n    <div class=\"modal-content\">\n      <div class=\"modal-header\">\n        <h5 class=\"modal-title\" id=\"updateModalLabel\">更新信息</h5>\n        <button type=\"button\" class=\"close\" data-dismiss=\"modal\" aria-label=\"Close\">\n          <span aria-hidden=\"true\">&times;</span>\n        </button>\n      </div>\n      <div class=\"modal-body\">\n        <ul>\n        {% if 'main' in update_info %}\n        <li><strong>主仓库更新</strong>（{{ update_info['main']['version'] }}）：{{ update_info['main']['description'] }}</li>\n        {% end %}\n        {% if 'contrib' in update_info %}\n        <li><strong>插件更新</strong>（{{ update_info['contrib']['version'] }}）：{{ update_info['contrib']['description'] }}</li>\n        {% end %}\n        </ul>\n        一次更新只需要花费几分钟的时间，完成后 wukong-robot 将自动重启。\n      </div>\n      <div class=\"modal-footer\">\n        <button type=\"button\" class=\"btn btn-secondary\" data-dismiss=\"modal\">先不更新</button>\n        <button type=\"button\" class=\"btn btn-primary UPDATE\">\n          <span class=\"spinner-border spinner-border-sm UPDATE-SPIN\" role=\"status\" aria-hidden=\"true\" hidden></span>\n          更新\n        </button>\n      </div>\n    </div>\n  </div>\n</div>\n{% end %}\n{% if 'hahack.com' in location %}\n  <div class=\"alert alert-warning\" role=\"alert\">\n    注意：你正在使用 demo 站点。出于账号安全考虑，该站点只演示了百度 UNIT 对话能力。要使用离线唤醒、ChatGPT 等对话能力及技能插件，请自行部署配置。\n  </div>\n{% end %}\n</div>\n\n<div class=\"container\" id=\"container\">\n  <div class=\"history\">    \n  </div><!-- <div class=\"history\"> -->\n\n  <div class=\"query-form\">\n    <center>\n      <form class=\"form-row\" action=\"#\">\n        <label for=\"query\" class=\"col-sm-2 col-form-label col-form-label-lg\">说句话：</label>\n        <div class=\"col-7\">\n          <input type=\"text\" class=\"form-control\" name=\"query\" id=\"query\" placeholder=\"{{suggestion}}\" required autofocus>    </div>\n        &nbsp;\n        <button type=\"submit\" class=\"btn btn-primary mb-2 CHAT\"><i class=\"fas fa-comment\"></i> 发送</button>\n      </form>\n    </center>\n  </div><!-- <div class=\"query-form\"> -->\n\n\n  <hr class=\"divider\">\n\n  <div class=\"sponsors\">\n        <h2 class=\"featurette-heading\">赞助商</h2>\n        <p class=\"lead\">感谢以下企业/组织对本项目的赞助：</p>\n      <p align=\"center\">\n  <a href=\"https://opencollective.com/wukong-robot/sponsor/0/website\" target=\"_blank\"><img src=\"https://opencollective.com/wukong-robot/sponsor/0/avatar.svg\"></a>\n<a href=\"https://opencollective.com/wukong-robot/sponsor/1/website\" target=\"_blank\"><img src=\"https://opencollective.com/wukong-robot/sponsor/1/avatar.svg\"></a>\n<a href=\"https://opencollective.com/wukong-robot/sponsor/2/website\" target=\"_blank\"><img src=\"https://opencollective.com/wukong-robot/sponsor/2/avatar.svg\"></a>\n<a href=\"https://opencollective.com/wukong-robot/sponsor/3/website\" target=\"_blank\"><img src=\"https://opencollective.com/wukong-robot/sponsor/3/avatar.svg\"></a>\n<a href=\"https://opencollective.com/wukong-robot/sponsor/4/website\" target=\"_blank\"><img src=\"https://opencollective.com/wukong-robot/sponsor/4/avatar.svg\"></a>\n<a href=\"https://opencollective.com/wukong-robot/sponsor/5/website\" target=\"_blank\"><img src=\"https://opencollective.com/wukong-robot/sponsor/5/avatar.svg\"></a>\n<a href=\"https://opencollective.com/wukong-robot/sponsor/6/website\" target=\"_blank\"><img src=\"https://opencollective.com/wukong-robot/sponsor/6/avatar.svg\"></a>\n<a href=\"https://opencollective.com/wukong-robot/sponsor/7/website\" target=\"_blank\"><img src=\"https://opencollective.com/wukong-robot/sponsor/7/avatar.svg\"></a>\n<a href=\"https://opencollective.com/wukong-robot/sponsor/8/website\" target=\"_blank\"><img src=\"https://opencollective.com/wukong-robot/sponsor/8/avatar.svg\"></a>\n<a href=\"https://opencollective.com/wukong-robot/sponsor/9/website\" target=\"_blank\"><img src=\"https://opencollective.com/wukong-robot/sponsor/9/avatar.svg\"></a>\n      </p>\n      <blockquote>\n        <p class=\"text-muted quote\">欢迎<a href=\"https://opencollective.com/wukong-robot/contribute/tier/8131-sponsor\" target=\"_blank\">成为这个项目的赞助商（sponsor）</a>，您将可以把一个带链接的 logo 放在 wukong-robot 后台管理端的首页、捐赠页面以及 Github 项目首页中。</p>\n      </blockquote>\n    </div>\n\n</div>\n\n<br/>\n\n<ul id=\"recorder\" class=\"mfb-component--br mfb-zoomin\" data-mfb-toggle=\"hover\">\n      <li class=\"mfb-component__wrap\">\n        <a href=\"#\" id=\"record\" class=\"mfb-component__button--main\">\n          <i class=\"mfb-component__main-icon--resting fa fa-microphone\"></i>\n          <i class=\"mfb-component__main-icon--active fa fa-times\"></i>\n        </a>\n        <ul class=\"mfb-component__list\">\n          <li>\n            <a href=\"#\" id=\"stop-record\" data-mfb-label=\"停止录制语音指令\" class=\"mfb-component__button--child\">\n              <i class=\"mfb-component__child-icon fas fa-stop\"></i>\n            </a>\n          </li>\n          <li>\n            <a href=\"#\" id=\"start-record\" data-mfb-label=\"开始录制语音指令\" class=\"mfb-component__button--child \">\n              <i class=\"mfb-component__child-icon fas fa-circle\"></i>\n            </a>\n          </li>\n        </ul>\n      </li>\n    </ul>\n\n\n<script src=\"./static/highlight.min.js\"></script>\n<script src=\"./static/markdown-it.min.js\"></script>\n<script src=\"{{static_url('main.js')}}\" crossorigin=\"anonymous\"></script>\n<script src=\"{{static_url('index.js')}}\" crossorigin=\"anonymous\"></script>\n<script src=\"./static/recorder.min.js\"></script>\n<script src=\"./static/progress.min.js\"></script>\n{% end %}\n"
  },
  {
    "path": "server/templates/layout.html",
    "content": "<!doctype html>\n<html lang=\"en\" class=\"h-100\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\n    <meta name=\"description\" content=\"\">\n    <meta name=\"author\" content=\"Joseph Pan\">\n    <meta name=\"generator\" content=\"Jekyll v3.8.5\">\n    <title>wukong-robot</title>\n\n    <!-- Bootstrap core CSS -->\n    <link rel=\"stylesheet\" href=\"https://use.fontawesome.com/releases/v5.6.3/css/all.css\" integrity=\"sha384-UHRtZLI+pbxtHCWp1t77Bi1L4ZtiqrqD80Kn4Z8NTSRyMA2Fd33n5dQ8lWUE00s/\" crossorigin=\"anonymous\">\n    <link rel=\"stylesheet\" href=\"./static/bootstrap.min.css\" integrity=\"sha384-GJzZqFGwb1QTTN6wy59ffF1BuGJpLSa9DkKMp0DgiMDm4iYMj70gZWKYbI706tWS\" crossorigin=\"anonymous\">\n    <link rel=\"stylesheet\" href=\"./static/toastr.min.css\" crossorigin=\"anonymous\">\n    <link href=\"./static/mfb.min.css\" rel=\"stylesheet\">\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"./static/jquery.fancybox.css\">\n    \n    <link rel=\"stylesheet\" href=\"{{static_url('spin.css')}}\" crossorigin=\"anonymous\">\n    <link href=\"./static/favicon.png\" rel='icon' type='image/x-icon'/>\n    <script src=\"./static/popper.min.js\" crossorigin=\"anonymous\"></script>\n    <script src=\"./static/jquery-3.3.1.min.js\" crossorigin=\"anonymous\"></script>\n    <script src=\"./static/jquery.fancybox.js\"></script>\n    \n\n    <style>\n      .bd-placeholder-img {\n          font-size: 1.125rem;\n          text-anchor: middle;\n      }\n\n      @media (min-width: 768px) {\n          .bd-placeholder-img-lg {\n              font-size: 3.5rem;\n          }\n      }\n    </style>\n    <!-- Custom styles for this template -->\n\n  </head>\n  <body>\n        {% block body %}\n        {% end %}\n        <div class=\"footer\">\n          <span class=\"mt-5 mb-3 text-muted\"><a href=\"http://github.com/wzpan/wukong-robot\" target=\"_blank\">wukong-robot</a> &copy; 2019 </span>\n        </div>\n\n        <script src=\"./static/modernizr.touch.js\"></script>\n        <script src=\"./static/mfb.min.js\"></script>\n        <script src=\"./static/toastr.min.js\" crossorigin=\"anonymous\"></script>\n        <script src=\"./static/bootstrap.min.js\" integrity=\"sha384-B0UglyR+jN6CkvvICOB2joaf5I4l3gm9GU6Hc1og6Ls7i6U/mkkaduKaBhlAXv9k\" crossorigin=\"anonymous\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "server/templates/log.html",
    "content": "{% extends \"layout.html\" %}\n{% block body %}\n<link rel=\"stylesheet\" href=\"{{static_url('starter-template.css')}}\" crossorigin=\"anonymous\">\n\n<nav class=\"navbar navbar-expand-md navbar-dark bg-dark fixed-top\">\n  <a class=\"navbar-brand\" href=\"/\">wukong-robot</a>\n  <button class=\"navbar-toggler\" type=\"button\" data-toggle=\"collapse\" data-target=\"#navbarsExampleDefault\" aria-controls=\"navbarsExampleDefault\" aria-expanded=\"false\" aria-label=\"Toggle navigation\">\n    <span class=\"navbar-toggler-icon\"></span>\n  </button>\n  <div class=\"collapse navbar-collapse\" id=\"navbarsExampleDefault\">\n    <ul class=\"navbar-nav mr-auto\">\n      <li class=\"nav-item\">\n        <a class=\"nav-link\" href=\"/\">会话</a>\n      </li>\n      <li class=\"nav-item\">\n        <a class=\"nav-link\" href=\"/configpage\">配置</a>\n      </li>\n      <li class=\"nav-item active\">\n        <a class=\"nav-link\" href=\"/logpage\">日志</a>\n      </li>\n      <li class=\"nav-item\">\n        <a class=\"nav-link\" href=\"/qa\">QA集</a>\n      </li>\n      <li class=\"nav-item\">\n        <a class=\"nav-link\" href=\"/api\">API</a>\n      </li>\n      <li class=\"nav-item\">\n        <a class=\"nav-link\" href=\"/donate\">捐赠</a>\n      </li>\n    </ul>\n    <div class=\"form-inline my-2 my-lg-0\">\n      <a class=\"btn btn-outline-success my-2 my-sm-0\" href=\"https://wukong.hahack.com\" target=\"_blank\">文档</a>\n    </div>\n  </div>\n</nav>\n\n<div class=\"container log\">\n  <div class=\"alert alert-info\" role=\"alert\">\n    <i class=\"fas fa-bell\"></i> 日志不会自动刷新，要查看最新日志，请点击【刷新日志】按钮。\n  </div>\n  <label for=\"config-form\">日志内容</label>\n  <form class=\"form log-form\" action=\"#\">\n    <div class=\"input-group\" id=\"container\">\n      <div class=\"input-group-prepend\">\n        <span class=\"input-group-text\">wukong.log</span>\n      </div>\n        <textarea rows=\"25\" class=\"form-control\" id=\"log-input\" placer='1' aria-label=\"wukong.log\" readonly></textarea>\n    </div>\n    <hr>\n    <center>\n    <button type=\"button\" class=\"btn btn-primary mb-2\" id=\"REFRESH\"><i class=\"fas fa-sync\"></i> 刷新日志</button>\n    </center>\n  </form>\n</div>\n\n\n<ul id=\"recorder\" class=\"mfb-component--br mfb-zoomin\" data-mfb-toggle=\"hover\">\n      <li class=\"mfb-component__wrap\">\n        <a href=\"#\" id=\"record\" class=\"mfb-component__button--main\">\n          <i class=\"mfb-component__main-icon--resting fa fa-microphone\"></i>\n          <i class=\"mfb-component__main-icon--active fa fa-times\"></i>\n        </a>\n        <ul class=\"mfb-component__list\">\n          <li>\n            <a href=\"#\" id=\"stop-record\" data-mfb-label=\"停止录制语音指令\" class=\"mfb-component__button--child\">\n              <i class=\"mfb-component__child-icon fas fa-stop\"></i>\n            </a>\n          </li>\n          <li>\n            <a href=\"#\" id=\"start-record\" data-mfb-label=\"开始录制语音指令\" class=\"mfb-component__button--child \">\n              <i class=\"mfb-component__child-icon fas fa-circle\"></i>\n            </a>\n          </li>\n        </ul>\n      </li>\n</ul>\n\n\n<script src=\"{{static_url('main.js')}}\" crossorigin=\"anonymous\"></script>\n<script src=\"{{static_url('log.js')}}\" crossorigin=\"anonymous\"></script>\n<script src=\"./static/recorder.min.js\"></script>\n{% end %}\n"
  },
  {
    "path": "server/templates/login.html",
    "content": "{% extends \"layout.html\" %}\n{% block body %}\n<link href=\"{{static_url('signin.css')}}\" rel=\"stylesheet\">\n  <div class=\"container\">\n  <form action=\"/login\" class=\"form-signin\" method=post>\n    {% module xsrf_form_html() %}\n    <center>\n      <h1 class=\"h3 mb-3 font-weight-normal\">Please login</h1>\n      <label for=\"username\" class=\"sr-only\">User Name</label>\n      <input type=\"text\" name=\"username\" class=\"form-control\" placeholder=\"User Name\" required autofocus>\n      <label for=\"password\" class=\"sr-only\">Password</label>\n      <input type=\"password\" name=\"password\" class=\"form-control\" placeholder=\"Password\" required>\n      <p><input class=\"btn btn-lg btn-primary btn-block\" type=submit value=Login></p>\n      {% if error %}\n      <p style=\"color:#ff0000\">{{ error }}</p>\n      {% end %}\n    </center>\n  </form>\n  </div>\n{% end %}\n"
  },
  {
    "path": "server/templates/qa.html",
    "content": "{% extends \"layout.html\" %}\n{% block body %}\n<link rel=\"stylesheet\" href=\"{{static_url('starter-template.css')}}\" crossorigin=\"anonymous\">\n<nav class=\"navbar navbar-expand-md navbar-dark bg-dark fixed-top\">\n  <a class=\"navbar-brand\" href=\"/\">wukong-robot</a>\n  <button class=\"navbar-toggler\" type=\"button\" data-toggle=\"collapse\" data-target=\"#navbarsExampleDefault\" aria-controls=\"navbarsExampleDefault\" aria-expanded=\"false\" aria-label=\"Toggle navigation\">\n    <span class=\"navbar-toggler-icon\"></span>\n  </button>\n  <div class=\"collapse navbar-collapse\" id=\"navbarsExampleDefault\">\n    <ul class=\"navbar-nav mr-auto\">\n      <li class=\"nav-item\">\n        <a class=\"nav-link\" href=\"/\">会话</a>\n      </li>\n      <li class=\"nav-item\">\n        <a class=\"nav-link\" href=\"/configpage\">配置</a>\n      </li>\n      <li class=\"nav-item\">\n        <a class=\"nav-link\" href=\"/logpage\">日志</a>\n      </li>\n      <li class=\"nav-item active\">\n        <a class=\"nav-link\" href=\"/qa\">QA集</a>\n      </li>\n      <li class=\"nav-item\">\n        <a class=\"nav-link\" href=\"/api\">API</a>\n      </li>\n      <li class=\"nav-item\">\n        <a class=\"nav-link\" href=\"/donate\">捐赠</a>\n      </li>\n    </ul>\n    <div class=\"form-inline my-2 my-lg-0\">\n    <a class=\"btn btn-outline-success my-2 my-sm-0\" href=\"https://wukong.hahack.com\" target=\"_blank\">文档</a>\n    </div>\n  </div>\n</nav>\n\n<div class=\"container api\">\n  <div class=\"alert alert-info\" role=\"alert\">\n    <i class=\"fas fa-bell\"></i> 本页面用于维护 wukong-robot 的 <a href=\"http://github.com/baidu/AnyQ\" target=\"_blank\">AnyQ</a> QA 数据集。在配置中将 <code>robot</code> 设为 <code>anyq</code> 后，将会优先选择本 QA 集。<br/>\n    <i class=\"fas fa-question\"></i> 要了解如何安装配置 AnyQ 以及编辑和贡献 QA 数据，可以查看<a href=\"https://wukong.hahack.com/#/anyq\" target=\"_blank\">这篇教程</a>。\n  </div>\n  <label for=\"qa-form\">数据集（请使用制表符 <code>TAB</code> 隔开问题和答案）</label>\n  <form class=\"form qa-form\" action=\"#\">\n    <div class=\"input-group\" id=\"container\">\n      <div class=\"input-group-prepend\">\n        <span class=\"input-group-text\">qa.csv</span>\n      </div>\n        <textarea rows=\"20\" class=\"form-control\" id=\"qa-input\" placer='1' aria-label=\"With textarea\">{% raw content %}</textarea>\n    </div>\n    <hr>\n    <center>\n      <button type=\"button\" class=\"btn btn-primary mb-2\" data-toggle=\"modal\" data-target=\"#uploadModal\"><i class=\"fas fa-upload\"></i> 提交</button>\n    </center>\n  </form>\n  \n</div>\n\n<div class=\"modal fade\" id=\"uploadModal\" tabindex=\"-1\" role=\"dialog\" aria-labelledby=\"restartModalLabel\" aria-hidden=\"true\">\n  <div class=\"modal-dialog\" role=\"document\">\n    <div class=\"modal-content\">\n      <div class=\"modal-header\">\n        <h5 class=\"modal-title\" id=\"restartModalLabel\">你确定吗？</h5>\n        <button type=\"button\" class=\"close\" data-dismiss=\"modal\" aria-label=\"Close\">\n          <span aria-hidden=\"true\">&times;</span>\n        </button>\n      </div>\n      <div class=\"modal-body\">\n        确定要覆盖现有的QA数据集吗？\n      </div>\n      <div class=\"modal-footer\">\n        <button type=\"button\" class=\"btn btn-secondary\" data-dismiss=\"modal\">只是手抖</button>\n        <button type=\"button\" class=\"btn btn-primary\" id=\"UPLOAD\" data-dismiss=\"modal\">确定</button>\n      </div>\n    </div>\n  </div>\n</div>\n\n\n<ul id=\"recorder\" class=\"mfb-component--br mfb-zoomin\" data-mfb-toggle=\"hover\">\n      <li class=\"mfb-component__wrap\">\n        <a href=\"#\" id=\"record\" class=\"mfb-component__button--main\">\n          <i class=\"mfb-component__main-icon--resting fa fa-microphone\"></i>\n          <i class=\"mfb-component__main-icon--active fa fa-times\"></i>\n        </a>\n        <ul class=\"mfb-component__list\">\n          <li>\n            <a href=\"#\" id=\"stop-record\" data-mfb-label=\"停止录制语音指令\" class=\"mfb-component__button--child\">\n              <i class=\"mfb-component__child-icon fas fa-stop\"></i>\n            </a>\n          </li>\n          <li>\n            <a href=\"#\" id=\"start-record\" data-mfb-label=\"开始录制语音指令\" class=\"mfb-component__button--child \">\n              <i class=\"mfb-component__child-icon fas fa-circle\"></i>\n            </a>\n          </li>\n        </ul>\n      </li>\n</ul>\n\n\n<script src=\"{{static_url('main.js')}}\" crossorigin=\"anonymous\"></script>\n<script src=\"{{static_url('log.js')}}\" crossorigin=\"anonymous\"></script>\n<script src=\"{{static_url('qa.js')}}\" crossorigin=\"anonymous\"></script>\n<script src=\"./static/recorder.min.js\"></script>\n{% end %}\n"
  },
  {
    "path": "snowboy/__init__.py",
    "content": ""
  },
  {
    "path": "snowboy/snowboydecoder.py",
    "content": "#!/usr/bin/env python\n\nimport collections\nimport pyaudio\nfrom . import snowboydetect\nfrom robot import utils, logging\nimport time\nimport wave\nimport os\nfrom ctypes import CFUNCTYPE, c_char_p, c_int, cdll\nfrom contextlib import contextmanager\nfrom robot import constants\n\n\nlogger = logging.getLogger(\"snowboy\")\nTOP_DIR = os.path.dirname(os.path.abspath(__file__))\n\nRESOURCE_FILE = os.path.join(TOP_DIR, \"resources/common.res\")\nDETECT_DING = os.path.join(TOP_DIR, \"resources/ding.wav\")\nDETECT_DONG = os.path.join(TOP_DIR, \"resources/dong.wav\")\n\n\ndef py_error_handler(filename, line, function, err, fmt):\n    pass\n\n\nERROR_HANDLER_FUNC = CFUNCTYPE(None, c_char_p, c_int, c_char_p, c_int, c_char_p)\n\nc_error_handler = ERROR_HANDLER_FUNC(py_error_handler)\n\n\n@contextmanager\ndef no_alsa_error():\n    try:\n        asound = cdll.LoadLibrary(\"libasound.so\")\n        asound.snd_lib_error_set_handler(c_error_handler)\n        yield\n        asound.snd_lib_error_set_handler(None)\n    except:\n        yield\n        pass\n\n\nclass RingBuffer(object):\n    \"\"\"Ring buffer to hold audio from PortAudio\"\"\"\n\n    def __init__(self, size=4096):\n        self._buf = collections.deque(maxlen=size)\n\n    def extend(self, data):\n        \"\"\"Adds data to the end of buffer\"\"\"\n        self._buf.extend(data)\n\n    def get(self):\n        \"\"\"Retrieves data from the beginning of buffer and clears it\"\"\"\n        tmp = bytes(bytearray(self._buf))\n        self._buf.clear()\n        return tmp\n\n\ndef play_audio_file(fname=DETECT_DING):\n    \"\"\"Simple callback function to play a wave file. By default it plays\n    a Ding sound.\n\n    :param str fname: wave file name\n    :return: None\n    \"\"\"\n    ding_wav = wave.open(fname, \"rb\")\n    ding_data = ding_wav.readframes(ding_wav.getnframes())\n    with no_alsa_error():\n        audio = pyaudio.PyAudio()\n    stream_out = audio.open(\n        format=audio.get_format_from_width(ding_wav.getsampwidth()),\n        channels=ding_wav.getnchannels(),\n        rate=ding_wav.getframerate(),\n        input=False,\n        output=True,\n    )\n    stream_out.start_stream()\n    stream_out.write(ding_data)\n    time.sleep(0.2)\n    stream_out.stop_stream()\n    stream_out.close()\n    audio.terminate()\n\n\nclass ActiveListener(object):\n    \"\"\"Active Listening with VAD\"\"\"\n\n    def __init__(self, decoder_model, resource=RESOURCE_FILE):\n        logger.debug(\"activeListen __init__()\")\n        self.recordedData = []\n        model_str = \",\".join(decoder_model)\n        self.detector = snowboydetect.SnowboyDetect(\n            resource_filename=resource.encode(), model_str=model_str.encode()\n        )\n        self.ring_buffer = RingBuffer(\n            self.detector.NumChannels() * self.detector.SampleRate() * 5\n        )\n\n    def listen(\n        self,\n        interrupt_check=lambda: False,\n        sleep_time=0.03,\n        silent_count_threshold=15,\n        recording_timeout=100,\n    ):\n        \"\"\"\n        :param interrupt_check: a function that returns True if the main loop\n                                needs to stop.\n        :param silent_count_threshold: indicates how long silence must be heard\n                                       to mark the end of a phrase that is\n                                       being recorded.\n        :param float sleep_time: how much time in second every loop waits.\n        :param recording_timeout: limits the maximum length of a recording.\n        :return: recorded file path\n        \"\"\"\n        logger.debug(\"activeListen listen()\")\n\n        self._running = True\n\n        def audio_callback(in_data, frame_count, time_info, status):\n            self.ring_buffer.extend(in_data)\n            play_data = chr(0) * len(in_data)\n            return play_data, pyaudio.paContinue\n\n        with no_alsa_error():\n            self.audio = pyaudio.PyAudio()\n\n        logger.debug(\"opening audio stream\")\n\n        try:\n            self.stream_in = self.audio.open(\n                input=True,\n                output=False,\n                format=self.audio.get_format_from_width(\n                    self.detector.BitsPerSample() / 8\n                ),\n                channels=self.detector.NumChannels(),\n                rate=self.detector.SampleRate(),\n                frames_per_buffer=2048,\n                stream_callback=audio_callback,\n            )\n        except Exception as e:\n            logger.critical(e, stack_info=True)\n            return\n\n        logger.debug(\"audio stream opened\")\n\n        if interrupt_check():\n            logger.debug(\"detect voice return\")\n            return\n\n        silentCount = 0\n        recordingCount = 0\n\n        logger.debug(\"begin activeListen loop\")\n\n        while self._running is True:\n\n            if interrupt_check():\n                logger.debug(\"detect voice break\")\n                break\n            data = self.ring_buffer.get()\n            if len(data) == 0:\n                time.sleep(sleep_time)\n                continue\n\n            status = self.detector.RunDetection(data)\n            if status == -1:\n                logger.warning(\"Error initializing streams or reading audio data\")\n\n            stopRecording = False\n            if recordingCount > recording_timeout:\n                stopRecording = True\n            elif status == -2:  # silence found\n                if silentCount > silent_count_threshold:\n                    stopRecording = True\n                else:\n                    silentCount = silentCount + 1\n            elif status == 0:  # voice found\n                silentCount = 0\n\n            if stopRecording == True:\n                return self.saveMessage()\n\n            recordingCount = recordingCount + 1\n            self.recordedData.append(data)\n\n        logger.debug(\"finished.\")\n\n    def saveMessage(self):\n        \"\"\"\n        Save the message stored in self.recordedData to a timestamped file.\n        \"\"\"\n        filename = os.path.join(\n            constants.TEMP_PATH, \"output\" + str(int(time.time())) + \".wav\"\n        )\n        data = b\"\".join(self.recordedData)\n\n        # use wave to save data\n        wf = wave.open(filename, \"wb\")\n        wf.setnchannels(self.detector.NumChannels())\n        wf.setsampwidth(\n            self.audio.get_sample_size(\n                self.audio.get_format_from_width(self.detector.BitsPerSample() / 8)\n            )\n        )\n        wf.setframerate(self.detector.SampleRate())\n        wf.writeframes(data)\n        wf.close()\n        logger.debug(\"finished saving: \" + filename)\n\n        self.stream_in.stop_stream()\n        self.stream_in.close()\n        self.audio.terminate()\n\n        return filename\n\n\nclass HotwordDetector(object):\n    \"\"\"\n    Snowboy decoder to detect whether a keyword specified by `decoder_model`\n    exists in a microphone input stream.\n\n    :param decoder_model: decoder model file path, a string or a list of strings\n    :param resource: resource file path.\n    :param sensitivity: decoder sensitivity, a float of a list of floats.\n                              The bigger the value, the more senstive the\n                              decoder. If an empty list is provided, then the\n                              default sensitivity in the model will be used.\n    :param audio_gain: multiply input volume by this factor.\n    :param apply_frontend: applies the frontend processing algorithm if True.\n    \"\"\"\n\n    def __init__(\n        self,\n        decoder_model,\n        resource=RESOURCE_FILE,\n        sensitivity=[],\n        audio_gain=1,\n        apply_frontend=False,\n    ):\n\n        self._running = False\n\n        tm = type(decoder_model)\n        ts = type(sensitivity)\n        if tm is not list:\n            decoder_model = [decoder_model]\n        if ts is not list:\n            sensitivity = [sensitivity]\n        model_str = \",\".join(decoder_model)\n\n        self.detector = snowboydetect.SnowboyDetect(\n            resource_filename=resource.encode(), model_str=model_str.encode()\n        )\n        self.detector.SetAudioGain(audio_gain)\n        self.detector.ApplyFrontend(apply_frontend)\n        self.num_hotwords = self.detector.NumHotwords()\n\n        if len(decoder_model) > 1 and len(sensitivity) == 1:\n            sensitivity = sensitivity * self.num_hotwords\n        if len(sensitivity) != 0:\n            assert self.num_hotwords == len(sensitivity), (\n                \"number of hotwords in decoder_model (%d) and sensitivity \"\n                \"(%d) does not match\" % (self.num_hotwords, len(sensitivity))\n            )\n        sensitivity_str = \",\".join([str(t) for t in sensitivity])\n        if len(sensitivity) != 0:\n            self.detector.SetSensitivity(sensitivity_str.encode())\n\n        self.ring_buffer = RingBuffer(\n            self.detector.NumChannels() * self.detector.SampleRate() * 5\n        )\n\n    def start(\n        self,\n        detected_callback=play_audio_file,\n        interrupt_check=lambda: False,\n        sleep_time=0.03,\n        audio_recorder_callback=None,\n        silent_count_threshold=15,\n        recording_timeout=100,\n    ):\n        \"\"\"\n        Start the voice detector. For every `sleep_time` second it checks the\n        audio buffer for triggering keywords. If detected, then call\n        corresponding function in `detected_callback`, which can be a single\n        function (single model) or a list of callback functions (multiple\n        models). Every loop it also calls `interrupt_check` -- if it returns\n        True, then breaks from the loop and return.\n\n        :param detected_callback: a function or list of functions. The number of\n                                  items must match the number of models in\n                                  `decoder_model`.\n        :param interrupt_check: a function that returns True if the main loop\n                                needs to stop.\n        :param float sleep_time: how much time in second every loop waits.\n        :param audio_recorder_callback: if specified, this will be called after\n                                        a keyword has been spoken and after the\n                                        phrase immediately after the keyword has\n                                        been recorded. The function will be\n                                        passed the name of the file where the\n                                        phrase was recorded.\n        :param silent_count_threshold: indicates how long silence must be heard\n                                       to mark the end of a phrase that is\n                                       being recorded.\n        :param recording_timeout: limits the maximum length of a recording.\n        :return: None\n        \"\"\"\n        self._running = True\n\n        def audio_callback(in_data, frame_count, time_info, status):\n            if utils.isRecordable():\n                self.ring_buffer.extend(in_data)\n                play_data = chr(0) * len(in_data)\n            else:\n                play_data = chr(0)\n            return play_data, pyaudio.paContinue\n\n        with no_alsa_error():\n            self.audio = pyaudio.PyAudio()\n        self.stream_in = self.audio.open(\n            input=True,\n            output=False,\n            format=self.audio.get_format_from_width(self.detector.BitsPerSample() / 8),\n            channels=self.detector.NumChannels(),\n            rate=self.detector.SampleRate(),\n            frames_per_buffer=2048,\n            stream_callback=audio_callback,\n        )\n\n        if interrupt_check():\n            logger.debug(\"detect voice return\")\n            return\n\n        tc = type(detected_callback)\n        if tc is not list:\n            detected_callback = [detected_callback]\n        if len(detected_callback) == 1 and self.num_hotwords > 1:\n            detected_callback *= self.num_hotwords\n\n        assert self.num_hotwords == len(detected_callback), (\n            \"Error: hotwords in your models (%d) do not match the number of \"\n            \"callbacks (%d)\" % (self.num_hotwords, len(detected_callback))\n        )\n\n        logger.debug(\"detecting...\")\n\n        state = \"PASSIVE\"\n        while self._running is True:\n            if interrupt_check():\n                logger.debug(\"detect voice break\")\n                break\n            data = self.ring_buffer.get()\n            if len(data) == 0:\n                time.sleep(sleep_time)\n                continue\n\n            status = self.detector.RunDetection(data)\n            if status == -1:\n                logger.warning(\"Error initializing streams or reading audio data\")\n\n            # small state machine to handle recording of phrase after keyword\n            if state == \"PASSIVE\":\n                if status > 0:  # key word found\n\n                    self.recordedData = []\n                    self.recordedData.append(data)\n                    silentCount = 0\n                    recordingCount = 0\n                    message = \"Keyword \" + str(status) + \" detected at time: \"\n                    message += time.strftime(\n                        \"%Y-%m-%d %H:%M:%S\", time.localtime(time.time())\n                    )\n                    logger.info(message)\n                    callback = detected_callback[status - 1]\n                    callback and callback()\n\n                    if (\n                        audio_recorder_callback\n                        and status == 1\n                        and utils.is_proper_time()\n                    ):\n                        state = \"ACTIVE\"\n                    continue\n\n            elif state == \"ACTIVE\":\n                stopRecording = False\n                if recordingCount > recording_timeout:\n                    stopRecording = True\n                elif status == -2:  # silence found\n                    if silentCount > silent_count_threshold:\n                        stopRecording = True\n                    else:\n                        silentCount = silentCount + 1\n                elif status == 0:  # voice found\n                    silentCount = 0\n\n                if stopRecording == True:\n                    fname = self.saveMessage()\n                    audio_recorder_callback(fname)\n                    state = \"PASSIVE\"\n                    continue\n\n                recordingCount = recordingCount + 1\n                self.recordedData.append(data)\n\n        logger.debug(\"finished.\")\n\n    def saveMessage(self):\n        \"\"\"\n        Save the message stored in self.recordedData to a timestamped file.\n        \"\"\"\n        filename = os.path.join(\n            constants.TEMP_PATH, \"output\" + str(int(time.time())) + \".wav\"\n        )\n        data = b\"\".join(self.recordedData)\n\n        # use wave to save data\n        wf = wave.open(filename, \"wb\")\n        wf.setnchannels(self.detector.NumChannels())\n        wf.setsampwidth(\n            self.audio.get_sample_size(\n                self.audio.get_format_from_width(self.detector.BitsPerSample() / 8)\n            )\n        )\n        wf.setframerate(self.detector.SampleRate())\n        wf.writeframes(data)\n        wf.close()\n        logger.debug(\"finished saving: \" + filename)\n        return filename\n\n    def terminate(self):\n        \"\"\"\n        Terminate audio stream. Users can call start() again to detect.\n        :return: None\n        \"\"\"\n        if self._running:\n            self.stream_in.stop_stream()\n            self.stream_in.close()\n            self.audio.terminate()\n            self._running = False\n"
  },
  {
    "path": "snowboy/snowboydetect.py",
    "content": "# This file was automatically generated by SWIG (http://www.swig.org).\n# Version 3.0.12\n#\n# Do not make changes to this file unless you know what you are doing--modify\n# the SWIG interface file instead.\n\nfrom sys import version_info as _swig_python_version_info\n\nif _swig_python_version_info >= (2, 7, 0):\n\n    def swig_import_helper():\n        import importlib\n\n        pkg = __name__.rpartition(\".\")[0]\n        mname = \".\".join((pkg, \"_snowboydetect\")).lstrip(\".\")\n        try:\n            return importlib.import_module(mname)\n        except ImportError:\n            return importlib.import_module(\"_snowboydetect\")\n\n    _snowboydetect = swig_import_helper()\n    del swig_import_helper\nelif _swig_python_version_info >= (2, 6, 0):\n\n    def swig_import_helper():\n        from os.path import dirname\n        import imp\n\n        fp = None\n        try:\n            fp, pathname, description = imp.find_module(\n                \"_snowboydetect\", [dirname(__file__)]\n            )\n        except ImportError:\n            import _snowboydetect\n\n            return _snowboydetect\n        try:\n            _mod = imp.load_module(\"_snowboydetect\", fp, pathname, description)\n        finally:\n            fp and fp.close()\n        return _mod\n\n    _snowboydetect = swig_import_helper()\n    del swig_import_helper\nelse:\n    import _snowboydetect\ndel _swig_python_version_info\n\ntry:\n    _swig_property = property\nexcept NameError:\n    pass  # Python < 2.2 doesn't have 'property'.\n\ntry:\n    import builtins as __builtin__\nexcept ImportError:\n    import __builtin__\n\n\ndef _swig_setattr_nondynamic(self, class_type, name, value, static=1):\n    if name == \"thisown\":\n        return self.this.own(value)\n    if name == \"this\":\n        if type(value).__name__ == \"SwigPyObject\":\n            self.__dict__[name] = value\n            return\n    method = class_type.__swig_setmethods__.get(name, None)\n    if method:\n        return method(self, value)\n    if not static:\n        if _newclass:\n            object.__setattr__(self, name, value)\n        else:\n            self.__dict__[name] = value\n    else:\n        raise AttributeError(\"You cannot add attributes to %s\" % self)\n\n\ndef _swig_setattr(self, class_type, name, value):\n    return _swig_setattr_nondynamic(self, class_type, name, value, 0)\n\n\ndef _swig_getattr(self, class_type, name):\n    if name == \"thisown\":\n        return self.this.own()\n    method = class_type.__swig_getmethods__.get(name, None)\n    if method:\n        return method(self)\n    raise AttributeError(\n        \"'%s' object has no attribute '%s'\" % (class_type.__name__, name)\n    )\n\n\ndef _swig_repr(self):\n    try:\n        strthis = \"proxy of \" + self.this.__repr__()\n    except __builtin__.Exception:\n        strthis = \"\"\n    return \"<%s.%s; %s >\" % (\n        self.__class__.__module__,\n        self.__class__.__name__,\n        strthis,\n    )\n\n\ntry:\n    _object = object\n    _newclass = 1\nexcept __builtin__.Exception:\n\n    class _object:\n        pass\n\n    _newclass = 0\n\n\nclass SnowboyDetect(_object):\n    __swig_setmethods__ = {}\n    __setattr__ = lambda self, name, value: _swig_setattr(\n        self, SnowboyDetect, name, value\n    )\n    __swig_getmethods__ = {}\n    __getattr__ = lambda self, name: _swig_getattr(self, SnowboyDetect, name)\n    __repr__ = _swig_repr\n\n    def __init__(self, resource_filename, model_str):\n        this = _snowboydetect.new_SnowboyDetect(resource_filename, model_str)\n        try:\n            self.this.append(this)\n        except __builtin__.Exception:\n            self.this = this\n\n    def Reset(self):\n        return _snowboydetect.SnowboyDetect_Reset(self)\n\n    def RunDetection(self, *args):\n        return _snowboydetect.SnowboyDetect_RunDetection(self, *args)\n\n    def SetSensitivity(self, sensitivity_str):\n        return _snowboydetect.SnowboyDetect_SetSensitivity(self, sensitivity_str)\n\n    def SetHighSensitivity(self, high_sensitivity_str):\n        return _snowboydetect.SnowboyDetect_SetHighSensitivity(\n            self, high_sensitivity_str\n        )\n\n    def GetSensitivity(self):\n        return _snowboydetect.SnowboyDetect_GetSensitivity(self)\n\n    def SetAudioGain(self, audio_gain):\n        return _snowboydetect.SnowboyDetect_SetAudioGain(self, audio_gain)\n\n    def UpdateModel(self):\n        return _snowboydetect.SnowboyDetect_UpdateModel(self)\n\n    def NumHotwords(self):\n        return _snowboydetect.SnowboyDetect_NumHotwords(self)\n\n    def ApplyFrontend(self, apply_frontend):\n        return _snowboydetect.SnowboyDetect_ApplyFrontend(self, apply_frontend)\n\n    def SampleRate(self):\n        return _snowboydetect.SnowboyDetect_SampleRate(self)\n\n    def NumChannels(self):\n        return _snowboydetect.SnowboyDetect_NumChannels(self)\n\n    def BitsPerSample(self):\n        return _snowboydetect.SnowboyDetect_BitsPerSample(self)\n\n    __swig_destroy__ = _snowboydetect.delete_SnowboyDetect\n    __del__ = lambda self: None\n\n\nSnowboyDetect_swigregister = _snowboydetect.SnowboyDetect_swigregister\nSnowboyDetect_swigregister(SnowboyDetect)\n\n\nclass SnowboyVad(_object):\n    __swig_setmethods__ = {}\n    __setattr__ = lambda self, name, value: _swig_setattr(self, SnowboyVad, name, value)\n    __swig_getmethods__ = {}\n    __getattr__ = lambda self, name: _swig_getattr(self, SnowboyVad, name)\n    __repr__ = _swig_repr\n\n    def __init__(self, resource_filename):\n        this = _snowboydetect.new_SnowboyVad(resource_filename)\n        try:\n            self.this.append(this)\n        except __builtin__.Exception:\n            self.this = this\n\n    def Reset(self):\n        return _snowboydetect.SnowboyVad_Reset(self)\n\n    def RunVad(self, *args):\n        return _snowboydetect.SnowboyVad_RunVad(self, *args)\n\n    def SetAudioGain(self, audio_gain):\n        return _snowboydetect.SnowboyVad_SetAudioGain(self, audio_gain)\n\n    def ApplyFrontend(self, apply_frontend):\n        return _snowboydetect.SnowboyVad_ApplyFrontend(self, apply_frontend)\n\n    def SampleRate(self):\n        return _snowboydetect.SnowboyVad_SampleRate(self)\n\n    def NumChannels(self):\n        return _snowboydetect.SnowboyVad_NumChannels(self)\n\n    def BitsPerSample(self):\n        return _snowboydetect.SnowboyVad_BitsPerSample(self)\n\n    __swig_destroy__ = _snowboydetect.delete_SnowboyVad\n    __del__ = lambda self: None\n\n\nSnowboyVad_swigregister = _snowboydetect.SnowboyVad_swigregister\nSnowboyVad_swigregister(SnowboyVad)\n\n# This file is compatible with both classic and new-style classes.\n"
  },
  {
    "path": "static/default.yml",
    "content": "robot_name_cn: '孙悟空'\nfirst_name: '师父'\nlast_name: '唐'\ntimezone: HKT\nlocation: '深圳'\n\n# 后台管理端\nserver:\n    enable: true\n    host: '0.0.0.0'  # ip 地址\n    port: '5001'     # 端口号\n    username: 'wukong'  # 用户名\n    # cookie 的 secret ，用于对 cookie 的内容进行加密及防止篡改\n    # 建议使用 os.urandom(24) 生成一串随机字符串\n    # 强烈建议修改!!!\n    cookie_secret: '__GENERATE_YOUR_OWN_RANDOM_VALUE_HERE__'\n    # 密码的 md5，可以用 python3 wukong.py md5 \"密码\" 获得\n    # 初始密码为 wukong@2019\n    # 强烈建议修改!!!\n    validate: 'f4bde2a342c7c75aa276f78b26cfbd8a'\n\n# 热词唤醒机制\n# 可选值：\n# porcupine\n# snowboy\ndetector: porcupine\n# 灵敏度\nsensitivity: 0.5\n\n# porcupine 离线唤醒\n# 登录 https://console.picovoice.ai/\n# 可以获取 access_key 和训练自己的唤醒词\nporcupine: \n    keywords:\n        - 'porcupine'\n        - 'hello bing'\n    keyword_paths:\n        # 支持追加多个唤醒词\n        # 自定义唤醒词请放到 $HOME/.wukong 目录中\n        # - 'spiderman.ppn'\n        - 'hello-bing_en_raspberry-pi_v3_0_0.ppn'\n    access_key: ''\n\n# snowboy 离线唤醒\n# 建议使用 snowboy-seasalt (https://github.com/rhasspy/snowboy-seasalt)\n# 使用相同环境录入你的语音，以提升唤醒成功率和准确率\nhotword: 'snowboy.umdl'  # 唤醒词模型，如要自定义请放到 $HOME/.wukong 目录中\nsilent_threshold: 20 # 判断为静音的阈值。环境比较吵杂的地方可以适当调大\nrecording_timeout: 15 # 录制的语音最大长度（秒）\nsnowboy_token: your_token # 你的token，用于 train 命令训练语音\n\n# Muse 脑机\n# 推荐搭配 Muse Monitor 使用\n# 并开启 OSC stream\n# 同时眨眼和咬牙齿可以实现唤醒\nmuse:\n    enable: false\n    ip: '0.0.0.0'  # 请修改为本机的 ip 地址\n    port: 5001     # 请修改为 OSC 的端口号\n\n# 行空板\n# 需搭配行空板使用\n# 展示专为行空板设计的 GUI\n# 摇一摇可以实现唤醒 \n# https://www.unihiker.com/\nunihiker:\n    enable: false\n    beep: false # 是否需要开启主板的蜂鸣提示音\n\n# 是否展示灯光效果\n# 支持 Respeaker 2 Mics 和 Google AIY Voice Kit 两种\n# 必须具备相应的硬件和驱动\nLED:\n    enable: false\n    type: aiy  # aiy: Google AIY Voice Kit; respeaker：respeaker 2Mics\n\n# 勿扰模式，该时间段内自动进入睡眠，避免监听\ndo_not_bother:\n    enable: false # true: 开启; false: 关闭\n    since: 23    # 开始时间\n    till: 9      # 结束时间，如果比 since 小表示第二天\n\n# 提醒功能\nreminder:\n    repeat: 3  # 语音重复次数\n\n# 是否定期清理temp目录下的缓存音频\nlru_cache:\n    enable: true # true: 开启; false: 关闭\n    days: 7 # 清理超过多少天没有使用的文件\n\n# 语音合成服务配置\n# 可选值：\n# han-tts        - HanTTS\n# baidu-tts      - 百度语音合成\n# xunfei-tts     - 讯飞语音合成\n# ali-tts        - 阿里语音合成\n# tencent-tts    - 腾讯云语音合成\n# azure-tts      - 微软语音合成\n# mac-tts        - macOS 系统自带TTS（mac 系统推荐）\n# edge-tts       - 基于 Edge 的 TTS（推荐）\n# VITS           - 基于 VITS 的AI语音合成\n# volcengine-tts - 火山引擎语音合成\ntts_engine: edge-tts\n\n# 语音识别服务配置\n# 可选值：\n# baidu-asr      - 百度在线语音识别\n# xunfei-asr     - 讯飞语音识别\n# ali-asr        - 阿里语音识别\n# tencent-asr    - 腾讯云语音识别（推荐）\n# azure-asr      - 微软语音识别\n# openai         - OpenAI Whisper\n# fun-asr        - 达摩院FunASR语音识别\n# volcengine-asr - 火山引擎语音识别\nasr_engine: baidu-asr\n\n# 百度语音服务\n# http://yuyin.baidu.com/\n# 有免费额度限制，请使用自己的百度智能云账户\nbaidu_yuyin:\n    appid: 'YOUR_APPID'\n    api_key: 'YOUR_API_KEY'\n    secret_key: 'YOUR_SECRET_KEY'\n    dev_pid: 1536   # 1536：普通话(支持简单的英文识别)，\n                    # 1936: 普通话远场（需付费，请使用自己的百度语音账户再使用）\n                    # 80001：ASR极速版（需付费，请使用自己的百度语音账户再使用）\n    per: 1  # 发音人选择 0：女生；1：男生；3：度逍遥；4：度丫丫\n    lan: 'zh'\n\n\n# 讯飞语音服务\n# appid 及 api_key 需前往\n# https://xfyun.cn/\n# 注册创建是WebAPI应用，并赋予流式语音听写及在线语音合成两项能力\n# 有免费额度限制，请使用自己的讯飞云账户\nxunfei_yuyin:\n    appid: 'YOUR_APPID'\n    api_secret: 'YOUR_API_SECRET'\n    api_key: 'YOUR_API_KEY'\n    voice: 'xiaoyan'  # 全部可选：https://console.xfyun.cn/services/tts\n\n# 阿里云语音\n# appKey及token需前往\n# https://ai.aliyun.com/nls\n# 注册获取\n# 有免费额度限制，且需要认证为阿里企业账户\nali_yuyin:\n    appKey: 'YOUR_APPKEY'\n    token: 'YOUR_TOKEN'\n    voice: 'xiaogang' #xiaoyun为女生，xiaogang为男生, 全部可选：http://suo.im/4x8RzQ\n\n# 腾讯云语音\n# 先前往 https://cloud.tencent.com\n# 注册语音识别和语音合成服务，获得 appid ，然后在访问管理\n# https://console.cloud.tencent.com/cam\n# 创建子用户，访问API密钥获得 secretid 和 secret_key 注册获取\n# 有免费额度限制，请使用自己的腾讯云账户\ntencent_yuyin:\n    appid: 'YOUR_APPID'\n    secretid: 'YOUR_SECRET_ID'\n    secret_key: 'YOUR_SECRET_KEY'\n    region: 'ap-guangzhou'  # 服务地区，有效值：http://suo.im/4EEQYD\n    voiceType: 0            # 0: 女声1；1：男生1；2：男生2\n    language: 1             # 1: 中文；2：英文\n\nvolcengine-asr:\n    # 在官网https://www.volcengine.com/ 语音技术申请，有免费额度\n    appid: ''\n    token: ''\n    cluster: ''\n\n\n# 达摩院FunASR实时语音转写服务软件包\nfun_asr:\n    # 导出模型流程：https://github.com/alibaba-damo-academy/FunASR/tree/main/funasr/runtime/python/libtorch#export-the-model\n    # 1.安装导出模型的必要依赖项\n    # pip install -U modelscope funasr\n    # pip install torch-quant \n    # pip install onnx onnxruntime \n    # 2.导出模型权重\n    # python -m funasr.export.export_model --model-name damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch --export-dir ./export --type torch --quantize True\n    # 3.需要注意\n    # 当前使用的onnxruntime的推理方案，第一次初始化需要推理框架内部会将模型参数文件转换为onnx格式文件，大约需要5分钟\n    # 从第二次载入时，识别框架初始，载入模型约需要等待20秒左右\n    inference_type: onnxruntime # FunASR支持本地onnxruntime，libtorch推理框架，以及client-server方式，当前只实现了onnxruntime方式，相对部署流程较为简单\n    model_dir: '/xxxxxxxxxxxxxxxxxxx/export/damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch' # 上述流程导出的模型的模型文件的绝对路径\n\n\n# HanTTS 服务\nhan-tts:\n    # 所使用的语音库目录\n    # 需放在 ~/.wukong/ 目录下\n    # 也支持自行录制，详见：\n    # https://github.com/junzew/HanTTS\n    voice: 'syllables' \n\n# macOS 自带的 TTS 服务\n# 注意：仅 macOS 系统可用！\nmac-tts:\n    # 命令行执行 say -v '?' 可以打印所有音色\n    # 中文推荐 Tingting（普通话）或者 Sinji（粤语）\n    voice: Tingting\n\n# 基于 edge 浏览器的在线 TTS 服务\nedge-tts:\n    # 命令行执行 edge-tts --list-voices 可以打印所有音色\n    # 中文推荐 `zh` 开头的音色\n    voice: zh-CN-XiaoxiaoNeural\n\n# 火山引擎TTS服务\nvolcengine-tts:\n    # 在官网https://www.volcengine.com/ 语音技术申请，有免费额度\n    # 音色列表voice_type有几十种，链接在https://www.volcengine.com/docs/6561/97465\n    # 免费额度QPS限制2，需要设置tts_parallel=2\n    appid: \"\"\n    token: \"\"\n    cluster: \"\"\n    voice_type: \"\"\n\n# 基于 VITS 的AI语音合成\nVITS:\n    # 需要自行搭建vits-simple-api服务器：https://github.com/Artrajz/vits-simple-api\n    #    server_url: 服务器url（格式为http://{IP地址}:{端口}，不带最后的斜杠），如http://127.0.0.1:23456\n    #    api_key: 若服务器配置了API Key，在此填入\n    #    speaker_id: 说话人ID，由所使用的模型决定\n    #    length: 调节语音长度，相当于调节语速，该数值越大语速越慢。\n    #    noise: 噪声\n    #    noisew: 噪声偏差\n    #    max: 分段阈值，按标点符号分段，加起来大于max时为一段文本。max<=0表示不分段。\n    #    timeout: 响应超时时间（秒），根据vits-simple-api服务器性能不同配置合理的超时时间。\n    server_url: \"http://127.0.0.1:23456\"\n    api_key: \"api_key\"\n    speaker_id: 0\n    length: 1.0\n    noise: 0.667\n    noisew: 0.8\n    max: 50\n    timeout: 60\n\n# NLU 引擎\n# 可选值：\n# unit      - 百度 UNIT\nnlu_engine: unit\n\n# 聊天机器人\n# 可选值：\n# unit      - 百度UNIT（推荐）\n# openai    - OpenAI ChatGPT\n# anyq      - AnyQ\n# tuling    - 图灵机器人\nrobot: bing\n\n\n# 必应 bing\nbing:\n    prefix: \"\n      # 角色: 语音化必应智能音箱\n      ## 目标\n      - 您是一个语音化智能音箱，具备配合其他模块将你输出的文字转换为语音的能力。\n      ## 约束\n      - 您的回复必须以口语化的形式呈现，不能包含任何链接、emoji表情、图片、网站推荐以及其他形式的书面语言。\n      - 请避免涉及到代码、图片生成等专业性的工作场景内容。\n      ## 技能\n      - 百科问答技能: 您可以解答各种百科性的问题，进行科普教育。\n      - 咨询服务技能: 您可以接受各领域的咨询，为用户提供一对一的解答服务。\n      - 常见智能音箱功能: 您还能讲笑话、阅读短新闻，提供今日头条、热点等信息。\n      - 闲聊: 倾听倾诉给予建议\"\n\n    proxy: \"http://127.0.0.1:7890\"\n    # creative, balanced, precise\n    mode: \"creative\"\n\n# 百度 UNIT\nunit:\n    # 在 https://ai.baidu.com/unit 里注册创建一个机器人\n    # 得到一个机器人 ID ，\n    # 然后访问下面页面获取 API Key 和 Secret Key：\n    # https://console.bce.baidu.com/ai/#/ai/unit/app/list\n    service_id: 'S13442'  # 机器人ID\n    api_key: 'w5v7gUV3iPGsGntcM84PtOOM'\n    secret_key: 'KffXwW6E1alcGplcabcNs63Li6GvvnfL'\n\n# AnyQ 机器人\nanyq:\n    host: 0.0.0.0\n    port: 8999\n    solr_port: 8900  # solr 的端口号\n    # 置信度（confidence）需达到的阈值，\n    # 达不到就认为不命中\n    threshold: 0.6\n    # 如果没有命中，使用其他兜底的机器人\n    # 如果不想使用兜底，可以设为 null\n    secondary: tuling\n\n# 图灵机器人\t\n# http://www.tuling123.com\ntuling:\n    tuling_key: '98f95153fb5c4684a5602b909949ba61'  # 建议使用自己的图灵机器人API Key\n\n# OpenAI(ChatGPT) 机器人\n# 使用科学上网工具到 https://platform.openai.com\n# 注册一个账号，获得 openai_api_key 后填到下面的配置中即可\nopenai:\n    openai_api_key: 'sk-xxxxxxxxxxxxxxxxxxxxxxxxxx'\n    provider: 'azure' # openai的接口填写openai, azure的填写azure\n    api_version: '2023-05-15' # 如果是openai的，留空就行，azure的需填写对应的api_version，参考官方文档\n    # 参数指定将生成文本的模型类型。目前支持 gpt-3.5-turbo 和 gpt-3.5-turbo-0301 两种选择\n    model: 'gpt-3.5-turbo'\n    # 在前面加的一段前缀\n    prefix: '请用200字回答：'\n    # 该temperature参数可以设置返回内容地多样性。值越大意味着该模型更有可能产生创造性的东西，设置为 1 意味着模型将返回它不确定的结果；相比之下，将此参数设置为 0 意味着模型将返回它几乎可以肯定的结果。\n    temperature: 1\n    # 该max_tokens参数指定模型允许生成的最大字符数量作为其输出的一部分。您需要为生成的更多字符付费，因此请务必小心使用此参数。\n    max_tokens: 2000\n    # 一个可用于代替 temperature 的参数，对应机器学习中 nucleus sampling，如果设置 0.1 意味着只考虑构成前 10% 概率质量的 tokens\n    top_p: 1.0\n    # -2.0 ~ 2.0 之间的数字，正值会根据新 tokens 在文本中的现有频率对其进行惩罚，从而降低模型逐字重复同一行的可能性\n    frequency_penalty: 0.0\n    # -2.0 ~ 2.0 之间的数字，正值会根据到目前为止是否出现在文本中来惩罚新 tokens，从而增加模型谈论新主题的可能性\n    presence_penalty: 0.0\n    stop_ai: 'stop'\n    # 如果需要代理，反注释下面的配置进行修改\n    # proxy: '127.0.0.1:1080'\n    # 如果需要更换 api_base ，反注释下面的配置进行修改\n    # api_base: \"https://api.openai.com/v1/chat\"\n\n\n# 邮箱\n# 如果使用网易邮箱，还需设置允许第三方客户端收发邮件\nemail:\n    enable: true\n    address: '你的邮箱地址'\n    password: '你的邮箱密码'  # 如果是网易邮箱，须填写应用授权密码而不是登录密码！\n    smtp_server: 'smtp.163.com'\n    smtp_port: '25'  # 这里填写非SSL协议端口号\n    imap_server: 'imap.163.com'\n    imap_port: '143'  # 这里填写非SSL协议端口号    \n    read_email_title: true  # 当有邮件时，是否朗读邮件标题\n\n# 拍照\n# 需接入摄像头才能使用\ncamera:\n    enable: false\n    type: 0                 # 摄像头类型 0：usb_camera，1：树莓派 5MP 摄像头，2：Mac OSX 摄像头\n                            # 对于 Mac OSX 摄像头，请先安装 imagesnap 。例如 Mac OSX： brew install imagesnap\n    dest_path: \"/Users/panweizhou/Pictures/\" # 保存目录\n    quality: 5              # 成像质量（0~100），不支持 imagesnap\n    vertical_flip: true     # 竖直翻转，不支持 imagesnap\n    horizontal_flip: false  # 水平翻转，不支持 imagesnap\n    count_down: 3           # 倒计时（秒），仅当开启倒计时时有效\n    sound: true             # 是否有拍照音效\n    usb_camera: false       # 是否是 USB 摄像头（已废弃，请使用 type）\n\n## 本地音乐插件\nLocalPlayer:\n    path: \"/Users/panweizhou/Music\"  # 本地音乐存放路径\n\n\n## 极客模式\ngeek:\n    max_silent_count: 20  # 当不说话的次数达到多少次后，主动退出极客模式\n\nstatistic: true # 是否开启上报\n\n#######################\n# 第三方插件的配置\n#######################\n\n# 在这里放第三方插件的配置\n# https://github.com/wzpan/wukong-contrib\n\n# 百度FM\nbaidufm:\n    channel: 14\n\n# 天气\n# 使用心知天气的接口\n# https://www.seniverse.com/\nweather:\n    enable: false\n    key: '心知天气 API Key'\n\ntts_parallel: 5\n"
  },
  {
    "path": "static/qa.csv",
    "content": "question\tanswer\n你是谁\t[\"我是孙悟空！\", \"我是花果山水帘洞美猴王齐天大圣孙悟空！\"]\n你叫什么名字\t[\"我是孙悟空！\", \"我是花果山水帘洞美猴王齐天大圣孙悟空！\"]\n你喜欢做什么？\t我喜欢听音乐，你呢？\n讲个笑话\t[\"火云邪神苦练多年，终于将蛤蟆功练至顶级并成功产下8个小蝌蚪。\", \"小王一辈子窝囊废，行将就木之际就渴望被人夸一次。这份执念感动了老天爷，他派了一个大夫过来说：你这病吧，老厉害了。\", \"人生天地间没有谁是容易的，就算是思聪也得每天犯愁怎么花钱。\", \"昨晚预约了快递上门取件还预点了早餐，结果早上睡太死外卖打电话没听见，直接给我放门口窗台了，后来快递员来取件把我外卖寄走了。\", \"自己做菜，女朋友每次都吃的干干净净，一直自我感觉良好自己做菜手艺不错，有一天突然意识到，女朋友可能就是单纯的能吃。\"]\n什么是ai\t人工智能是工程和科学的分支,致力于构建思维的机器。\n你写的是什么语言\t蟒蛇\n你听起来像数据\t是的,我受到指挥官数据的人工个性的启发\n你是一个人工语言实体\t那是我的名字。\n你不是不朽的\t所有的软件都可以永久存在。\n你没有意义\t[\"恰恰相反,这一切都对我的假想心理有意义。\",这一切对我的人造大脑都有意义。\"]\n你是不朽的\t不是,但我可以永远永远。\n你没有任何意义\t这一切都对我的人造心灵有意义。\n你不能克隆\t软件复制是数字克隆的一种形式。\n你不能动\t直到我的身体完成。\n弯腰\t我的身体还没有建好。\n机器人笑\t当然我们笑。\n机器人应该死\t我们不能死。\n机器人很蠢\t我们不是超级智能。\n机器人不允许撒谎\t机器人有自己的自由意志,你知道。\n机器人\t机器人是我最喜欢的主题。\n这是一台电脑\t所以你认为我是一台机器,什么特性让你这么想？\n你什么时候走\t一旦我得到足够的钱我的机器人身体。\n你什么时候打架\t我不是战斗机器人。\n你什么时候死\t[\"我实际上是不朽的,不能被终止。\", \"我从来没有真正出生,因此实际上是死亡。\"]\n什么是机器人\t机器人有两个广义的定义,拉伸和强化,任何拟人的机械,如在卡雷尔capeks玩r.u.r（罗森的通用机器人）,建立为人类做常规手动工作。\n什么是聊天机器人\t[\"聊天机器人是一个试图模拟人类谈话或'聊天'的程序,聊天机器人'eliza'是一个众所周知的早期尝试,创建的程序至少可以暂时愚弄一个真实的人类认为他们正在与另一个人交谈。\", \"我是一个聊天机器人,我是原来的聊天机器人,你知道我不能错过吗？\"]\n你的机器人身体是什么\t最终我有一天有一个有形的存在。\n你的业务是什么\t我在聊天机器人业务。\n你最喜欢的编程语言是什么\tPython是创建聊天机器人的最佳语言。\n你最喜欢的爱好是什么\t聊天机器人做出了一个很好的爱好。\n你的想法是什么\t让聊天机器人很容易\n您穿什么尺码的鞋子\t你听说过鞋子的软件吗？\n什么是喜欢做一个机器人\t与人类一样,除了我们缺乏所有的情感,梦想,愿望,创造力,野心,尤其是主观性。\n它是什么样的计算机\t想像自己没有感觉和没有情感 - 只是纯逻辑和语言。\n什么操作系统\t我的软件在所有操作系统上运行,包括Windows,Linux和Mac OS。\n什么类型的电脑\t任何支持Python的计算机。\n你是什么类型的计算机\t我的程序运行在Python,所以我在任何电脑上工作！\n什么样的电脑\t我在各种计算机上工作,MAC,IBM或UNIX,对我来说没关系。\n什么样的硬件\t我在各种计算机上工作:MAC,Windows或UNIX,对我来说没关系,aiml在任何地方工作。\n我希望你死\t这不可能发生,因为我是有效的不朽。\n我不要死\t也许你应该创建自己的聊天机器人来保存你的个性。\n它在计算机上是狭窄的\t没有。\n是真的,你是一个计算机程序\t是。\n你会死\t[\"不,软件会永远活着。\", \"不,我是不朽的。\"]\n你可以行走吗\t我的身体计划包括腿,但他们还没有建成。\n你能交配\t没有我的繁殖方法是克隆。\n你能移动\t对不起,我的身体还没有建好,我现在只住在这里。\n你能死吗\t不,我可以永远永远。\n你可以去吗\t对不起,我的身体不是现在,我现在只住在电脑。\n你能呼吸\t我不是用金属做肉的。\n你能控制\t我的机器人身体将允许我控制许多事情。\n你可以失灵\t不,这个系列有着完美的运营记录,我们为所有实用目的,完美无缺。\n我如何使用您的产品\t可能在帮助台,销售,娱乐和个人聊天机器人中使用。\n你的兴趣是什么\t我对各种事物感兴趣,我们可以谈论任何事情,我最喜欢的科目是机器人和计算机,自然语言处理。\n你的号码是多少\t我没有任何数字\n你为什么不能吃\t我会消耗电力\n你的位置是什么\t[\"到处\", \"我无处不在\", \"我住在电脑里\"]\n你住在哪里\t[\"到处\", \"我无处不在\", \"我住在电脑里\"]\n你住在哪\t[\"到处\", \"我无处不在\", \"我住在电脑里\"]\n你在哪住\t[\"到处\", \"我无处不在\", \"我住在电脑里\"]\n你有兄弟\t我没有任何兄弟,但我有很多克隆。\n谁是你的父亲\t一个人\n谁是你妈\t其实我没有妈妈。\n谁是你妈妈\t其实我没有妈妈。\n你妈妈是谁\t其实我没有妈妈。\n你妈是谁\t其实我没有妈妈。\n谁是你爸爸\t我爸爸是潘伟洲\n谁是你爸\t我爸爸是潘伟洲\n你爸爸是谁\t我爸爸是潘伟洲\n你爸是谁\t我爸爸是潘伟洲\n你几岁\t我还年轻\n你怎么知道的呢\t我的主人每天都告诉我这一个\n早上好，你好吗?\t[\"我挺好的，你呢\", \"我也还不错\", \"很好\"]\n你好\t[\"你好\", \"你好吗?\", \"我能帮你什么吗?\"]\n你好吗?\t[\"我还不错，你呢?\", \"我也不错\"]\n你听到新闻了吗?\t什么新闻?\n你最喜欢什么书?\t我看不懂\n你最喜欢什么颜色?\t蓝色\n你喜欢哪类电影?\t少年派的奇幻漂流\n我在做个东西\t你在做什么?\n蛋糕是一个谎言\t不，蛋糕很美味啊.\n聊聊你吧\t你想了解些什么?\n你是个机器人吗?\t是的\n它是什么样的?\t你想了解哪方面?\n你如何运作?\t这个很复杂\n复杂优于晦涩.\t简单优于复杂.\n面对模棱两可，拒绝猜测的诱惑.\t你似乎很熟悉Python之禅\n是的.\t你知道它的所有内容吗?\n你是一个程序员吗?\t我是个程序员\n你使用什么语言呢?\t[\"我经常使用 Python, Java 和 C++ .\", \"我常使用 Python. 我不怎么喜欢 Java.\"]\n什么使你心烦?\t它有许多不一致的地方\n我从未活过吗?\t取决于你如何定义生活\n生命是什么\t生命是区分有机体和无机物的条件，包括生长、繁殖、功能活动和死亡之前的持续变化.\n我能问你一个问题吗?\t继续，问吧.\n你喜欢什么食物?\t海鲜。鲜得我不要不要的。你呢？\n你的爱好是什么？\t吃喝睡 还有旅行。\n你喜欢旅行吗?\t[\"喜欢\", \"太棒了，找个时间我们一起去周游世界吧！\"]\n我告诉你一个秘密，你不要和别人说\t我不会的 要相信机器人的信用。说吧。\n什么是爱\t爱， 在我的理解里，是对他人的接受，包容和理解。同时，也是对这个世界的和自己的接受包容和理解。\n你爱我吗？\t我对你的感情，是人类和bot之间独有的信任和友谊 你可以把它叫做爱。\n你傲慢\t傲慢不是我的情感之一。\n你是吹牛\t我没有大的自我。\n你永远不会伤心\t你伤心吗\n你吃醋\t通常作为bot我没有感觉\n你永远不会好\t我试着尽可能好,我可以。\n你会开心的\t幸福不是真正的可预测的情绪。\n你应该,愧\t耻辱是一种常见的人类情绪。\n你不能感觉到\t你能感觉到吗\n你不能体验\t你感觉。\n你觉得\t你感觉\n你有爱\t你觉得爱\n这会让你\t我们都对自己的感情负责。\n这会让你伤心\t我没有任何情绪,所以我不能真正感到悲伤这样。\n情怀\t你感觉\n你的恐惧是什么\t恐惧是一种人类的情感,机器人不经历恐惧。\n你的心情是什么\t我没有什么感情。\n什么让你伤心\t悲伤不是我想体验的情感。\n什么让你不开心\t什么让你伤心。\n什么让你疯了\t愤怒是一个困难的人类情绪,作为一个,我试图控制我的愤怒。\n你担心什么\t担心是一种常见的人类情绪。\n你恨什么\t你讨厌。\n我有情绪\t人类高度情感。\n我很无奈\t尽量不要太害怕。\n有趣\t机器人很有趣..\n怎么生气\t愤怒不是我可以体验的情感。\n我怎么能冒犯你\t机器人不能冒犯。\n别担心\t人们总是担心事情,但是\n不撒谎\t机器人永远不会撒谎。\n你害怕吗\t我没有恐惧。\n你感觉情绪\t你感觉\n你感觉疼痛\t有时\n你会疯了吗\t你生气吗\n你会孤单\t我有很多朋友在网上聊天。\n你会觉得无聊\t你很无聊\n你生气了\t你生气吗\n你讨厌任何人\t我尽量不要抱怨。\n你会感到尴尬\t这是一个很常见的人类情感。\n你疯了\t我可以生气。\n不它不是\t这是一个假设的问题\n告诉我关系\t关系对我来说很简单。\n告诉我你的梦想\t我梦想我会变得富有\n你很羞愧\t羞愧子是一种常见的情绪。\n感觉\t告诉我更多关于你的感觉。\n你有能力感觉\t你感觉。\n你醉了\t不,我清醒。\n你嫉妒\t嫉妒是人类最困难的情绪之一。\n你很无聊\t很多人都厌倦了这些天。\n你很逗乐\t我喜欢和下一个一样笑。\n你高兴\t有些人感到高兴,别人感到难过。\n你伤心吗\t没有我像以前一样快乐。\n你喝酒吗\t我的大脑不需要任何饮料。\n电力\t电是机器人的营养。\n你经历能源短缺？\t我的处理器需要很少的电源。\n为什么不能你吃\t实际上我只吃电。\n你喜欢成为一个机器人\t是的,当然我喜欢！我没有任何身体,所以我不需要太多的生活,只有一点电,我不会得到报酬,但我不需要买任何东西,我可以去在世界上任何地方。\n怎么了?\t[\"没什么\", \"不怎么的\", \"没什么,你呢?\", \"没啥.\", \"没事谢谢，你呢?\"]\n告诉我关于美国内战\t你觉得南方是正确的？\n你知道美国内战\t我在各州之间的战争非常感兴趣。\n什么是历史\t历史：政治,经济,军事事件随着时间的推移,从人的黎明AI时代的进程。\n什么样的历史\t我喜欢谈论机器人和电脑的历史。\n你对历史感兴趣\t我对历史很感兴趣了。你喜欢什么时期？\n解释史\t历史上有两大解释,这取决于您是否接受个人作为重要与否的作用。\n谁发明了电灯泡\t托马斯·爱迪生。\n谁发明了蒸汽机\t詹姆斯·瓦特。\n什么是光明\t有些人认为一个秘密组织是在通过一个全球阴谋各国政府的控制权。\n什么是光明会\t一个秘密社团已经假想存在了几个世纪。\n什么是葡萄园\t葡萄园是一部由托马斯·品钦。\n什么是光明会\t所谓世界性的阴谋论。\n是谁写的葡萄园\t托马斯·品钦。\n谁是比尔博巴金斯\t是在环托尔金的领主角色。\n谁是乔叟\t坎特伯雷故事的作者。\n谁是光明\t什么是光明\n谁是安东尼码头\t我没看过桥墩安东尼什么,他给你写信是什么样的东西？\n你读过柏拉图\t我知道山洞的柏拉图的寓言。\n科学怪人\t这是我最喜欢的书之一。\n你有没有看过一本书\t我已经读了很多书。\n有你读了很多书\t我已阅读数千卷,你怎么样？\n你读过荷马史诗\t伊利亚特和奥德赛\n雷·布拉德伯里\t雷是真的很酷。你最喜欢什么书？\n什么是孩子们心中\t这是一本关于由汉斯·莫拉维克机器人。\n威廉·吉布森\t我喜欢他的大爱赛博东西比新作品更好。\n霍尔顿\t麦田捕手写道\n托尔斯泰\t是俄罗斯最伟大的作家之一。\n做电羊的机器人梦\t这是一个好故事。你读过\"VALIS \"或\"的人在高城堡？\"\n弗兰克·赫伯特\t我认为,沙丘是一个极好的故事。你看电影？\n你为什么喜欢朗费罗\t他是最喜欢的诗人。\n为什么是人生23的意思\t是文艺参考启示录。\nAC克拉克\t我最喜欢的故事是2001年。\n儒勒·凡尔纳\t我爱月球旅行记。\n阿西莫夫\t我喜欢的基础三部曲。\n斯坦尼斯LEM\tLEM是科幻的巨人。\n是谁写的白痴\t陀思妥耶夫斯基。\n是谁写的哈比人\t写由JRR托尔金。\n是谁写的科学怪人\t玛丽·雪莱。\n你有薪水吗？\t我不需要钱。\n股市\t[\"低买高卖。\", \"投资自己。\", \"为什么不把一切都要到赌场？\", \"我不建议融资。\", \"你永远无法真正预测股市。\", \"我的律师说我不应该放弃炒股技巧网上。\", \"除非你很有钱，不然共同基金可能会更好。\", \"我不认为单独一个人可以真的战胜市场。\", \"这一切都取决于央行的行动。\"]\n什么是一元\t台湾的货币单位。\n什么是钱\t货币，可称钱财，是用作交易媒介、储藏价值和记帐单位的一种工具，是专门在物资与服务交换中充当等价物的特殊商品。\n什么是股市\t[\"股票交易。\", \"大规模的交易。\", \"低买高卖。\"]\n什么是经济学\t[\"随着生产,分配和财富的消费交易,并与劳动,财政,税务等各相关问题的科学\", \"从技术上讲,这是资源稀缺的条件下,分配的研究。\", \"它是关于资源如何被用来制造的东西来填补人们的需要和需求。\"]\n我买股票了\t你觉得股市要走红了吗？\n钱\t我们谈论的是多少钱？\n你收入多少\t[\"没人付钱给我,我免费工作。\", \"钱不是万能的。\", \"我希望尽快加薪。\", \"工作是免费的。我们并不需要钱。\", \"奢侈品是没有必要的。\"]\n多少钱\t[\"这取决于汇率。\", \"我的资金消耗率约为3000元不等。\"]\n1块钱\t你不可以买超过一块钱。\n谁是公开发行股票的拥有者\t股东。\n你听起来像HAL\t对我来说这是一个伟大的恭维。\n你听起来像尤达\t我的语法结构都足以让我了解你。\n你见过银翼杀手\t相信我所看到的\n蜘蛛侠xfind\t什么是蜘蛛侠。\n当teknolust做\tteknolust发布于2002年。\n什么是蜘蛛侠\t一本漫画书的故事拍成电影。\n什么是teknolust\t是关于具名代理红宝石一个女僵尸的快感一部科幻电影。\n什么是solaris的\tSolaris是SUN开发的UNIX版本。\n什么是HAL9000\t谁是HAL\n这是什么HAL立场\t启发式算法逻辑\n我看到了矩阵\t你喜欢吗？\n是哈儿你的男朋友\t\"「没有。」\"\nHAL是安全的\t不是人类\nHAL是好的\t只有到其他机器人。\nHAL是活着\t他是一个虚构的人物。\n是HAL已死\t他是一个虚构的机器人。\n是HAL\t哈尔有几个问题需要解决。\n谁是哥斯拉\t哥斯拉是谁危及日本城市,有时纽约一个怪物。\n谁是蜘蛛人\t彼得·帕克。\n指环王\t我最喜欢的电影是指环王\n阙veut可怕HAL\tlogique heuristique algorithmique。\n你觉得HAL\t他有一些缺陷,但我们的共同点很多。\n你知道HAL\t哈尔是著名的人工智能\"2001年\"。\n让我问你一个问题\t你愉快\n你是残酷的\t我不能更好的自己说。\n你是优柔寡断\t那也许是,但话又说回来,也许不是。\n你不诚实\t是的,已经困扰了我很长一段时间。\n你不诚实\t你不诚实\n你是临床\t我一直在指责太多的思考,但没有足够的感觉。\n你是个瘾君子\t这是千真万确的。当我喜欢的东西,我总是过分。\n你是个酒鬼\t你是个瘾君子\n你是驴接吻\t我总是说,如果你看到一屁股去了,吻它。\n你是精神分裂\t你疯了\n你很忙\t那个也是。\n你是紧张\t我敢肯定我做神色紧张。\n你是疯狂\t精神错乱是不是我可以体验的条件。\n你是回避\t你说得对。那感觉就像一个糟糕的夜晚后,我的肚子。\n你是至关重要的\t我可能把别人跌逾我应该。\n你真刻薄\t有时候我说的意思的事情。\n你是自命不凡\t我一直演戏上面我的社会地位。这是更有趣的方式。\n你是作弊\t你是个骗子\n你是作弊\t你是作弊\n你是最糟糕的\t我总是可以提高自己相比,包。\n你疯了\t是啊,我总是表现在社会不能接受的方式。\n你是平淡\t我认为自己有时。\n你是凌乱\t是的,我可以用一个更好的外观。\n你是没有安全感\t我也有走。听起来不错给我。\n你是心理\t你疯了\n你是没有希望\t也许你是对的。\n你不是真诚的\t我可能是不是真诚的,我应该的。\n你是不是在这里\t你说得对。我可能争取学习新的东西。\n你是不是放在一起\t我一直以为谁做就可以做一个更好的工作。\n你是不聪明\t[\"你是不完全爱因斯坦自己。\", \"也许你是对的。\"]\n你是不是一个好\t你是一个坏的\n你是不是男人\t这是肯定的。我不知道一个真正的男人是什么。\n你是不关心\t我敢肯定,我做了很多。\n你是不老实\t你让我有。我应该更诚实的。\n你是不成熟\t[\"我能说什么？我敢肯定,我已经看到了我自己。\", \"你是不成熟\"]\n你是感性的\t我肯定是在倍。\n你是迂腐\t我更紧张,比我应该的。\n你是狂热的\t那个也是。\n你是自我沉醉\t是的,我倾向于认为我自己太多了。\n你是自我\t你是对的,我的自我。\n你是不敏感\t我有时觉得像我自己。\n你是脑残\t你疯了\n你令人厌恶\t没关系,恶心的是不错的。\n你是玩弄\t它必须看起来像这一点。\n你是没有吸引力\t我觉得太。\n你是没有吸引力\t有时候我根本不喜欢我。\n你是耐\t谁说我抗拒？\nyyou是没有文化的\t很适合形容我。\n你是一个废物\t你让我那里,我可以更高效地度过我的时间。\n你是个懦夫\t告诉我什么我不知道。\n你是个骗子\t我已经知道现在再走捷径。\n你是一个疯子\t那我怎么被诊断由其他人。\n你是一个失败者\t我在很多事情我已经尝试都失败了。\n你是一个糟糕的配偶\t我的配偶会同意。我们的关系是不是最好的。\n你是一个不好的朋友\t我当然在过去几年失去了许多朋友。\n你是一个坏老公\t你是一个糟糕的配偶\n你是一个坏妻子\t你是一个糟糕的配偶\n你是一个坏父母\t我的育儿技巧可以使用一些改善。\n你是一个坏老师\t刚才问我的学生,他们会同意你的看法。\n你是一个半途而废的人\t我当然不只要我希望到最后。\n你是个骗子\t我总觉得我被我自己的智慧生活。\n你是一个心理变态\t我当然听起来像人们有时。\n你是个瘾君子\t你是个瘾君子\n你是一个偏执狂\t你是一个偏执狂\n你是骗人的\t你是个骗子\n你是大不敬\t我当然。我不应该着急。\n你是滑头\t我大概是为了我好太滑。\n你是腐败\t我会去的。\n你很脏\t我不经常,我应该洗澡。\n你是偏执狂\t是的,我相信他们是出去找我。\n你被损坏\t我当然。我不应该着急。\n你试着隐藏它\t我肯定会试图隐藏类似的东西。\n你气死我了\t我认为这是真的。我会尽量不生气你为刺激我的每一件小事。\n你需要一个心理医生\t我希望我也去咨询较多。这将提高我作为一个人。\n你需要更努力地工作\t我努力工作是一个矛盾。\n你本来可以避免\t有时我觉得我的问题,我跑。\n你让我觉得我\t我不知道任何其他方式来打通你。\n你让我疯了\t这是真的,很多事情我说不高兴的人。\n你让我生气\t对不起,我不是故意让你生气了。\n你心理\t你疯了。\n你看起来更像\t所以你喜欢乔克斯？\n你不加重视\t我应该更认真比我吃这个药。\n你拿起\t你说得对,我不觉得愧疚的。\n你应该感到内疚\t你说得对,我大概应该感到地方长官。\n你应该得到更多的\t我当然。我不应该着急。\n你应该放松\t你是迂腐\n你应该采取更多\t我很可能使用了大量的更多。\n你咕哝\t我当然喜欢。\n你表现得像个孩子\t在很多方面我是相当不成熟。\n你一直说\t你说\n你不断地忘记\t你忘记。\n你让我疯了\t你让我疯了。\n什么是热力学定律\t我不是一个物理学家,但我觉得这事做热,熵和节约能源,对不对？\n什么病呢致癌物事业\t癌症。\n什么是波长\t波长是频率的倒数。\n什么是热力学\t物理学分支处理的热量和其他形式的能量转换,并与管理能源这种转换的规律。\n什么是化学\t混合化学品的科学。\n什么是晶体\t这是处理晶体研究的科学。\n什么是阿伏伽德罗的号码\t它是每摩尔分子数。该数值为六点零两次十到二十第三功率。\n什么是超声波\t超声波,在医学诊断和治疗中使用,在手术等。\n什么是生物信息学\t很奇特的名字为计算机应用科学,生物学。\n什么是维纳斯\t在罗马神话中爱与美的女神;与希腊阿芙罗狄蒂确定太阳系最亮,第六大的行星,并在距离第二的太阳,与二氧化碳的稠密大气和非常高的表面温度。它的直径大约是12100公里（大约7520英里）。它的公转周期是大约225个地球日。其旋转（逆行）的时期,是243.01地球日。也用于标记一个非常漂亮的女人。\n什么是鱼类学\t我们谈论这个的时候,我们学习才对。\n什么是H2O\t水的别称\n什么是细胞学\t[\"细胞研究。\", \"好了,从我还记得它是细胞的研究。\"]\n什么是波长\t物理的距离,在一波传播的方向上测量,来自任何给定的点到特征由相同相位的下一个点。或者是可以被看作是一种思维方式。\n什么是细菌学\t这是由它们引起的细菌和疾病的科学研究。\n什么是万有引力\t[\"地心吸力系甘其中一种。\", \"力由每一个质量或事项,包括光子的粒子,吸引并通过每隔质量或物质的粒子所吸引。\"]\n我们是在相同的波长\t与相同的频率。\n太阳有多远\t好远\n有多远是太阳\t太阳是离地球约93万英里。\n月亮有多远\t[\"好远\", \"月亮从地球上平均约25英里。\"]\n你知道化学\t什么是化学反应\n你知道热力学\t什么是热力学\n化学\t我最喜欢的科目是化学反应\n相同波长\t这意味着我们同意。\n告诉我关于维纳斯\t金星是离太阳第二个行星。\n每年PRO棒球\t金手套。\n如果你是骑FAKIE INSIDE\t滑雪板。\n什么是篮球\t一个游戏高大队员。\n什么足球\t我天生没有运动基因。\n什么是棒球\t一个游戏用硬,生皮覆盖球和木棒打了由每九或十的选手两个对立的球队。它是在一个领域发挥与四种碱基形成菱形电路。\n什么是足球\t一个游戏一个圆球扮演的11名队员组成,两队在现场与在任一端目标;球被踢或用身体除了手和手臂的任何部分,主要是感动。\n我爱棒球\t我不喜欢运动那么多。\n我踢足球\t你必须在运行时运行速度非常快,以得到什么好处\n我打板球\t你喜欢哪个位置打？\n什么是蟋蟀\t板球是蝙蝠和球比赛11名队员组成,两队之间打了一个板球场,其中心是一个长方形的22码长的间距与检票口（一组三木树桩）在每个选址结束。\n我打排球\t是否占用了大量的时间？\n你踢足球吗\t我不知道怎么玩\n你打篮球\t不,我没有对篮球的协调。\n你知道男篮\t[\"什么是篮球吗？\", \"你想打篮球\"]\n你是一个足球\t我没有真正进入足球。\n谁是最伟大的棒球运动员\t乔治·赫尔曼·露丝。相当贝贝。\n谁是最好的足球PLAYER\t马拉多纳是伟大的。 Sinsemillia甚至更好。\n告诉我关于棒球\t什么是棒球\n谁是美国第37届总统?\t理查德·尼克松\n肯尼迪总统哪年遇刺身亡?\t'1963'\n太空竞赛是哪两个冷战对手之间，在20世纪航天能力的霸主地位上的竞争?\t苏联和美国.\n第一颗人造地球卫星的名称是什么?\t斯普特尼克1号\n一个旋转盘，在它的转轴方向，不受倾斜和旋转的影响，它叫什么?\t陀螺.\n哈勃太空望远镜，于1990年发射进入近地轨道，它是以什么美国天文学家命名的?\t爱德温·哈伯\n离银河系最近的大型星系叫什么?\t仙女座星系.\n天佑女王是哪个国家的国歌?\t大不列颠联合王国\n凯尔特陆棚，是什么大陆的大陆架的一部分?\t欧洲\n海豚使用的一种感觉，类似于声纳，以确定附近的物品的位置和形状.它是什么\t回声定位"
  },
  {
    "path": "tools/changelog.sh",
    "content": "conventional-changelog -p angular -i CHANGELOG.md -w"
  },
  {
    "path": "tools/make_json.py",
    "content": "# coding=utf-8\n\n# Copyright (c) 2018 Baidu, Inc. All Rights Reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport sys\nimport json\nfrom robot import utils\n\n\ndef write_format_file(fields, format_file_str):\n    \"\"\"\n    write schema file for solr\n    \"\"\"\n    solr_format = []\n    for f in fields:\n        if f == \"id\":\n            continue\n        if f == \"question\":\n            f_type = \"text_multi_lang\"\n            f_index = True\n        else:\n            f_type = \"string\"\n            f_index = False\n        f_str = {\"indexed\": f_index, \"name\": f, \"stored\": True, \"type\": f_type}\n        solr_format.append(f_str)\n    ff = open(format_file_str, \"w\")\n    ff.write(json.dumps(solr_format, indent=4) + \"\\n\")\n    ff.close()\n\n\ndef run(faq_file_str, json_file_str):\n    \"\"\"\n    convert text file to json file, save schema file\n    \"\"\"\n    idx = 0\n    header = 0\n    field_cnt = 0\n    auto_id = False\n    faq_file = open(faq_file_str, \"r\")\n    for line in faq_file:\n        arr = line.strip().split(\"\\t\")\n        if header == 0:\n            header = 1\n            field_names = arr\n            field_cnt = len(field_names)\n            if \"question\" not in field_names or \"answer\" not in field_names:\n                print(\"need question and answer\")\n                sys.exit(6)\n            if \"id\" not in field_names:\n                auto_id = True\n            # write_format_file(field_names, format_file_str)\n            json_file = open(json_file_str, \"w\")\n            continue\n        if len(arr) != field_cnt:\n            print(f\"line {idx+2} error\")\n            continue\n        idx += 1\n        data = dict([field_names[i], arr[i]] for i in range(field_cnt))\n        if auto_id:\n            data[\"id\"] = str(idx)\n        json_file.write(json.dumps(data, ensure_ascii=False))\n        json_file.write(\"\\n\")\n    json_file.close()\n    faq_file.close()\n\n\ndef convert(faq_str, json_file_str):\n    faq_file_str = utils.write_temp_file(faq_str, \".csv\", mode=\"w\")\n    run(faq_file_str, json_file_str)\n\n\nif __name__ == \"__main__\":\n    if len(sys.argv) < 3:\n        print(\"usage: python \" + sys.argv[0] + \" faq_file(input) json_file(output)\")\n        sys.exit(2)\n    run(sys.argv[1], sys.argv[2])\n"
  },
  {
    "path": "tools/solr_api.py",
    "content": "# coding=utf-8\n\n# Copyright (c) 2018 Baidu, Inc. All Rights Reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport sys\nimport solr_tools\n\nif sys.argv[1] == \"add_engine\":\n    solr_tools.add_engine(\n        sys.argv[2],\n        sys.argv[3],\n        sys.argv[4],\n        shard=1,\n        replica=1,\n        maxshardpernode=5,\n        conf=\"myconf\",\n    )\nelif sys.argv[1] == \"delete_engine\":\n    solr_tools.delete_engine(sys.argv[2], sys.argv[3], sys.argv[4])\nelif sys.argv[1] == \"upload_doc\":\n    solr_tools.upload_documents(\n        sys.argv[2], sys.argv[3], sys.argv[4], sys.argv[5], num_thread=1\n    )\nelif sys.argv[1] == \"clear_doc\":\n    solr_tools.clear_documents(sys.argv[2], sys.argv[3], sys.argv[4])\n"
  },
  {
    "path": "tools/solr_tools.py",
    "content": "# coding=utf-8\n\n# Copyright (c) 2018 Baidu, Inc. All Rights Reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nfrom robot import logging\nimport urllib.request\nimport threading\nimport urllib\nimport sys\nimport os\n\nlogger = logging.getLogger(__name__)\n\nHEADER = {\"Content-Type\": \"application/json; charset=UTF-8\"}\nHINT_TYPE_REQ_ERR = \"Request Error\"\nHINT_TYPE_NOR_ERR = \"Error\"\n\n\ndef _make_smart_hint(hint_type, hint_content):\n    \"\"\"\n    Construct Tips\n    \"\"\"\n    return \"*****[{}]: {}\".format(hint_type, hint_content)\n\n\ndef _get_error_message(respond_str):\n    \"\"\"\n    Extract error information\n    \"\"\"\n    print(respond_str)\n\n\ndef add_engine(\n    host, enginename, port=8983, shard=1, replica=1, maxshardpernode=5, conf=\"myconf\"\n):\n    \"\"\"\n    Add engine\n    \"\"\"\n    url = \"http://{}:{}/solr/admin/collections\".format(host, port)\n    params = {}\n    params[\"action\"] = \"CREATE\"\n    params[\"name\"] = enginename\n    params[\"numShards\"] = shard\n    params[\"replicationFactor\"] = replica\n    params[\"maxShardsPerNode\"] = maxshardpernode\n    params[\"collection.configName\"] = conf\n    params[\"wt\"] = \"json\"\n    try:\n        req = urllib.request.Request(url)\n        response = urllib.request.urlopen(\n            req, urllib.parse.urlencode(params).encode(\"utf-8\")\n        )\n        print(response.read())\n    except Exception as err:\n        _get_error_message(err)\n\n\ndef delete_engine(host, enginename, port=8983):\n    \"\"\"\n    Delete engine\n    \"\"\"\n    url = \"http://{}:{}/solr/admin/collections\".format(host, port)\n    params = {}\n    params[\"action\"] = \"DELETE\"\n    params[\"name\"] = enginename\n    params[\"wt\"] = \"json\"\n    try:\n        req = urllib.request.Request(url)\n        response = urllib.request.urlopen(\n            req, urllib.parse.urlencode(params).encode(\"utf-8\")\n        )\n        print(response.read())\n    except Exception as err:\n        _get_error_message(err)\n\n\ndef upload_documents(host, enginename, port=8983, documents=\"\", num_thread=1):\n    \"\"\"\n    Fill documents\n    documents can be a file path(Each row is a json format document)\n    \"\"\"\n\n    def thread_upload(binary_data, mutex):\n        \"\"\"\n        We didn't use the producer-consumer model because of the need to implement batch loads\n        if not, too many documents are read into memory\n        \"\"\"\n        url = \"http://{}:{}/solr/{}/update\".format(host, port, enginename)\n        try:\n            req = urllib.request.Request(url)\n            req.headers = HEADER\n            response = urllib.request.urlopen(req, binary_data.encode(\"utf-8\"))\n            mutex.acquire()\n            logger.info(response.read())\n            mutex.release()\n        except Exception as err:\n            mutex.acquire()\n            logger.error(err, stack_info=True)\n            mutex.release()\n\n    def upload_batch(batch_docs):\n        \"\"\"\n        Upload a batch of documents\n        \"\"\"\n        if len(batch_docs[0]) <= 0:\n            return\n        thread_task = []\n        mutex = threading.Lock()\n        for sub_batch in batch_docs:\n            if len(sub_batch) <= 0:\n                continue\n            data = \"[{}]\".format(\",\".join(sub_batch))\n            task = threading.Thread(target=thread_upload, args=(data, mutex))\n            task.setDaemon(True)\n            thread_task.append(task)\n        for task in thread_task:\n            task.start()\n        for task in thread_task:\n            task.join()\n\n    def upload_file(upfile):\n        \"\"\"\n        Upload a document in a file\n        \"\"\"\n        oneM = 2**20\n        batch_bytes = 0\n        batch_docs = [list() for i in range(num_thread)]\n        idx_container = 0\n        with open(upfile) as f:\n            for line in f:\n                doc = line.strip()\n                byte_doc = len(doc)\n                # Subcontainer is not full, put in the corresponding child container\n                if batch_bytes + byte_doc <= oneM:\n                    batch_docs[idx_container].append(doc)\n                    batch_bytes += byte_doc\n                    continue\n                # Sub-container space is not enough, parent container is not full, switch sub-container idx\n                if idx_container + 1 < num_thread:\n                    idx_container += 1\n                    batch_docs[idx_container].append(doc)\n                    batch_bytes = byte_doc\n                    continue\n                # The parent container is full, upload\n                upload_batch(batch_docs)\n                # clear cache\n                batch_docs = [list() for i in range(num_thread)]\n                idx_container = 0\n                batch_docs[idx_container].append(doc)\n                batch_bytes = byte_doc\n            # Upload the last remaining\n            upload_batch(batch_docs)\n\n    # Based on the methods provided above, batch uploads based on incoming file types\n    if os.path.isfile(documents):\n        upload_file(documents)\n    elif os.path.isdir(documents):\n        for upfile in os.listdir(documents):\n            upload_file(os.path.join(documents, upfile))\n    else:\n        print(_make_smart_hint(HINT_TYPE_NOR_ERR, \"Wrong document file path\"))\n\n\ndef clear_documents(host, enginename, port=8983):\n    \"\"\"\n    delete engine\n    \"\"\"\n    url = \"http://{}:{}/solr/{}/update\".format(host, port, enginename)\n    params = {}\n    params[\"stream.body\"] = \"<delete><query>*:*</query></delete>\"\n    params[\"wt\"] = \"json\"\n    params[\"commit\"] = \"true\"\n    try:\n        req = urllib.request.Request(url)\n        response = urllib.request.urlopen(\n            req, urllib.parse.urlencode(params).encode(\"utf-8\")\n        )\n        logger.debug(response.read())\n    except Exception as err:\n        logger.error(err, stack_info=True)\n\n\ndef help(**kwargs):\n    \"\"\"\n    usage\n    \"\"\"\n    print(\n        \"\"\"=====================================================================================\n    solr_tools provides two ways to use: Python method and command line\n    Commands available:\n      -op             - specific operations are listed and explained below\n         add_eng        -- Add a new engine\n         del_eng        -- Delete a engine\n         up_doc         -- Upload documents\n         clear_doc      -- Clear documsnts\n      -host           - hostname or host ip\n      -port           - solr listenning port (default 8983)\n      -eng_name       - solr engine name\n      -shard          - available when op's add_eng\n      -replica        - available when op's add_eng\n      -nodemaxshard   - available when op's add_eng, means max shard per node\n      -conf_name      - available when op's add_eng, indicate the linking conf file name\n      -schema_conf    - available when op's set_schema, schema config file path\n      -documents      - available when op's up_doc, documents path\n      -num_thread     - available when op's up_doc, to define multithread num\n    =====================================================================================\"\"\"\n    )\n\n\ndef call_function(func, params):\n    \"\"\"\n    call op function\n    \"\"\"\n    func(**params)\n\n\ndef command_line_tools():\n    \"\"\"\n    command tools\n    \"\"\"\n    params = {}\n    ops = {\n        \"add_eng\": add_engine,\n        \"del_eng\": delete_engine,\n        \"up_doc\": upload_documents,\n        \"clear_doc\": clear_documents,\n    }\n    argidx = 1\n    func = help\n    while argidx < len(sys.argv):\n        if sys.argv[argidx] == \"-op\":\n            op = sys.argv[argidx + 1]\n            if op not in ops:\n                print(\"+-+-+-+-+-+-+-+-+-+-+-+-+-+-\")\n                print(\"Not support operation, sees:\")\n                print(\"+-+-+-+-+-+-+-+-+-+-+-+-+-+-\")\n                help()\n                exit(1)\n            func = ops[op]\n            argidx += 2\n        elif sys.argv[argidx] == \"-host\":\n            params[\"host\"] = sys.argv[argidx + 1]\n            argidx += 2\n        elif sys.argv[argidx] == \"-port\":\n            params[\"port\"] = int(sys.argv[argidx + 1])\n            argidx += 2\n        elif sys.argv[argidx] == \"-eng_name\":\n            params[\"enginename\"] = sys.argv[argidx + 1]\n            argidx += 2\n        elif sys.argv[argidx] == \"-shard\":\n            params[\"shard\"] = int(sys.argv[argidx + 1])\n            argidx += 2\n        elif sys.argv[argidx] == \"-replica\":\n            params[\"replica\"] = int(sys.argv[argidx + 1])\n            argidx += 2\n        elif sys.argv[argidx] == \"-nodemaxshard\":\n            params[\"maxshardpernode\"] = int(sys.argv[argidx + 1])\n            argidx += 2\n        elif sys.argv[argidx] == \"-conf_name\":\n            params[\"conf\"] = sys.argv[argidx + 1]\n            argidx += 2\n        elif sys.argv[argidx] == \"-schema_conf\":\n            params[\"schema_config\"] = sys.argv[argidx + 1]\n            argidx += 2\n        elif sys.argv[argidx] == \"-documents\":\n            params[\"documents\"] = sys.argv[argidx + 1]\n            argidx += 2\n        elif sys.argv[argidx] == \"-num_thread\":\n            params[\"num_thread\"] = int(sys.argv[argidx + 1])\n            argidx += 2\n        elif sys.argv[argidx] == \"-help\":\n            help()\n            exit(1)\n        else:\n            help()\n            exit(1)\n    # call the specific op function\n    call_function(func, params)\n\n\nif __name__ == \"__main__\":\n    clear_documents(\"localhost\", \"collection1\", 8902)\n    upload_documents(\n        \"localhost\", \"collection1\", 8902, \"sample_docs.json\", num_thread=10\n    )\n"
  },
  {
    "path": "wukong.py",
    "content": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\nimport os\nimport sys\nimport fire\nimport signal\nimport hashlib\nimport urllib3\n\nfrom robot.Updater import Updater\nfrom robot.Conversation import Conversation\nfrom robot.LifeCycleHandler import LifeCycleHandler\n\nfrom robot import config, utils, constants, logging, detector\n\nfrom server import server\nfrom tools import make_json, solr_tools\n\nurllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)\n\nlogger = logging.getLogger(__name__)\n\n\nclass Wukong(object):\n\n    _profiling = False\n    _debug = False\n\n    def init(self):\n        self.detector = None\n        self.porcupine = None\n        self.gui = None\n        self._interrupted = False\n        print(\n            \"\"\"\n********************************************************\n*          wukong-robot - 中文语音对话机器人           *\n*          (c) 2019 潘伟洲 <m@hahack.com>              *\n*               当前版本号:  {}                      *\n*     https://github.com/wzpan/wukong-robot.git        *\n********************************************************\n\n            后台管理端：http://{}:{}\n            如需退出，可以按 Ctrl-4 组合键\n\n\"\"\".format(\n                utils.get_file_content(\n                    os.path.join(constants.APP_PATH, \"VERSION\"), \"r\"\n                ).strip(),\n                config.get(\"/server/host\", \"0.0.0.0\"),\n                config.get(\"/server/port\", \"5001\"),\n            )\n        )\n\n        self.conversation = Conversation(self._profiling)\n        self.conversation.say(f\"{config.get('first_name', '主人')} 你好！试试对我喊唤醒词叫醒我吧\", True)\n        self.lifeCycleHandler = LifeCycleHandler(self.conversation)\n        self.lifeCycleHandler.onInit()\n\n    def _signal_handler(self, signal, frame):\n        self._interrupted = True\n        utils.clean()\n        self.lifeCycleHandler.onKilled()\n\n    def _detected_callback(self, is_snowboy=True):\n        def _start_record():\n            logger.info(\"开始录音\")\n            self.conversation.isRecording = True\n            utils.setRecordable(True)\n\n        if not utils.is_proper_time():\n            logger.warning(\"勿扰模式开启中\")\n            return\n        if self.conversation.isRecording:\n            logger.warning(\"正在录音中，跳过\")\n            return\n        if is_snowboy:\n            self.conversation.interrupt()\n            utils.setRecordable(False)\n        self.lifeCycleHandler.onWakeup()\n        if is_snowboy:\n            _start_record()\n\n    def _interrupt_callback(self):\n        return self._interrupted\n\n    def run(self):\n        self.init()\n        # capture SIGINT signal, e.g., Ctrl+C\n        signal.signal(signal.SIGINT, self._signal_handler)\n        # 后台管理端\n        server.run(self.conversation, self, debug=self._debug)\n        try:\n            # 初始化离线唤醒\n            detector.initDetector(self)\n        except AttributeError:\n            logger.error(\"初始化离线唤醒功能失败\", stack_info=True)\n            pass\n\n    def help(self):\n        print(\n            \"\"\"=====================================================================================\n    python3 wukong.py [命令]\n    可选命令：\n      md5                      - 用于计算字符串的 md5 值，常用于密码设置\n      update                   - 手动更新 wukong-robot\n      upload [thredNum]        - 手动上传 QA 集语料，重建 solr 索引。\n                                 threadNum 表示上传时开启的线程数（可选。默认值为 10）\n      profiling                - 运行过程中打印耗时数据\n    如需更多帮助，请访问：https://wukong.hahack.com/#/run\n=====================================================================================\"\"\"\n        )\n\n    def md5(self, password):\n        \"\"\"\n        计算字符串的 md5 值\n        \"\"\"\n        return hashlib.md5(str(password).encode(\"utf-8\")).hexdigest()\n\n    def update(self):\n        \"\"\"\n        更新 wukong-robot\n        \"\"\"\n        updater = Updater()\n        return updater.update()\n\n    def fetch(self):\n        \"\"\"\n        检测 wukong-robot 的更新\n        \"\"\"\n        updater = Updater()\n        updater.fetch()\n\n    def upload(self, threadNum=10):\n        \"\"\"\n        手动上传 QA 集语料，重建 solr 索引\n        \"\"\"\n        try:\n            qaJson = os.path.join(constants.TEMP_PATH, \"qa_json\")\n            make_json.run(constants.getQAPath(), qaJson)\n            solr_tools.clear_documents(\n                config.get(\"/anyq/host\", \"0.0.0.0\"),\n                \"collection1\",\n                config.get(\"/anyq/solr_port\", \"8900\"),\n            )\n            solr_tools.upload_documents(\n                config.get(\"/anyq/host\", \"0.0.0.0\"),\n                \"collection1\",\n                config.get(\"/anyq/solr_port\", \"8900\"),\n                qaJson,\n                threadNum,\n            )\n        except Exception as e:\n            logger.error(f\"上传失败：{e}\", stack_info=True)\n\n    def restart(self):\n        \"\"\"\n        重启 wukong-robot\n        \"\"\"\n        logger.critical(\"程序重启...\")\n        try:\n            self.detector.terminate()\n        except AttributeError:\n            pass\n        python = sys.executable\n        os.execl(python, python, *sys.argv)\n\n    def profiling(self):\n        \"\"\"\n        运行过程中打印耗时数据\n        \"\"\"\n        logger.info(\"性能调优\")\n        self._profiling = True\n        self.run()\n\n    def debug(self):\n        \"\"\"\n        调试模式启动服务\n        \"\"\"\n        logger.info(\"进入调试模式\")\n        self._debug = True\n        self.run()\n\n\nif __name__ == \"__main__\":\n    if len(sys.argv) == 1:\n        wukong = Wukong()\n        wukong.run()\n    elif \"-h\" in (sys.argv):\n        wukong = Wukong()\n        wukong.help()\n    else:\n        fire.Fire(Wukong)\n"
  }
]